From 3a4992633ee62d5edfbb484d9c6bcb3cf158489d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 31 Jul 2023 14:34:36 +0200 Subject: Migrate server to ESM Sorry for the very big commit that may lead to git log issues and merge conflicts, but it's a major step forward: * Server can be faster at startup because imports() are async and we can easily lazy import big modules * Angular doesn't seem to support ES import (with .js extension), so we had to correctly organize peertube into a monorepo: * Use yarn workspace feature * Use typescript reference projects for dependencies * Shared projects have been moved into "packages", each one is now a node module (with a dedicated package.json/tsconfig.json) * server/tools have been moved into apps/ and is now a dedicated app bundled and published on NPM so users don't have to build peertube cli tools manually * server/tests have been moved into packages/ so we don't compile them every time we want to run the server * Use isolatedModule option: * Had to move from const enum to const (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums) * Had to explictely specify "type" imports when used in decorators * Prefer tsx (that uses esbuild under the hood) instead of ts-node to load typescript files (tests with mocha or scripts): * To reduce test complexity as esbuild doesn't support decorator metadata, we only test server files that do not import server models * We still build tests files into js files for a faster CI * Remove unmaintained peertube CLI import script * Removed some barrels to speed up execution (less imports) --- server/tests/api/activitypub/cleaner.ts | 342 ------ server/tests/api/activitypub/client.ts | 136 --- server/tests/api/activitypub/fetch.ts | 82 -- server/tests/api/activitypub/helpers.ts | 167 --- server/tests/api/activitypub/index.ts | 6 - server/tests/api/activitypub/refresher.ts | 157 --- server/tests/api/activitypub/security.ts | 321 ------ server/tests/api/check-params/abuses.ts | 438 ------- server/tests/api/check-params/accounts.ts | 43 - server/tests/api/check-params/blocklist.ts | 556 --------- server/tests/api/check-params/bulk.ts | 80 -- .../api/check-params/channel-import-videos.ts | 209 ---- server/tests/api/check-params/config.ts | 428 ------- server/tests/api/check-params/contact-form.ts | 86 -- server/tests/api/check-params/custom-pages.ts | 79 -- server/tests/api/check-params/debug.ts | 61 - server/tests/api/check-params/follows.ts | 369 ------ server/tests/api/check-params/index.ts | 45 - server/tests/api/check-params/jobs.ts | 125 -- server/tests/api/check-params/live.ts | 589 ---------- server/tests/api/check-params/logs.ts | 157 --- server/tests/api/check-params/metrics.ts | 208 ---- server/tests/api/check-params/my-user.ts | 491 -------- server/tests/api/check-params/plugins.ts | 490 -------- server/tests/api/check-params/redundancy.ts | 240 ---- server/tests/api/check-params/registrations.ts | 446 -------- server/tests/api/check-params/runners.ts | 910 --------------- server/tests/api/check-params/search.ts | 272 ----- server/tests/api/check-params/services.ts | 195 ---- server/tests/api/check-params/transcoding.ts | 112 -- server/tests/api/check-params/two-factor.ts | 288 ----- server/tests/api/check-params/upload-quota.ts | 134 --- .../tests/api/check-params/user-notifications.ts | 290 ----- .../tests/api/check-params/user-subscriptions.ts | 298 ----- server/tests/api/check-params/users-admin.ts | 456 -------- server/tests/api/check-params/users-emails.ts | 116 -- server/tests/api/check-params/video-blacklist.ts | 292 ----- server/tests/api/check-params/video-captions.ts | 307 ----- .../tests/api/check-params/video-channel-syncs.ts | 318 ------ server/tests/api/check-params/video-channels.ts | 378 ------ server/tests/api/check-params/video-comments.ts | 484 -------- server/tests/api/check-params/video-files.ts | 195 ---- server/tests/api/check-params/video-imports.ts | 431 ------- server/tests/api/check-params/video-passwords.ts | 609 ---------- server/tests/api/check-params/video-playlists.ts | 695 ----------- server/tests/api/check-params/video-source.ts | 154 --- server/tests/api/check-params/video-storyboards.ts | 45 - server/tests/api/check-params/video-studio.ts | 388 ------- server/tests/api/check-params/video-token.ts | 70 -- .../api/check-params/videos-common-filters.ts | 163 --- server/tests/api/check-params/videos-history.ts | 145 --- server/tests/api/check-params/videos-overviews.ts | 31 - server/tests/api/check-params/videos.ts | 881 -------------- server/tests/api/check-params/views.ts | 227 ---- server/tests/api/index.ts | 13 - server/tests/api/live/index.ts | 7 - server/tests/api/live/live-constraints.ts | 237 ---- server/tests/api/live/live-fast-restream.ts | 153 --- server/tests/api/live/live-permanent.ts | 204 ---- server/tests/api/live/live-rtmps.ts | 143 --- server/tests/api/live/live-save-replay.ts | 570 --------- server/tests/api/live/live-socket-messages.ts | 186 --- server/tests/api/live/live.ts | 764 ------------- server/tests/api/moderation/abuses.ts | 887 -------------- .../tests/api/moderation/blocklist-notification.ts | 231 ---- server/tests/api/moderation/blocklist.ts | 902 --------------- server/tests/api/moderation/index.ts | 4 - server/tests/api/moderation/video-blacklist.ts | 414 ------- .../tests/api/notifications/admin-notifications.ts | 159 --- .../api/notifications/comments-notifications.ts | 305 ----- server/tests/api/notifications/index.ts | 6 - .../api/notifications/moderation-notifications.ts | 609 ---------- .../tests/api/notifications/notifications-api.ts | 206 ---- .../notifications/registrations-notifications.ts | 88 -- .../tests/api/notifications/user-notifications.ts | 574 ---------- server/tests/api/object-storage/index.ts | 4 - server/tests/api/object-storage/live.ts | 311 ----- server/tests/api/object-storage/video-imports.ts | 111 -- .../object-storage/video-static-file-privacy.ts | 570 --------- server/tests/api/object-storage/videos.ts | 438 ------- server/tests/api/redundancy/index.ts | 3 - server/tests/api/redundancy/manage-redundancy.ts | 324 ------ .../tests/api/redundancy/redundancy-constraints.ts | 191 ---- server/tests/api/redundancy/redundancy.ts | 742 ------------ server/tests/api/runners/index.ts | 5 - server/tests/api/runners/runner-common.ts | 743 ------------ .../tests/api/runners/runner-live-transcoding.ts | 330 ------ server/tests/api/runners/runner-socket.ts | 120 -- .../tests/api/runners/runner-studio-transcoding.ts | 168 --- server/tests/api/runners/runner-vod-transcoding.ts | 545 --------- server/tests/api/search/index.ts | 7 - .../search/search-activitypub-video-channels.ts | 255 ----- .../search/search-activitypub-video-playlists.ts | 214 ---- .../tests/api/search/search-activitypub-videos.ts | 196 ---- server/tests/api/search/search-channels.ts | 159 --- server/tests/api/search/search-index.ts | 432 ------- server/tests/api/search/search-playlists.ts | 180 --- server/tests/api/search/search-videos.ts | 568 --------- server/tests/api/server/auto-follows.ts | 189 --- server/tests/api/server/bulk.ts | 185 --- server/tests/api/server/config-defaults.ts | 288 ----- server/tests/api/server/config.ts | 645 ----------- server/tests/api/server/contact-form.ts | 101 -- server/tests/api/server/email.ts | 371 ------ server/tests/api/server/follow-constraints.ts | 321 ------ server/tests/api/server/follows-moderation.ts | 364 ------ server/tests/api/server/follows.ts | 641 ----------- server/tests/api/server/handle-down.ts | 338 ------ server/tests/api/server/homepage.ts | 81 -- server/tests/api/server/index.ts | 22 - server/tests/api/server/jobs.ts | 128 --- server/tests/api/server/logs.ts | 265 ----- server/tests/api/server/no-client.ts | 24 - server/tests/api/server/open-telemetry.ts | 186 --- server/tests/api/server/plugins.ts | 409 ------- server/tests/api/server/proxy.ts | 171 --- server/tests/api/server/reverse-proxy.ts | 156 --- server/tests/api/server/services.ts | 137 --- server/tests/api/server/slow-follows.ts | 85 -- server/tests/api/server/stats.ts | 279 ----- server/tests/api/server/tracker.ts | 104 -- server/tests/api/transcoding/audio-only.ts | 104 -- server/tests/api/transcoding/create-transcoding.ts | 266 ----- server/tests/api/transcoding/hls.ts | 175 --- server/tests/api/transcoding/index.ts | 6 - server/tests/api/transcoding/transcoder.ts | 800 ------------- .../api/transcoding/update-while-transcoding.ts | 160 --- server/tests/api/transcoding/video-studio.ts | 377 ------ server/tests/api/users/index.ts | 8 - server/tests/api/users/oauth.ts | 197 ---- server/tests/api/users/registrations.ts | 415 ------- server/tests/api/users/two-factor.ts | 200 ---- server/tests/api/users/user-subscriptions.ts | 614 ---------- server/tests/api/users/user-videos.ts | 219 ---- server/tests/api/users/users-email-verification.ts | 165 --- server/tests/api/users/users-multiple-servers.ts | 216 ---- server/tests/api/users/users.ts | 529 --------- server/tests/api/videos/channel-import-videos.ts | 161 --- server/tests/api/videos/index.ts | 23 - server/tests/api/videos/multiple-servers.ts | 1099 ------------------ server/tests/api/videos/resumable-upload.ts | 310 ----- server/tests/api/videos/single-server.ts | 460 -------- server/tests/api/videos/video-captions.ts | 188 --- server/tests/api/videos/video-change-ownership.ts | 314 ----- server/tests/api/videos/video-channel-syncs.ts | 320 ------ server/tests/api/videos/video-channels.ts | 555 --------- server/tests/api/videos/video-comments.ts | 335 ------ server/tests/api/videos/video-description.ts | 103 -- server/tests/api/videos/video-files.ts | 202 ---- server/tests/api/videos/video-imports.ts | 631 ---------- server/tests/api/videos/video-nsfw.ts | 227 ---- server/tests/api/videos/video-passwords.ts | 97 -- .../tests/api/videos/video-playlist-thumbnails.ts | 234 ---- server/tests/api/videos/video-playlists.ts | 1208 -------------------- server/tests/api/videos/video-privacy.ts | 287 ----- server/tests/api/videos/video-schedule-update.ts | 155 --- server/tests/api/videos/video-source.ts | 447 -------- .../tests/api/videos/video-static-file-privacy.ts | 600 ---------- server/tests/api/videos/video-storyboard.ts | 213 ---- server/tests/api/videos/videos-common-filters.ts | 489 -------- server/tests/api/videos/videos-history.ts | 224 ---- server/tests/api/videos/videos-overview.ts | 129 --- server/tests/api/views/index.ts | 5 - server/tests/api/views/video-views-counter.ts | 153 --- .../tests/api/views/video-views-overall-stats.ts | 368 ------ .../tests/api/views/video-views-retention-stats.ts | 53 - .../tests/api/views/video-views-timeserie-stats.ts | 253 ---- server/tests/api/views/videos-views-cleaner.ts | 98 -- server/tests/cli/create-generate-storyboard-job.ts | 120 -- server/tests/cli/create-import-video-file-job.ts | 168 --- server/tests/cli/create-move-video-storage-job.ts | 124 -- server/tests/cli/index.ts | 10 - server/tests/cli/peertube.ts | 331 ------ server/tests/cli/plugins.ts | 76 -- server/tests/cli/prune-storage.ts | 223 ---- server/tests/cli/regenerate-thumbnails.ts | 122 -- server/tests/cli/reset-password.ts | 26 - server/tests/cli/update-host.ts | 134 --- server/tests/client.ts | 556 --------- server/tests/external-plugins/akismet.ts | 160 --- server/tests/external-plugins/auth-ldap.ts | 117 -- server/tests/external-plugins/auto-block-videos.ts | 167 --- server/tests/external-plugins/auto-mute.ts | 216 ---- server/tests/external-plugins/index.ts | 4 - server/tests/feeds/feeds.ts | 695 ----------- server/tests/feeds/index.ts | 1 - server/tests/fixtures/60fps_720p_small.mp4 | Bin 276786 -> 0 bytes .../ap-json/mastodon/bad-body-http-signature.json | 93 -- .../ap-json/mastodon/bad-http-signature.json | 93 -- .../fixtures/ap-json/mastodon/bad-public-key.json | 3 - .../ap-json/mastodon/create-bad-signature.json | 81 -- server/tests/fixtures/ap-json/mastodon/create.json | 81 -- .../fixtures/ap-json/mastodon/http-signature.json | 93 -- .../fixtures/ap-json/mastodon/public-key.json | 3 - .../ap-json/peertube/announce-without-context.json | 13 - .../fixtures/ap-json/peertube/invalid-keys.json | 6 - server/tests/fixtures/ap-json/peertube/keys.json | 4 - server/tests/fixtures/avatar-big.png | Bin 146585 -> 0 bytes server/tests/fixtures/avatar-resized-120x120.gif | Bin 88318 -> 0 bytes server/tests/fixtures/avatar-resized-120x120.png | Bin 1727 -> 0 bytes server/tests/fixtures/avatar-resized-48x48.gif | Bin 20462 -> 0 bytes server/tests/fixtures/avatar-resized-48x48.png | Bin 727 -> 0 bytes server/tests/fixtures/avatar.gif | Bin 46917 -> 0 bytes server/tests/fixtures/avatar.png | Bin 1674 -> 0 bytes server/tests/fixtures/avatar2-resized-120x120.png | Bin 1725 -> 0 bytes server/tests/fixtures/avatar2-resized-48x48.png | Bin 760 -> 0 bytes server/tests/fixtures/avatar2.png | Bin 4850 -> 0 bytes server/tests/fixtures/banner-resized.jpg | Bin 59947 -> 0 bytes server/tests/fixtures/banner.jpg | Bin 31648 -> 0 bytes server/tests/fixtures/custom-preview-big.png | Bin 536513 -> 0 bytes server/tests/fixtures/custom-preview.jpg | Bin 14146 -> 0 bytes server/tests/fixtures/custom-thumbnail-big.jpg | Bin 20379 -> 0 bytes server/tests/fixtures/custom-thumbnail.jpg | Bin 6898 -> 0 bytes server/tests/fixtures/custom-thumbnail.png | Bin 18070 -> 0 bytes server/tests/fixtures/exif.jpg | Bin 10877 -> 0 bytes server/tests/fixtures/exif.png | Bin 21059 -> 0 bytes server/tests/fixtures/live/0-000067.ts | Bin 270532 -> 0 bytes server/tests/fixtures/live/0-000068.ts | Bin 181420 -> 0 bytes server/tests/fixtures/live/0-000069.ts | Bin 345732 -> 0 bytes server/tests/fixtures/live/0-000070.ts | Bin 282376 -> 0 bytes server/tests/fixtures/live/0.m3u8 | 14 - server/tests/fixtures/live/1-000067.ts | Bin 620024 -> 0 bytes server/tests/fixtures/live/1-000068.ts | Bin 382392 -> 0 bytes server/tests/fixtures/live/1-000069.ts | Bin 712332 -> 0 bytes server/tests/fixtures/live/1-000070.ts | Bin 608556 -> 0 bytes server/tests/fixtures/live/1.m3u8 | 14 - server/tests/fixtures/live/master.m3u8 | 8 - server/tests/fixtures/low-bitrate.mp4 | Bin 43850 -> 0 bytes .../fixtures/peertube-plugin-test-broken/main.js | 12 - .../peertube-plugin-test-broken/package.json | 20 - .../peertube-plugin-test-external-auth-one/main.js | 85 -- .../package.json | 20 - .../main.js | 53 - .../package.json | 20 - .../peertube-plugin-test-external-auth-two/main.js | 95 -- .../package.json | 20 - .../languages/fr.json | 3 - .../languages/it.json | 3 - .../main.js | 21 - .../package.json | 23 - .../fixtures/peertube-plugin-test-five/main.js | 23 - .../peertube-plugin-test-five/package.json | 20 - .../fixtures/peertube-plugin-test-four/main.js | 201 ---- .../peertube-plugin-test-four/package.json | 20 - .../peertube-plugin-test-id-pass-auth-one/main.js | 69 -- .../package.json | 20 - .../main.js | 106 -- .../package.json | 20 - .../peertube-plugin-test-id-pass-auth-two/main.js | 65 -- .../package.json | 20 - .../fixtures/peertube-plugin-test-native/main.js | 21 - .../peertube-plugin-test-native/package.json | 23 - .../main.js | 82 -- .../package.json | 19 - .../fixtures/peertube-plugin-test-six/main.js | 46 - .../fixtures/peertube-plugin-test-six/package.json | 20 - .../peertube-plugin-test-transcoding-one/main.js | 92 -- .../package.json | 20 - .../peertube-plugin-test-transcoding-two/main.js | 38 - .../package.json | 20 - .../fixtures/peertube-plugin-test-unloading/lib.js | 2 - .../peertube-plugin-test-unloading/main.js | 14 - .../peertube-plugin-test-unloading/package.json | 20 - .../peertube-plugin-test-video-constants/main.js | 46 - .../package.json | 20 - .../peertube-plugin-test-websocket/main.js | 36 - .../peertube-plugin-test-websocket/package.json | 20 - .../peertube-plugin-test/languages/fr.json | 3 - server/tests/fixtures/peertube-plugin-test/main.js | 477 -------- .../fixtures/peertube-plugin-test/package.json | 22 - server/tests/fixtures/rtmps.cert | 21 - server/tests/fixtures/rtmps.key | 28 - server/tests/fixtures/sample.ogg | Bin 105243 -> 0 bytes server/tests/fixtures/subtitle-bad.txt | 11 - server/tests/fixtures/subtitle-good.srt | 11 - server/tests/fixtures/subtitle-good1.vtt | 8 - server/tests/fixtures/subtitle-good2.vtt | 8 - server/tests/fixtures/thumbnail-playlist.jpg | Bin 5040 -> 0 bytes server/tests/fixtures/video-720p.torrent | Bin 2644 -> 0 bytes server/tests/fixtures/video_import_preview.jpg | Bin 9551 -> 0 bytes .../tests/fixtures/video_import_preview_yt_dlp.jpg | Bin 15844 -> 0 bytes server/tests/fixtures/video_import_thumbnail.jpg | Bin 10980 -> 0 bytes .../fixtures/video_import_thumbnail_yt_dlp.jpg | Bin 10676 -> 0 bytes server/tests/fixtures/video_short.avi | Bin 584656 -> 0 bytes server/tests/fixtures/video_short.mkv | Bin 40642 -> 0 bytes server/tests/fixtures/video_short.mp4 | Bin 38783 -> 0 bytes server/tests/fixtures/video_short.mp4.jpg | Bin 5028 -> 0 bytes server/tests/fixtures/video_short.ogv | Bin 140849 -> 0 bytes server/tests/fixtures/video_short.ogv.jpg | Bin 5023 -> 0 bytes server/tests/fixtures/video_short.webm | Bin 218910 -> 0 bytes server/tests/fixtures/video_short.webm.jpg | Bin 5028 -> 0 bytes .../tests/fixtures/video_short1-preview.webm.jpg | Bin 31188 -> 0 bytes server/tests/fixtures/video_short1.webm | Bin 572456 -> 0 bytes server/tests/fixtures/video_short1.webm.jpg | Bin 6334 -> 0 bytes server/tests/fixtures/video_short2.webm | Bin 942961 -> 0 bytes server/tests/fixtures/video_short2.webm.jpg | Bin 6607 -> 0 bytes server/tests/fixtures/video_short3.webm | Bin 292677 -> 0 bytes server/tests/fixtures/video_short3.webm.jpg | Bin 5674 -> 0 bytes server/tests/fixtures/video_short_0p.mp4 | Bin 3051 -> 0 bytes server/tests/fixtures/video_short_144p.m3u8 | 13 - server/tests/fixtures/video_short_144p.mp4 | Bin 15634 -> 0 bytes server/tests/fixtures/video_short_240p.m3u8 | 13 - server/tests/fixtures/video_short_240p.mp4 | Bin 23084 -> 0 bytes server/tests/fixtures/video_short_360p.m3u8 | 13 - server/tests/fixtures/video_short_360p.mp4 | Bin 30620 -> 0 bytes server/tests/fixtures/video_short_480.webm | Bin 69217 -> 0 bytes server/tests/fixtures/video_short_480p.m3u8 | 13 - server/tests/fixtures/video_short_480p.mp4 | Bin 39881 -> 0 bytes server/tests/fixtures/video_short_4k.mp4 | Bin 618949 -> 0 bytes server/tests/fixtures/video_short_720p.m3u8 | 13 - server/tests/fixtures/video_short_720p.mp4 | Bin 59109 -> 0 bytes server/tests/fixtures/video_short_fake.webm | 1 - server/tests/fixtures/video_short_mp3_256k.mp4 | Bin 194985 -> 0 bytes server/tests/fixtures/video_short_no_audio.mp4 | Bin 34259 -> 0 bytes server/tests/fixtures/video_very_long_10p.mp4 | Bin 185338 -> 0 bytes server/tests/fixtures/video_very_short_240p.mp4 | Bin 9352 -> 0 bytes server/tests/helpers/comment-model.ts | 24 - server/tests/helpers/core-utils.ts | 150 --- server/tests/helpers/crypto.ts | 33 - server/tests/helpers/dns.ts | 16 - server/tests/helpers/image.ts | 96 -- server/tests/helpers/index.ts | 9 - server/tests/helpers/markdown.ts | 39 - server/tests/helpers/request.ts | 62 - server/tests/helpers/validator.ts | 32 - server/tests/helpers/version.ts | 36 - server/tests/index.ts | 10 - server/tests/lib/index.ts | 1 - .../tests/lib/video-constant-registry-factory.ts | 154 --- server/tests/misc-endpoints.ts | 237 ---- server/tests/peertube-runner/client-cli.ts | 70 -- server/tests/peertube-runner/index.ts | 4 - server/tests/peertube-runner/live-transcoding.ts | 201 ---- server/tests/peertube-runner/studio-transcoding.ts | 124 -- server/tests/peertube-runner/vod-transcoding.ts | 350 ------ server/tests/plugins/action-hooks.ts | 298 ----- server/tests/plugins/external-auth.ts | 436 ------- server/tests/plugins/filter-hooks.ts | 909 --------------- server/tests/plugins/html-injection.ts | 73 -- server/tests/plugins/id-and-pass-auth.ts | 242 ---- server/tests/plugins/index.ts | 13 - server/tests/plugins/plugin-helpers.ts | 383 ------- server/tests/plugins/plugin-router.ts | 105 -- server/tests/plugins/plugin-storage.ts | 94 -- server/tests/plugins/plugin-transcoding.ts | 279 ----- server/tests/plugins/plugin-unloading.ts | 75 -- server/tests/plugins/plugin-websocket.ts | 70 -- server/tests/plugins/translations.ts | 74 -- server/tests/plugins/video-constants.ts | 180 --- server/tests/shared/actors.ts | 69 -- server/tests/shared/captions.ts | 21 - server/tests/shared/checks.ts | 174 --- server/tests/shared/directories.ts | 43 - server/tests/shared/generate.ts | 74 -- server/tests/shared/index.ts | 19 - server/tests/shared/live.ts | 185 --- server/tests/shared/mock-servers/index.ts | 8 - server/tests/shared/mock-servers/mock-429.ts | 33 - server/tests/shared/mock-servers/mock-email.ts | 61 - server/tests/shared/mock-servers/mock-http.ts | 23 - .../shared/mock-servers/mock-instances-index.ts | 46 - .../mock-servers/mock-joinpeertube-versions.ts | 34 - .../shared/mock-servers/mock-object-storage.ts | 41 - .../shared/mock-servers/mock-plugin-blocklist.ts | 36 - server/tests/shared/mock-servers/mock-proxy.ts | 24 - server/tests/shared/mock-servers/shared.ts | 33 - server/tests/shared/notifications.ts | 889 -------------- server/tests/shared/peertube-runner-process.ts | 98 -- server/tests/shared/plugins.ts | 18 - server/tests/shared/requests.ts | 12 - server/tests/shared/sql-command.ts | 150 --- server/tests/shared/streaming-playlists.ts | 296 ----- server/tests/shared/tests.ts | 40 - server/tests/shared/tracker.ts | 27 - server/tests/shared/video-playlists.ts | 22 - server/tests/shared/videos.ts | 315 ----- server/tests/shared/views.ts | 93 -- server/tests/shared/webtorrent.ts | 58 - 378 files changed, 62105 deletions(-) delete mode 100644 server/tests/api/activitypub/cleaner.ts delete mode 100644 server/tests/api/activitypub/client.ts delete mode 100644 server/tests/api/activitypub/fetch.ts delete mode 100644 server/tests/api/activitypub/helpers.ts delete mode 100644 server/tests/api/activitypub/index.ts delete mode 100644 server/tests/api/activitypub/refresher.ts delete mode 100644 server/tests/api/activitypub/security.ts delete mode 100644 server/tests/api/check-params/abuses.ts delete mode 100644 server/tests/api/check-params/accounts.ts delete mode 100644 server/tests/api/check-params/blocklist.ts delete mode 100644 server/tests/api/check-params/bulk.ts delete mode 100644 server/tests/api/check-params/channel-import-videos.ts delete mode 100644 server/tests/api/check-params/config.ts delete mode 100644 server/tests/api/check-params/contact-form.ts delete mode 100644 server/tests/api/check-params/custom-pages.ts delete mode 100644 server/tests/api/check-params/debug.ts delete mode 100644 server/tests/api/check-params/follows.ts delete mode 100644 server/tests/api/check-params/index.ts delete mode 100644 server/tests/api/check-params/jobs.ts delete mode 100644 server/tests/api/check-params/live.ts delete mode 100644 server/tests/api/check-params/logs.ts delete mode 100644 server/tests/api/check-params/metrics.ts delete mode 100644 server/tests/api/check-params/my-user.ts delete mode 100644 server/tests/api/check-params/plugins.ts delete mode 100644 server/tests/api/check-params/redundancy.ts delete mode 100644 server/tests/api/check-params/registrations.ts delete mode 100644 server/tests/api/check-params/runners.ts delete mode 100644 server/tests/api/check-params/search.ts delete mode 100644 server/tests/api/check-params/services.ts delete mode 100644 server/tests/api/check-params/transcoding.ts delete mode 100644 server/tests/api/check-params/two-factor.ts delete mode 100644 server/tests/api/check-params/upload-quota.ts delete mode 100644 server/tests/api/check-params/user-notifications.ts delete mode 100644 server/tests/api/check-params/user-subscriptions.ts delete mode 100644 server/tests/api/check-params/users-admin.ts delete mode 100644 server/tests/api/check-params/users-emails.ts delete mode 100644 server/tests/api/check-params/video-blacklist.ts delete mode 100644 server/tests/api/check-params/video-captions.ts delete mode 100644 server/tests/api/check-params/video-channel-syncs.ts delete mode 100644 server/tests/api/check-params/video-channels.ts delete mode 100644 server/tests/api/check-params/video-comments.ts delete mode 100644 server/tests/api/check-params/video-files.ts delete mode 100644 server/tests/api/check-params/video-imports.ts delete mode 100644 server/tests/api/check-params/video-passwords.ts delete mode 100644 server/tests/api/check-params/video-playlists.ts delete mode 100644 server/tests/api/check-params/video-source.ts delete mode 100644 server/tests/api/check-params/video-storyboards.ts delete mode 100644 server/tests/api/check-params/video-studio.ts delete mode 100644 server/tests/api/check-params/video-token.ts delete mode 100644 server/tests/api/check-params/videos-common-filters.ts delete mode 100644 server/tests/api/check-params/videos-history.ts delete mode 100644 server/tests/api/check-params/videos-overviews.ts delete mode 100644 server/tests/api/check-params/videos.ts delete mode 100644 server/tests/api/check-params/views.ts delete mode 100644 server/tests/api/index.ts delete mode 100644 server/tests/api/live/index.ts delete mode 100644 server/tests/api/live/live-constraints.ts delete mode 100644 server/tests/api/live/live-fast-restream.ts delete mode 100644 server/tests/api/live/live-permanent.ts delete mode 100644 server/tests/api/live/live-rtmps.ts delete mode 100644 server/tests/api/live/live-save-replay.ts delete mode 100644 server/tests/api/live/live-socket-messages.ts delete mode 100644 server/tests/api/live/live.ts delete mode 100644 server/tests/api/moderation/abuses.ts delete mode 100644 server/tests/api/moderation/blocklist-notification.ts delete mode 100644 server/tests/api/moderation/blocklist.ts delete mode 100644 server/tests/api/moderation/index.ts delete mode 100644 server/tests/api/moderation/video-blacklist.ts delete mode 100644 server/tests/api/notifications/admin-notifications.ts delete mode 100644 server/tests/api/notifications/comments-notifications.ts delete mode 100644 server/tests/api/notifications/index.ts delete mode 100644 server/tests/api/notifications/moderation-notifications.ts delete mode 100644 server/tests/api/notifications/notifications-api.ts delete mode 100644 server/tests/api/notifications/registrations-notifications.ts delete mode 100644 server/tests/api/notifications/user-notifications.ts delete mode 100644 server/tests/api/object-storage/index.ts delete mode 100644 server/tests/api/object-storage/live.ts delete mode 100644 server/tests/api/object-storage/video-imports.ts delete mode 100644 server/tests/api/object-storage/video-static-file-privacy.ts delete mode 100644 server/tests/api/object-storage/videos.ts delete mode 100644 server/tests/api/redundancy/index.ts delete mode 100644 server/tests/api/redundancy/manage-redundancy.ts delete mode 100644 server/tests/api/redundancy/redundancy-constraints.ts delete mode 100644 server/tests/api/redundancy/redundancy.ts delete mode 100644 server/tests/api/runners/index.ts delete mode 100644 server/tests/api/runners/runner-common.ts delete mode 100644 server/tests/api/runners/runner-live-transcoding.ts delete mode 100644 server/tests/api/runners/runner-socket.ts delete mode 100644 server/tests/api/runners/runner-studio-transcoding.ts delete mode 100644 server/tests/api/runners/runner-vod-transcoding.ts delete mode 100644 server/tests/api/search/index.ts delete mode 100644 server/tests/api/search/search-activitypub-video-channels.ts delete mode 100644 server/tests/api/search/search-activitypub-video-playlists.ts delete mode 100644 server/tests/api/search/search-activitypub-videos.ts delete mode 100644 server/tests/api/search/search-channels.ts delete mode 100644 server/tests/api/search/search-index.ts delete mode 100644 server/tests/api/search/search-playlists.ts delete mode 100644 server/tests/api/search/search-videos.ts delete mode 100644 server/tests/api/server/auto-follows.ts delete mode 100644 server/tests/api/server/bulk.ts delete mode 100644 server/tests/api/server/config-defaults.ts delete mode 100644 server/tests/api/server/config.ts delete mode 100644 server/tests/api/server/contact-form.ts delete mode 100644 server/tests/api/server/email.ts delete mode 100644 server/tests/api/server/follow-constraints.ts delete mode 100644 server/tests/api/server/follows-moderation.ts delete mode 100644 server/tests/api/server/follows.ts delete mode 100644 server/tests/api/server/handle-down.ts delete mode 100644 server/tests/api/server/homepage.ts delete mode 100644 server/tests/api/server/index.ts delete mode 100644 server/tests/api/server/jobs.ts delete mode 100644 server/tests/api/server/logs.ts delete mode 100644 server/tests/api/server/no-client.ts delete mode 100644 server/tests/api/server/open-telemetry.ts delete mode 100644 server/tests/api/server/plugins.ts delete mode 100644 server/tests/api/server/proxy.ts delete mode 100644 server/tests/api/server/reverse-proxy.ts delete mode 100644 server/tests/api/server/services.ts delete mode 100644 server/tests/api/server/slow-follows.ts delete mode 100644 server/tests/api/server/stats.ts delete mode 100644 server/tests/api/server/tracker.ts delete mode 100644 server/tests/api/transcoding/audio-only.ts delete mode 100644 server/tests/api/transcoding/create-transcoding.ts delete mode 100644 server/tests/api/transcoding/hls.ts delete mode 100644 server/tests/api/transcoding/index.ts delete mode 100644 server/tests/api/transcoding/transcoder.ts delete mode 100644 server/tests/api/transcoding/update-while-transcoding.ts delete mode 100644 server/tests/api/transcoding/video-studio.ts delete mode 100644 server/tests/api/users/index.ts delete mode 100644 server/tests/api/users/oauth.ts delete mode 100644 server/tests/api/users/registrations.ts delete mode 100644 server/tests/api/users/two-factor.ts delete mode 100644 server/tests/api/users/user-subscriptions.ts delete mode 100644 server/tests/api/users/user-videos.ts delete mode 100644 server/tests/api/users/users-email-verification.ts delete mode 100644 server/tests/api/users/users-multiple-servers.ts delete mode 100644 server/tests/api/users/users.ts delete mode 100644 server/tests/api/videos/channel-import-videos.ts delete mode 100644 server/tests/api/videos/index.ts delete mode 100644 server/tests/api/videos/multiple-servers.ts delete mode 100644 server/tests/api/videos/resumable-upload.ts delete mode 100644 server/tests/api/videos/single-server.ts delete mode 100644 server/tests/api/videos/video-captions.ts delete mode 100644 server/tests/api/videos/video-change-ownership.ts delete mode 100644 server/tests/api/videos/video-channel-syncs.ts delete mode 100644 server/tests/api/videos/video-channels.ts delete mode 100644 server/tests/api/videos/video-comments.ts delete mode 100644 server/tests/api/videos/video-description.ts delete mode 100644 server/tests/api/videos/video-files.ts delete mode 100644 server/tests/api/videos/video-imports.ts delete mode 100644 server/tests/api/videos/video-nsfw.ts delete mode 100644 server/tests/api/videos/video-passwords.ts delete mode 100644 server/tests/api/videos/video-playlist-thumbnails.ts delete mode 100644 server/tests/api/videos/video-playlists.ts delete mode 100644 server/tests/api/videos/video-privacy.ts delete mode 100644 server/tests/api/videos/video-schedule-update.ts delete mode 100644 server/tests/api/videos/video-source.ts delete mode 100644 server/tests/api/videos/video-static-file-privacy.ts delete mode 100644 server/tests/api/videos/video-storyboard.ts delete mode 100644 server/tests/api/videos/videos-common-filters.ts delete mode 100644 server/tests/api/videos/videos-history.ts delete mode 100644 server/tests/api/videos/videos-overview.ts delete mode 100644 server/tests/api/views/index.ts delete mode 100644 server/tests/api/views/video-views-counter.ts delete mode 100644 server/tests/api/views/video-views-overall-stats.ts delete mode 100644 server/tests/api/views/video-views-retention-stats.ts delete mode 100644 server/tests/api/views/video-views-timeserie-stats.ts delete mode 100644 server/tests/api/views/videos-views-cleaner.ts delete mode 100644 server/tests/cli/create-generate-storyboard-job.ts delete mode 100644 server/tests/cli/create-import-video-file-job.ts delete mode 100644 server/tests/cli/create-move-video-storage-job.ts delete mode 100644 server/tests/cli/index.ts delete mode 100644 server/tests/cli/peertube.ts delete mode 100644 server/tests/cli/plugins.ts delete mode 100644 server/tests/cli/prune-storage.ts delete mode 100644 server/tests/cli/regenerate-thumbnails.ts delete mode 100644 server/tests/cli/reset-password.ts delete mode 100644 server/tests/cli/update-host.ts delete mode 100644 server/tests/client.ts delete mode 100644 server/tests/external-plugins/akismet.ts delete mode 100644 server/tests/external-plugins/auth-ldap.ts delete mode 100644 server/tests/external-plugins/auto-block-videos.ts delete mode 100644 server/tests/external-plugins/auto-mute.ts delete mode 100644 server/tests/external-plugins/index.ts delete mode 100644 server/tests/feeds/feeds.ts delete mode 100644 server/tests/feeds/index.ts delete mode 100644 server/tests/fixtures/60fps_720p_small.mp4 delete mode 100644 server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/bad-http-signature.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/bad-public-key.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/create-bad-signature.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/create.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/http-signature.json delete mode 100644 server/tests/fixtures/ap-json/mastodon/public-key.json delete mode 100644 server/tests/fixtures/ap-json/peertube/announce-without-context.json delete mode 100644 server/tests/fixtures/ap-json/peertube/invalid-keys.json delete mode 100644 server/tests/fixtures/ap-json/peertube/keys.json delete mode 100644 server/tests/fixtures/avatar-big.png delete mode 100644 server/tests/fixtures/avatar-resized-120x120.gif delete mode 100644 server/tests/fixtures/avatar-resized-120x120.png delete mode 100644 server/tests/fixtures/avatar-resized-48x48.gif delete mode 100644 server/tests/fixtures/avatar-resized-48x48.png delete mode 100644 server/tests/fixtures/avatar.gif delete mode 100644 server/tests/fixtures/avatar.png delete mode 100644 server/tests/fixtures/avatar2-resized-120x120.png delete mode 100644 server/tests/fixtures/avatar2-resized-48x48.png delete mode 100644 server/tests/fixtures/avatar2.png delete mode 100644 server/tests/fixtures/banner-resized.jpg delete mode 100644 server/tests/fixtures/banner.jpg delete mode 100644 server/tests/fixtures/custom-preview-big.png delete mode 100644 server/tests/fixtures/custom-preview.jpg delete mode 100644 server/tests/fixtures/custom-thumbnail-big.jpg delete mode 100644 server/tests/fixtures/custom-thumbnail.jpg delete mode 100644 server/tests/fixtures/custom-thumbnail.png delete mode 100644 server/tests/fixtures/exif.jpg delete mode 100644 server/tests/fixtures/exif.png delete mode 100644 server/tests/fixtures/live/0-000067.ts delete mode 100644 server/tests/fixtures/live/0-000068.ts delete mode 100644 server/tests/fixtures/live/0-000069.ts delete mode 100644 server/tests/fixtures/live/0-000070.ts delete mode 100644 server/tests/fixtures/live/0.m3u8 delete mode 100644 server/tests/fixtures/live/1-000067.ts delete mode 100644 server/tests/fixtures/live/1-000068.ts delete mode 100644 server/tests/fixtures/live/1-000069.ts delete mode 100644 server/tests/fixtures/live/1-000070.ts delete mode 100644 server/tests/fixtures/live/1.m3u8 delete mode 100644 server/tests/fixtures/live/master.m3u8 delete mode 100644 server/tests/fixtures/low-bitrate.mp4 delete mode 100644 server/tests/fixtures/peertube-plugin-test-broken/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-broken/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-one/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-three/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-three/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-two/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-external-auth-two/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-filter-translations/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-filter-translations/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-five/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-five/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-four/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-four/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-native/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-native/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-six/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-six/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-transcoding-one/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-transcoding-one/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-transcoding-two/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-transcoding-two/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-unloading/lib.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-unloading/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-unloading/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-video-constants/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-video-constants/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test-websocket/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test-websocket/package.json delete mode 100644 server/tests/fixtures/peertube-plugin-test/languages/fr.json delete mode 100644 server/tests/fixtures/peertube-plugin-test/main.js delete mode 100644 server/tests/fixtures/peertube-plugin-test/package.json delete mode 100644 server/tests/fixtures/rtmps.cert delete mode 100644 server/tests/fixtures/rtmps.key delete mode 100644 server/tests/fixtures/sample.ogg delete mode 100644 server/tests/fixtures/subtitle-bad.txt delete mode 100644 server/tests/fixtures/subtitle-good.srt delete mode 100644 server/tests/fixtures/subtitle-good1.vtt delete mode 100644 server/tests/fixtures/subtitle-good2.vtt delete mode 100644 server/tests/fixtures/thumbnail-playlist.jpg delete mode 100644 server/tests/fixtures/video-720p.torrent delete mode 100644 server/tests/fixtures/video_import_preview.jpg delete mode 100644 server/tests/fixtures/video_import_preview_yt_dlp.jpg delete mode 100644 server/tests/fixtures/video_import_thumbnail.jpg delete mode 100644 server/tests/fixtures/video_import_thumbnail_yt_dlp.jpg delete mode 100644 server/tests/fixtures/video_short.avi delete mode 100644 server/tests/fixtures/video_short.mkv delete mode 100644 server/tests/fixtures/video_short.mp4 delete mode 100644 server/tests/fixtures/video_short.mp4.jpg delete mode 100644 server/tests/fixtures/video_short.ogv delete mode 100644 server/tests/fixtures/video_short.ogv.jpg delete mode 100644 server/tests/fixtures/video_short.webm delete mode 100644 server/tests/fixtures/video_short.webm.jpg delete mode 100644 server/tests/fixtures/video_short1-preview.webm.jpg delete mode 100644 server/tests/fixtures/video_short1.webm delete mode 100644 server/tests/fixtures/video_short1.webm.jpg delete mode 100644 server/tests/fixtures/video_short2.webm delete mode 100644 server/tests/fixtures/video_short2.webm.jpg delete mode 100644 server/tests/fixtures/video_short3.webm delete mode 100644 server/tests/fixtures/video_short3.webm.jpg delete mode 100644 server/tests/fixtures/video_short_0p.mp4 delete mode 100644 server/tests/fixtures/video_short_144p.m3u8 delete mode 100644 server/tests/fixtures/video_short_144p.mp4 delete mode 100644 server/tests/fixtures/video_short_240p.m3u8 delete mode 100644 server/tests/fixtures/video_short_240p.mp4 delete mode 100644 server/tests/fixtures/video_short_360p.m3u8 delete mode 100644 server/tests/fixtures/video_short_360p.mp4 delete mode 100644 server/tests/fixtures/video_short_480.webm delete mode 100644 server/tests/fixtures/video_short_480p.m3u8 delete mode 100644 server/tests/fixtures/video_short_480p.mp4 delete mode 100644 server/tests/fixtures/video_short_4k.mp4 delete mode 100644 server/tests/fixtures/video_short_720p.m3u8 delete mode 100644 server/tests/fixtures/video_short_720p.mp4 delete mode 100644 server/tests/fixtures/video_short_fake.webm delete mode 100644 server/tests/fixtures/video_short_mp3_256k.mp4 delete mode 100644 server/tests/fixtures/video_short_no_audio.mp4 delete mode 100644 server/tests/fixtures/video_very_long_10p.mp4 delete mode 100644 server/tests/fixtures/video_very_short_240p.mp4 delete mode 100644 server/tests/helpers/comment-model.ts delete mode 100644 server/tests/helpers/core-utils.ts delete mode 100644 server/tests/helpers/crypto.ts delete mode 100644 server/tests/helpers/dns.ts delete mode 100644 server/tests/helpers/image.ts delete mode 100644 server/tests/helpers/index.ts delete mode 100644 server/tests/helpers/markdown.ts delete mode 100644 server/tests/helpers/request.ts delete mode 100644 server/tests/helpers/validator.ts delete mode 100644 server/tests/helpers/version.ts delete mode 100644 server/tests/index.ts delete mode 100644 server/tests/lib/index.ts delete mode 100644 server/tests/lib/video-constant-registry-factory.ts delete mode 100644 server/tests/misc-endpoints.ts delete mode 100644 server/tests/peertube-runner/client-cli.ts delete mode 100644 server/tests/peertube-runner/index.ts delete mode 100644 server/tests/peertube-runner/live-transcoding.ts delete mode 100644 server/tests/peertube-runner/studio-transcoding.ts delete mode 100644 server/tests/peertube-runner/vod-transcoding.ts delete mode 100644 server/tests/plugins/action-hooks.ts delete mode 100644 server/tests/plugins/external-auth.ts delete mode 100644 server/tests/plugins/filter-hooks.ts delete mode 100644 server/tests/plugins/html-injection.ts delete mode 100644 server/tests/plugins/id-and-pass-auth.ts delete mode 100644 server/tests/plugins/index.ts delete mode 100644 server/tests/plugins/plugin-helpers.ts delete mode 100644 server/tests/plugins/plugin-router.ts delete mode 100644 server/tests/plugins/plugin-storage.ts delete mode 100644 server/tests/plugins/plugin-transcoding.ts delete mode 100644 server/tests/plugins/plugin-unloading.ts delete mode 100644 server/tests/plugins/plugin-websocket.ts delete mode 100644 server/tests/plugins/translations.ts delete mode 100644 server/tests/plugins/video-constants.ts delete mode 100644 server/tests/shared/actors.ts delete mode 100644 server/tests/shared/captions.ts delete mode 100644 server/tests/shared/checks.ts delete mode 100644 server/tests/shared/directories.ts delete mode 100644 server/tests/shared/generate.ts delete mode 100644 server/tests/shared/index.ts delete mode 100644 server/tests/shared/live.ts delete mode 100644 server/tests/shared/mock-servers/index.ts delete mode 100644 server/tests/shared/mock-servers/mock-429.ts delete mode 100644 server/tests/shared/mock-servers/mock-email.ts delete mode 100644 server/tests/shared/mock-servers/mock-http.ts delete mode 100644 server/tests/shared/mock-servers/mock-instances-index.ts delete mode 100644 server/tests/shared/mock-servers/mock-joinpeertube-versions.ts delete mode 100644 server/tests/shared/mock-servers/mock-object-storage.ts delete mode 100644 server/tests/shared/mock-servers/mock-plugin-blocklist.ts delete mode 100644 server/tests/shared/mock-servers/mock-proxy.ts delete mode 100644 server/tests/shared/mock-servers/shared.ts delete mode 100644 server/tests/shared/notifications.ts delete mode 100644 server/tests/shared/peertube-runner-process.ts delete mode 100644 server/tests/shared/plugins.ts delete mode 100644 server/tests/shared/requests.ts delete mode 100644 server/tests/shared/sql-command.ts delete mode 100644 server/tests/shared/streaming-playlists.ts delete mode 100644 server/tests/shared/tests.ts delete mode 100644 server/tests/shared/tracker.ts delete mode 100644 server/tests/shared/video-playlists.ts delete mode 100644 server/tests/shared/videos.ts delete mode 100644 server/tests/shared/views.ts delete mode 100644 server/tests/shared/webtorrent.ts (limited to 'server/tests') diff --git a/server/tests/api/activitypub/cleaner.ts b/server/tests/api/activitypub/cleaner.ts deleted file mode 100644 index d67175e20..000000000 --- a/server/tests/api/activitypub/cleaner.ts +++ /dev/null @@ -1,342 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { SQLCommand } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test AP cleaner', function () { - let servers: PeerTubeServer[] = [] - const sqlCommands: SQLCommand[] = [] - - let videoUUID1: string - let videoUUID2: string - let videoUUID3: string - - let videoUUIDs: string[] - - before(async function () { - this.timeout(120000) - - const config = { - federation: { - videos: { cleanup_remote_interactions: true } - } - } - servers = await createMultipleServers(3, config) - - // Get the access tokens - await setAccessTokensToServers(servers) - - await Promise.all([ - doubleFollow(servers[0], servers[1]), - doubleFollow(servers[1], servers[2]), - doubleFollow(servers[0], servers[2]) - ]) - - // Update 1 local share, check 6 shares - - // Create 1 comment per video - // Update 1 remote URL and 1 local URL on - - videoUUID1 = (await servers[0].videos.quickUpload({ name: 'server 1' })).uuid - videoUUID2 = (await servers[1].videos.quickUpload({ name: 'server 2' })).uuid - videoUUID3 = (await servers[2].videos.quickUpload({ name: 'server 3' })).uuid - - videoUUIDs = [ videoUUID1, videoUUID2, videoUUID3 ] - - await waitJobs(servers) - - for (const server of servers) { - for (const uuid of videoUUIDs) { - await server.videos.rate({ id: uuid, rating: 'like' }) - await server.comments.createThread({ videoId: uuid, text: 'comment' }) - } - - sqlCommands.push(new SQLCommand(server)) - } - - await waitJobs(servers) - }) - - it('Should have the correct likes', async function () { - for (const server of servers) { - for (const uuid of videoUUIDs) { - const video = await server.videos.get({ id: uuid }) - - expect(video.likes).to.equal(3) - expect(video.dislikes).to.equal(0) - } - } - }) - - it('Should destroy server 3 internal likes and correctly clean them', async function () { - this.timeout(20000) - - await sqlCommands[2].deleteAll('accountVideoRate') - for (const uuid of videoUUIDs) { - await sqlCommands[2].setVideoField(uuid, 'likes', '0') - } - - await wait(5000) - await waitJobs(servers) - - // Updated rates of my video - { - const video = await servers[0].videos.get({ id: videoUUID1 }) - expect(video.likes).to.equal(2) - expect(video.dislikes).to.equal(0) - } - - // Did not update rates of a remote video - { - const video = await servers[0].videos.get({ id: videoUUID2 }) - expect(video.likes).to.equal(3) - expect(video.dislikes).to.equal(0) - } - }) - - it('Should update rates to dislikes', async function () { - this.timeout(20000) - - for (const server of servers) { - for (const uuid of videoUUIDs) { - await server.videos.rate({ id: uuid, rating: 'dislike' }) - } - } - - await waitJobs(servers) - - for (const server of servers) { - for (const uuid of videoUUIDs) { - const video = await server.videos.get({ id: uuid }) - expect(video.likes).to.equal(0) - expect(video.dislikes).to.equal(3) - } - } - }) - - it('Should destroy server 3 internal dislikes and correctly clean them', async function () { - this.timeout(20000) - - await sqlCommands[2].deleteAll('accountVideoRate') - - for (const uuid of videoUUIDs) { - await sqlCommands[2].setVideoField(uuid, 'dislikes', '0') - } - - await wait(5000) - await waitJobs(servers) - - // Updated rates of my video - { - const video = await servers[0].videos.get({ id: videoUUID1 }) - expect(video.likes).to.equal(0) - expect(video.dislikes).to.equal(2) - } - - // Did not update rates of a remote video - { - const video = await servers[0].videos.get({ id: videoUUID2 }) - expect(video.likes).to.equal(0) - expect(video.dislikes).to.equal(3) - } - }) - - it('Should destroy server 3 internal shares and correctly clean them', async function () { - this.timeout(20000) - - const preCount = await sqlCommands[0].getVideoShareCount() - expect(preCount).to.equal(6) - - await sqlCommands[2].deleteAll('videoShare') - await wait(5000) - await waitJobs(servers) - - // Still 6 because we don't have remote shares on local videos - const postCount = await sqlCommands[0].getVideoShareCount() - expect(postCount).to.equal(6) - }) - - it('Should destroy server 3 internal comments and correctly clean them', async function () { - this.timeout(20000) - - { - const { total } = await servers[0].comments.listThreads({ videoId: videoUUID1 }) - expect(total).to.equal(3) - } - - await sqlCommands[2].deleteAll('videoComment') - - await wait(5000) - await waitJobs(servers) - - { - const { total } = await servers[0].comments.listThreads({ videoId: videoUUID1 }) - expect(total).to.equal(2) - } - }) - - it('Should correctly update rate URLs', async function () { - this.timeout(30000) - - async function check (like: string, ofServerUrl: string, urlSuffix: string, remote: 'true' | 'false') { - const query = `SELECT "videoId", "accountVideoRate".url FROM "accountVideoRate" ` + - `INNER JOIN video ON "accountVideoRate"."videoId" = video.id AND remote IS ${remote} WHERE "accountVideoRate"."url" LIKE '${like}'` - const res = await sqlCommands[0].selectQuery<{ url: string }>(query) - - for (const rate of res) { - const matcher = new RegExp(`^${ofServerUrl}/accounts/root/dislikes/\\d+${urlSuffix}$`) - expect(rate.url).to.match(matcher) - } - } - - async function checkLocal () { - const startsWith = 'http://' + servers[0].host + '%' - // On local videos - await check(startsWith, servers[0].url, '', 'false') - // On remote videos - await check(startsWith, servers[0].url, '', 'true') - } - - async function checkRemote (suffix: string) { - const startsWith = 'http://' + servers[1].host + '%' - // On local videos - await check(startsWith, servers[1].url, suffix, 'false') - // On remote videos, we should not update URLs so no suffix - await check(startsWith, servers[1].url, '', 'true') - } - - await checkLocal() - await checkRemote('') - - { - const query = `UPDATE "accountVideoRate" SET url = url || 'stan'` - await sqlCommands[1].updateQuery(query) - - await wait(5000) - await waitJobs(servers) - } - - await checkLocal() - await checkRemote('stan') - }) - - it('Should correctly update comment URLs', async function () { - this.timeout(30000) - - async function check (like: string, ofServerUrl: string, urlSuffix: string, remote: 'true' | 'false') { - const query = `SELECT "videoId", "videoComment".url, uuid as "videoUUID" FROM "videoComment" ` + - `INNER JOIN video ON "videoComment"."videoId" = video.id AND remote IS ${remote} WHERE "videoComment"."url" LIKE '${like}'` - - const res = await sqlCommands[0].selectQuery<{ url: string, videoUUID: string }>(query) - - for (const comment of res) { - const matcher = new RegExp(`${ofServerUrl}/videos/watch/${comment.videoUUID}/comments/\\d+${urlSuffix}`) - expect(comment.url).to.match(matcher) - } - } - - async function checkLocal () { - const startsWith = 'http://' + servers[0].host + '%' - // On local videos - await check(startsWith, servers[0].url, '', 'false') - // On remote videos - await check(startsWith, servers[0].url, '', 'true') - } - - async function checkRemote (suffix: string) { - const startsWith = 'http://' + servers[1].host + '%' - // On local videos - await check(startsWith, servers[1].url, suffix, 'false') - // On remote videos, we should not update URLs so no suffix - await check(startsWith, servers[1].url, '', 'true') - } - - { - const query = `UPDATE "videoComment" SET url = url || 'kyle'` - await sqlCommands[1].updateQuery(query) - - await wait(5000) - await waitJobs(servers) - } - - await checkLocal() - await checkRemote('kyle') - }) - - it('Should remove unavailable remote resources', async function () { - this.timeout(240000) - - async function expectNotDeleted () { - { - const video = await servers[0].videos.get({ id: uuid }) - - expect(video.likes).to.equal(3) - expect(video.dislikes).to.equal(0) - } - - { - const { total } = await servers[0].comments.listThreads({ videoId: uuid }) - expect(total).to.equal(3) - } - } - - async function expectDeleted () { - { - const video = await servers[0].videos.get({ id: uuid }) - - expect(video.likes).to.equal(2) - expect(video.dislikes).to.equal(0) - } - - { - const { total } = await servers[0].comments.listThreads({ videoId: uuid }) - expect(total).to.equal(2) - } - } - - const uuid = (await servers[0].videos.quickUpload({ name: 'server 1 video 2' })).uuid - - await waitJobs(servers) - - for (const server of servers) { - await server.videos.rate({ id: uuid, rating: 'like' }) - await server.comments.createThread({ videoId: uuid, text: 'comment' }) - } - - await waitJobs(servers) - - await expectNotDeleted() - - await servers[1].kill() - - await wait(5000) - await expectNotDeleted() - - let continueWhile = true - - do { - try { - await expectDeleted() - continueWhile = false - } catch { - } - } while (continueWhile) - }) - - after(async function () { - for (const sql of sqlCommands) { - await sql.cleanup() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts deleted file mode 100644 index 572a358a0..000000000 --- a/server/tests/api/activitypub/client.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { processViewersStats } from '@server/tests/shared' -import { HttpStatusCode, VideoPlaylistPrivacy, WatchActionObject } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeActivityPubGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test activitypub', function () { - let servers: PeerTubeServer[] = [] - let video: { id: number, uuid: string, shortUUID: string } - let playlist: { id: number, uuid: string, shortUUID: string } - - async function testAccount (path: string) { - const res = await makeActivityPubGetRequest(servers[0].url, path) - const object = res.body - - expect(object.type).to.equal('Person') - expect(object.id).to.equal(servers[0].url + '/accounts/root') - expect(object.name).to.equal('root') - expect(object.preferredUsername).to.equal('root') - } - - async function testChannel (path: string) { - const res = await makeActivityPubGetRequest(servers[0].url, path) - const object = res.body - - expect(object.type).to.equal('Group') - expect(object.id).to.equal(servers[0].url + '/video-channels/root_channel') - expect(object.name).to.equal('Main root channel') - expect(object.preferredUsername).to.equal('root_channel') - } - - async function testVideo (path: string) { - const res = await makeActivityPubGetRequest(servers[0].url, path) - const object = res.body - - expect(object.type).to.equal('Video') - expect(object.id).to.equal(servers[0].url + '/videos/watch/' + video.uuid) - expect(object.name).to.equal('video') - } - - async function testPlaylist (path: string) { - const res = await makeActivityPubGetRequest(servers[0].url, path) - const object = res.body - - expect(object.type).to.equal('Playlist') - expect(object.id).to.equal(servers[0].url + '/video-playlists/' + playlist.uuid) - expect(object.name).to.equal('playlist') - } - - before(async function () { - this.timeout(30000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - { - video = await servers[0].videos.quickUpload({ name: 'video' }) - } - - { - const attributes = { displayName: 'playlist', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[0].store.channel.id } - playlist = await servers[0].playlists.create({ attributes }) - } - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should return the account object', async function () { - await testAccount('/accounts/root') - await testAccount('/a/root') - }) - - it('Should return the channel object', async function () { - await testChannel('/video-channels/root_channel') - await testChannel('/c/root_channel') - }) - - it('Should return the video object', async function () { - await testVideo('/videos/watch/' + video.id) - await testVideo('/videos/watch/' + video.uuid) - await testVideo('/videos/watch/' + video.shortUUID) - await testVideo('/w/' + video.id) - await testVideo('/w/' + video.uuid) - await testVideo('/w/' + video.shortUUID) - }) - - it('Should return the playlist object', async function () { - await testPlaylist('/video-playlists/' + playlist.id) - await testPlaylist('/video-playlists/' + playlist.uuid) - await testPlaylist('/video-playlists/' + playlist.shortUUID) - await testPlaylist('/w/p/' + playlist.id) - await testPlaylist('/w/p/' + playlist.uuid) - await testPlaylist('/w/p/' + playlist.shortUUID) - await testPlaylist('/videos/watch/playlist/' + playlist.id) - await testPlaylist('/videos/watch/playlist/' + playlist.uuid) - await testPlaylist('/videos/watch/playlist/' + playlist.shortUUID) - }) - - it('Should redirect to the origin video object', async function () { - const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + video.uuid, HttpStatusCode.FOUND_302) - - expect(res.header.location).to.equal(servers[0].url + '/videos/watch/' + video.uuid) - }) - - it('Should return the watch action', async function () { - this.timeout(50000) - - await servers[0].views.simulateViewer({ id: video.uuid, currentTimes: [ 0, 2 ] }) - await processViewersStats(servers) - - const res = await makeActivityPubGetRequest(servers[0].url, '/videos/local-viewer/1', HttpStatusCode.OK_200) - - const object: WatchActionObject = res.body - expect(object.type).to.equal('WatchAction') - expect(object.duration).to.equal('PT2S') - expect(object.actionStatus).to.equal('CompletedActionStatus') - expect(object.watchSections).to.have.lengthOf(1) - expect(object.watchSections[0].startTimestamp).to.equal(0) - expect(object.watchSections[0].endTimestamp).to.equal(2) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts deleted file mode 100644 index 3899a6a49..000000000 --- a/server/tests/api/activitypub/fetch.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { SQLCommand } from '@server/tests/shared' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test ActivityPub fetcher', function () { - let servers: PeerTubeServer[] - let sqlCommandServer1: SQLCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - - const user = { username: 'user1', password: 'password' } - for (const server of servers) { - await server.users.create({ username: user.username, password: user.password }) - } - - const userAccessToken = await servers[0].login.getAccessToken(user) - - await servers[0].videos.upload({ attributes: { name: 'video root' } }) - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'bad video root' } }) - await servers[0].videos.upload({ token: userAccessToken, attributes: { name: 'video user' } }) - - sqlCommandServer1 = new SQLCommand(servers[0]) - - { - const to = servers[0].url + '/accounts/user1' - const value = servers[1].url + '/accounts/user1' - await sqlCommandServer1.setActorField(to, 'url', value) - } - - { - const value = servers[2].url + '/videos/watch/' + uuid - await sqlCommandServer1.setVideoField(uuid, 'url', value) - } - }) - - it('Should add only the video with a valid actor URL', async function () { - this.timeout(60000) - - await doubleFollow(servers[0], servers[1]) - await waitJobs(servers) - - { - const { total, data } = await servers[0].videos.list({ sort: 'createdAt' }) - - expect(total).to.equal(3) - expect(data[0].name).to.equal('video root') - expect(data[1].name).to.equal('bad video root') - expect(data[2].name).to.equal('video user') - } - - { - const { total, data } = await servers[1].videos.list({ sort: 'createdAt' }) - - expect(total).to.equal(1) - expect(data[0].name).to.equal('video root') - } - }) - - after(async function () { - this.timeout(20000) - - await sqlCommandServer1.cleanup() - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts deleted file mode 100644 index bad86ef47..000000000 --- a/server/tests/api/activitypub/helpers.ts +++ /dev/null @@ -1,167 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { cloneDeep } from 'lodash' -import { signAndContextify } from '@server/lib/activitypub/send' -import { buildRequestStub } from '@server/tests/shared' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' - -describe('Test activity pub helpers', function () { - - describe('When checking the Linked Signature', function () { - - it('Should fail with an invalid Mastodon signature', async function () { - const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create-bad-signature.json')) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey - const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } - - const result = await isJsonLDSignatureVerified(fromActor as any, body) - - expect(result).to.be.false - }) - - it('Should fail with an invalid public key', async function () { - const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create.json')) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-public-key.json')).publicKey - const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } - - const result = await isJsonLDSignatureVerified(fromActor as any, body) - - expect(result).to.be.false - }) - - it('Should succeed with a valid Mastodon signature', async function () { - const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create.json')) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey - const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } - - const result = await isJsonLDSignatureVerified(fromActor as any, body) - - expect(result).to.be.true - }) - - it('Should fail with an invalid PeerTube signature', async function () { - const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/invalid-keys.json')) - const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json')) - - const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } - const signedBody = await signAndContextify(actorSignature as any, body, 'Announce') - - const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' } - const result = await isJsonLDSignatureVerified(fromActor as any, signedBody) - - expect(result).to.be.false - }) - - it('Should succeed with a valid PeerTube signature', async function () { - const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/keys.json')) - const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json')) - - const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } - const signedBody = await signAndContextify(actorSignature as any, body, 'Announce') - - const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' } - const result = await isJsonLDSignatureVerified(fromActor as any, signedBody) - - expect(result).to.be.true - }) - }) - - describe('When checking HTTP signature', function () { - it('Should fail with an invalid http signature', async function () { - const req = buildRequestStub() - req.method = 'POST' - req.url = '/accounts/ronan/inbox' - - const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-http-signature.json'))) - req.body = mastodonObject.body - req.headers = mastodonObject.headers - - const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey - - const actor = { publicKey } - const verified = isHTTPSignatureVerified(parsed, actor as any) - - expect(verified).to.be.false - }) - - it('Should fail with an invalid public key', async function () { - const req = buildRequestStub() - req.method = 'POST' - req.url = '/accounts/ronan/inbox' - - const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json'))) - req.body = mastodonObject.body - req.headers = mastodonObject.headers - - const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-public-key.json')).publicKey - - const actor = { publicKey } - const verified = isHTTPSignatureVerified(parsed, actor as any) - - expect(verified).to.be.false - }) - - it('Should fail because of clock skew', async function () { - const req = buildRequestStub() - req.method = 'POST' - req.url = '/accounts/ronan/inbox' - - const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json'))) - req.body = mastodonObject.body - req.headers = mastodonObject.headers - - let errored = false - try { - parseHTTPSignature(req) - } catch { - errored = true - } - - expect(errored).to.be.true - }) - - it('Should with a scheme', async function () { - const req = buildRequestStub() - req.method = 'POST' - req.url = '/accounts/ronan/inbox' - - const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json'))) - req.body = mastodonObject.body - req.headers = mastodonObject.headers - req.headers = 'Signature ' + mastodonObject.headers - - let errored = false - try { - parseHTTPSignature(req, 3600 * 1000 * 365 * 10) - } catch { - errored = true - } - - expect(errored).to.be.true - }) - - it('Should succeed with a valid signature', async function () { - const req = buildRequestStub() - req.method = 'POST' - req.url = '/accounts/ronan/inbox' - - const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json'))) - req.body = mastodonObject.body - req.headers = mastodonObject.headers - - const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) - const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey - - const actor = { publicKey } - const verified = isHTTPSignatureVerified(parsed, actor as any) - - expect(verified).to.be.true - }) - - }) - -}) diff --git a/server/tests/api/activitypub/index.ts b/server/tests/api/activitypub/index.ts deleted file mode 100644 index 324b444e4..000000000 --- a/server/tests/api/activitypub/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import './cleaner' -import './client' -import './fetch' -import './refresher' -import './helpers' -import './security' diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts deleted file mode 100644 index 4ea7929ec..000000000 --- a/server/tests/api/activitypub/refresher.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { SQLCommand } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test AP refresher', function () { - let servers: PeerTubeServer[] = [] - let sqlCommandServer2: SQLCommand - let videoUUID1: string - let videoUUID2: string - let videoUUID3: string - let playlistUUID1: string - let playlistUUID2: string - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - for (const server of servers) { - await server.config.disableTranscoding() - } - - { - videoUUID1 = (await servers[1].videos.quickUpload({ name: 'video1' })).uuid - videoUUID2 = (await servers[1].videos.quickUpload({ name: 'video2' })).uuid - videoUUID3 = (await servers[1].videos.quickUpload({ name: 'video3' })).uuid - } - - { - const token1 = await servers[1].users.generateUserAndToken('user1') - await servers[1].videos.upload({ token: token1, attributes: { name: 'video4' } }) - - const token2 = await servers[1].users.generateUserAndToken('user2') - await servers[1].videos.upload({ token: token2, attributes: { name: 'video5' } }) - } - - { - const attributes = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].store.channel.id } - const created = await servers[1].playlists.create({ attributes }) - playlistUUID1 = created.uuid - } - - { - const attributes = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].store.channel.id } - const created = await servers[1].playlists.create({ attributes }) - playlistUUID2 = created.uuid - } - - await doubleFollow(servers[0], servers[1]) - - sqlCommandServer2 = new SQLCommand(servers[1]) - }) - - describe('Videos refresher', function () { - - it('Should remove a deleted remote video', async function () { - this.timeout(60000) - - await wait(10000) - - // Change UUID so the remote server returns a 404 - await sqlCommandServer2.setVideoField(videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') - - await servers[0].videos.get({ id: videoUUID1 }) - await servers[0].videos.get({ id: videoUUID2 }) - - await waitJobs(servers) - - await servers[0].videos.get({ id: videoUUID1, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await servers[0].videos.get({ id: videoUUID2 }) - }) - - it('Should not update a remote video if the remote instance is down', async function () { - this.timeout(70000) - - await killallServers([ servers[1] ]) - - await sqlCommandServer2.setVideoField(videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') - - // Video will need a refresh - await wait(10000) - - await servers[0].videos.get({ id: videoUUID3 }) - // The refresh should fail - await waitJobs([ servers[0] ]) - - await servers[1].run() - - await servers[0].videos.get({ id: videoUUID3 }) - }) - }) - - describe('Actors refresher', function () { - - it('Should remove a deleted actor', async function () { - this.timeout(60000) - - const command = servers[0].accounts - - await wait(10000) - - // Change actor name so the remote server returns a 404 - const to = servers[1].url + '/accounts/user2' - await sqlCommandServer2.setActorField(to, 'preferredUsername', 'toto') - - await command.get({ accountName: 'user1@' + servers[1].host }) - await command.get({ accountName: 'user2@' + servers[1].host }) - - await waitJobs(servers) - - await command.get({ accountName: 'user1@' + servers[1].host, expectedStatus: HttpStatusCode.OK_200 }) - await command.get({ accountName: 'user2@' + servers[1].host, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Playlist refresher', function () { - - it('Should remove a deleted playlist', async function () { - this.timeout(60000) - - await wait(10000) - - // Change UUID so the remote server returns a 404 - await sqlCommandServer2.setPlaylistField(playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') - - await servers[0].playlists.get({ playlistId: playlistUUID1 }) - await servers[0].playlists.get({ playlistId: playlistUUID2 }) - - await waitJobs(servers) - - await servers[0].playlists.get({ playlistId: playlistUUID1, expectedStatus: HttpStatusCode.OK_200 }) - await servers[0].playlists.get({ playlistId: playlistUUID2, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - after(async function () { - await sqlCommandServer2.cleanup() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts deleted file mode 100644 index 8e87361a9..000000000 --- a/server/tests/api/activitypub/security.ts +++ /dev/null @@ -1,321 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { buildDigest } from '@server/helpers/peertube-crypto' -import { ACTIVITY_PUB, HTTP_SIGNATURE } from '@server/initializers/constants' -import { activityPubContextify } from '@server/lib/activitypub/context' -import { buildGlobalHeaders, signAndContextify } from '@server/lib/activitypub/send' -import { makePOSTAPRequest, SQLCommand } from '@server/tests/shared' -import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createMultipleServers, killallServers, PeerTubeServer } from '@shared/server-commands' - -function setKeysOfServer (onServer: SQLCommand, ofServerUrl: string, publicKey: string, privateKey: string) { - const url = ofServerUrl + '/accounts/peertube' - - return Promise.all([ - onServer.setActorField(url, 'publicKey', publicKey), - onServer.setActorField(url, 'privateKey', privateKey) - ]) -} - -function setUpdatedAtOfServer (onServer: SQLCommand, ofServerUrl: string, updatedAt: string) { - const url = ofServerUrl + '/accounts/peertube' - - return Promise.all([ - onServer.setActorField(url, 'createdAt', updatedAt), - onServer.setActorField(url, 'updatedAt', updatedAt) - ]) -} - -function getAnnounceWithoutContext (server: PeerTubeServer) { - const json = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json')) - const result: typeof json = {} - - for (const key of Object.keys(json)) { - if (Array.isArray(json[key])) { - result[key] = json[key].map(v => v.replace(':9002', `:${server.port}`)) - } else { - result[key] = json[key].replace(':9002', `:${server.port}`) - } - } - - return result -} - -async function makeFollowRequest (to: { url: string }, by: { url: string, privateKey }) { - const follow = { - type: 'Follow', - id: by.url + '/' + new Date().getTime(), - actor: by.url, - object: to.url - } - - const body = await activityPubContextify(follow, 'Follow') - - const httpSignature = { - algorithm: HTTP_SIGNATURE.ALGORITHM, - authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, - keyId: by.url, - key: by.privateKey, - headers: HTTP_SIGNATURE.HEADERS_TO_SIGN_WITH_PAYLOAD - } - const headers = { - 'digest': buildDigest(body), - 'content-type': 'application/activity+json', - 'accept': ACTIVITY_PUB.ACCEPT_HEADER - } - - return makePOSTAPRequest(to.url + '/inbox', body, httpSignature, headers) -} - -describe('Test ActivityPub security', function () { - let servers: PeerTubeServer[] - let sqlCommands: SQLCommand[] = [] - - let url: string - - const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/keys.json')) - const invalidKeys = require(buildAbsoluteFixturePath('./ap-json/peertube/invalid-keys.json')) - const baseHttpSignature = () => ({ - algorithm: HTTP_SIGNATURE.ALGORITHM, - authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, - keyId: 'acct:peertube@' + servers[1].host, - key: keys.privateKey, - headers: HTTP_SIGNATURE.HEADERS_TO_SIGN_WITH_PAYLOAD - }) - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(3) - - sqlCommands = servers.map(s => new SQLCommand(s)) - - url = servers[0].url + '/inbox' - - await setKeysOfServer(sqlCommands[0], servers[1].url, keys.publicKey, null) - await setKeysOfServer(sqlCommands[1], servers[1].url, keys.publicKey, keys.privateKey) - - const to = { url: servers[0].url + '/accounts/peertube' } - const by = { url: servers[1].url + '/accounts/peertube', privateKey: keys.privateKey } - await makeFollowRequest(to, by) - }) - - describe('When checking HTTP signature', function () { - - it('Should fail with an invalid digest', async function () { - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = { - Digest: buildDigest({ hello: 'coucou' }) - } - - try { - await makePOSTAPRequest(url, body, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - - it('Should fail with an invalid date', async function () { - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' - - try { - await makePOSTAPRequest(url, body, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - - it('Should fail with bad keys', async function () { - await setKeysOfServer(sqlCommands[0], servers[1].url, invalidKeys.publicKey, invalidKeys.privateKey) - await setKeysOfServer(sqlCommands[1], servers[1].url, invalidKeys.publicKey, invalidKeys.privateKey) - - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - - try { - await makePOSTAPRequest(url, body, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - - it('Should reject requests without appropriate signed headers', async function () { - await setKeysOfServer(sqlCommands[0], servers[1].url, keys.publicKey, keys.privateKey) - await setKeysOfServer(sqlCommands[1], servers[1].url, keys.publicKey, keys.privateKey) - - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - - const signatureOptions = baseHttpSignature() - const badHeadersMatrix = [ - [ '(request-target)', 'date', 'digest' ], - [ 'host', 'date', 'digest' ], - [ '(request-target)', 'host', 'digest' ] - ] - - for (const badHeaders of badHeadersMatrix) { - signatureOptions.headers = badHeaders - - try { - await makePOSTAPRequest(url, body, signatureOptions, headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - } - }) - - it('Should succeed with a valid HTTP signature draft 11 (without date but with (created))', async function () { - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - - const signatureOptions = baseHttpSignature() - signatureOptions.headers = [ '(request-target)', '(created)', 'host', 'digest' ] - - const { statusCode } = await makePOSTAPRequest(url, body, signatureOptions, headers) - expect(statusCode).to.equal(HttpStatusCode.NO_CONTENT_204) - }) - - it('Should succeed with a valid HTTP signature', async function () { - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - - const { statusCode } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers) - expect(statusCode).to.equal(HttpStatusCode.NO_CONTENT_204) - }) - - it('Should refresh the actor keys', async function () { - this.timeout(20000) - - // Update keys of server 2 to invalid keys - // Server 1 should refresh the actor and fail - await setKeysOfServer(sqlCommands[1], servers[1].url, invalidKeys.publicKey, invalidKeys.privateKey) - await setUpdatedAtOfServer(sqlCommands[0], servers[1].url, '2015-07-17 22:00:00+00') - - // Invalid peertube actor cache - await killallServers([ servers[1] ]) - await servers[1].run() - - const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce') - const headers = buildGlobalHeaders(body) - - try { - await makePOSTAPRequest(url, body, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - console.error(err) - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - }) - - describe('When checking Linked Data Signature', function () { - before(async function () { - await setKeysOfServer(sqlCommands[0], servers[1].url, keys.publicKey, keys.privateKey) - await setKeysOfServer(sqlCommands[1], servers[1].url, keys.publicKey, keys.privateKey) - await setKeysOfServer(sqlCommands[2], servers[2].url, keys.publicKey, keys.privateKey) - - const to = { url: servers[0].url + '/accounts/peertube' } - const by = { url: servers[2].url + '/accounts/peertube', privateKey: keys.privateKey } - await makeFollowRequest(to, by) - }) - - it('Should fail with bad keys', async function () { - await setKeysOfServer(sqlCommands[0], servers[2].url, invalidKeys.publicKey, invalidKeys.privateKey) - await setKeysOfServer(sqlCommands[2], servers[2].url, invalidKeys.publicKey, invalidKeys.privateKey) - - const body = getAnnounceWithoutContext(servers[1]) - body.actor = servers[2].url + '/accounts/peertube' - - const signer: any = { privateKey: invalidKeys.privateKey, url: servers[2].url + '/accounts/peertube' } - const signedBody = await signAndContextify(signer, body, 'Announce') - - const headers = buildGlobalHeaders(signedBody) - - try { - await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - - it('Should fail with an altered body', async function () { - await setKeysOfServer(sqlCommands[0], servers[2].url, keys.publicKey, keys.privateKey) - await setKeysOfServer(sqlCommands[0], servers[2].url, keys.publicKey, keys.privateKey) - - const body = getAnnounceWithoutContext(servers[1]) - body.actor = servers[2].url + '/accounts/peertube' - - const signer: any = { privateKey: keys.privateKey, url: servers[2].url + '/accounts/peertube' } - const signedBody = await signAndContextify(signer, body, 'Announce') - - signedBody.actor = servers[2].url + '/account/peertube' - - const headers = buildGlobalHeaders(signedBody) - - try { - await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - - it('Should succeed with a valid signature', async function () { - const body = getAnnounceWithoutContext(servers[1]) - body.actor = servers[2].url + '/accounts/peertube' - - const signer: any = { privateKey: keys.privateKey, url: servers[2].url + '/accounts/peertube' } - const signedBody = await signAndContextify(signer, body, 'Announce') - - const headers = buildGlobalHeaders(signedBody) - - const { statusCode } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) - expect(statusCode).to.equal(HttpStatusCode.NO_CONTENT_204) - }) - - it('Should refresh the actor keys', async function () { - this.timeout(20000) - - // Wait refresh invalidation - await wait(10000) - - // Update keys of server 3 to invalid keys - // Server 1 should refresh the actor and fail - await setKeysOfServer(sqlCommands[2], servers[2].url, invalidKeys.publicKey, invalidKeys.privateKey) - - const body = getAnnounceWithoutContext(servers[1]) - body.actor = servers[2].url + '/accounts/peertube' - - const signer: any = { privateKey: keys.privateKey, url: servers[2].url + '/accounts/peertube' } - const signedBody = await signAndContextify(signer, body, 'Announce') - - const headers = buildGlobalHeaders(signedBody) - - try { - await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers) - expect(true, 'Did not throw').to.be.false - } catch (err) { - expect(err.statusCode).to.equal(HttpStatusCode.FORBIDDEN_403) - } - }) - }) - - after(async function () { - for (const sql of sqlCommands) { - await sql.cleanup() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/abuses.ts b/server/tests/api/check-params/abuses.ts deleted file mode 100644 index 331d3f8f7..000000000 --- a/server/tests/api/check-params/abuses.ts +++ /dev/null @@ -1,438 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { AbuseCreate, AbuseState, HttpStatusCode } from '@shared/models' -import { - AbusesCommand, - cleanupTests, - createSingleServer, - doubleFollow, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test abuses API validators', function () { - const basePath = '/api/v1/abuses/' - - let server: PeerTubeServer - - let userToken = '' - let userToken2 = '' - let abuseId: number - let messageId: number - - let command: AbusesCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - userToken = await server.users.generateUserAndToken('user_1') - userToken2 = await server.users.generateUserAndToken('user_2') - - server.store.videoCreated = await server.videos.upload() - - command = server.abuses - }) - - describe('When listing abuses for admins', function () { - const path = basePath - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a bad id filter', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 'toto' } }) - }) - - it('Should fail with a bad filter', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'toto' } }) - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'videos' } }) - }) - - it('Should fail with bad predefined reason', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { predefinedReason: 'violentOrRepulsives' } }) - }) - - it('Should fail with a bad state filter', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 'toto' } }) - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 0 } }) - }) - - it('Should fail with a bad videoIs filter', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { videoIs: 'toto' } }) - }) - - it('Should succeed with the correct params', async function () { - const query = { - id: 13, - predefinedReason: 'violentOrRepulsive', - filter: 'comment', - state: 2, - videoIs: 'deleted' - } - - await makeGetRequest({ url: server.url, path, token: server.accessToken, query, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When listing abuses for users', function () { - const path = '/api/v1/users/me/abuses' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, userToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, userToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, userToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad id filter', async function () { - await makeGetRequest({ url: server.url, path, token: userToken, query: { id: 'toto' } }) - }) - - it('Should fail with a bad state filter', async function () { - await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 'toto' } }) - await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 0 } }) - }) - - it('Should succeed with the correct params', async function () { - const query = { - id: 13, - state: 2 - } - - await makeGetRequest({ url: server.url, path, token: userToken, query, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When reporting an abuse', function () { - const path = basePath - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with a wrong video', async function () { - const fields = { video: { id: 'blabla' }, reason: 'my super reason' } - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with an unknown video', async function () { - const fields = { video: { id: 42 }, reason: 'my super reason' } - await makePostBodyRequest({ - url: server.url, - path, - token: userToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a wrong comment', async function () { - const fields = { comment: { id: 'blabla' }, reason: 'my super reason' } - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with an unknown comment', async function () { - const fields = { comment: { id: 42 }, reason: 'my super reason' } - await makePostBodyRequest({ - url: server.url, - path, - token: userToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a wrong account', async function () { - const fields = { account: { id: 'blabla' }, reason: 'my super reason' } - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with an unknown account', async function () { - const fields = { account: { id: 42 }, reason: 'my super reason' } - await makePostBodyRequest({ - url: server.url, - path, - token: userToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with not account, comment or video', async function () { - const fields = { reason: 'my super reason' } - await makePostBodyRequest({ - url: server.url, - path, - token: userToken, - fields, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a non authenticated user', async function () { - const fields = { video: { id: server.store.videoCreated.id }, reason: 'my super reason' } - - await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a reason too short', async function () { - const fields = { video: { id: server.store.videoCreated.id }, reason: 'h' } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with a too big reason', async function () { - const fields = { video: { id: server.store.videoCreated.id }, reason: 'super'.repeat(605) } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should succeed with the correct parameters (basic)', async function () { - const fields: AbuseCreate = { video: { id: server.store.videoCreated.shortUUID }, reason: 'my super reason' } - - const res = await makePostBodyRequest({ - url: server.url, - path, - token: userToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - abuseId = res.body.abuse.id - }) - - it('Should fail with a wrong predefined reason', async function () { - const fields = { video: server.store.videoCreated, reason: 'my super reason', predefinedReasons: [ 'wrongPredefinedReason' ] } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail with negative timestamps', async function () { - const fields = { video: { id: server.store.videoCreated.id, startAt: -1 }, reason: 'my super reason' } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should fail mith misordered startAt/endAt', async function () { - const fields = { video: { id: server.store.videoCreated.id, startAt: 5, endAt: 1 }, reason: 'my super reason' } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields }) - }) - - it('Should succeed with the correct parameters (advanced)', async function () { - const fields: AbuseCreate = { - video: { - id: server.store.videoCreated.id, - startAt: 1, - endAt: 5 - }, - reason: 'my super reason', - predefinedReasons: [ 'serverRules' ] - } - - await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When updating an abuse', function () { - - it('Should fail with a non authenticated user', async function () { - await command.update({ token: 'blabla', abuseId, body: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a non admin user', async function () { - await command.update({ token: userToken, abuseId, body: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad abuse id', async function () { - await command.update({ abuseId: 45, body: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a bad state', async function () { - const body = { state: 5 } - await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad moderation comment', async function () { - const body = { moderationComment: 'b'.repeat(3001) } - await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct params', async function () { - const body = { state: AbuseState.ACCEPTED } - await command.update({ abuseId, body }) - }) - }) - - describe('When creating an abuse message', function () { - const message = 'my super message' - - it('Should fail with an invalid abuse id', async function () { - await command.addMessage({ token: userToken2, abuseId: 888, message, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non authenticated user', async function () { - await command.addMessage({ token: 'fake_token', abuseId, message, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with an invalid logged in user', async function () { - await command.addMessage({ token: userToken2, abuseId, message, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with an invalid message', async function () { - await command.addMessage({ token: userToken, abuseId, message: 'a'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct params', async function () { - const res = await command.addMessage({ token: userToken, abuseId, message }) - messageId = res.body.abuseMessage.id - }) - }) - - describe('When listing abuse messages', function () { - - it('Should fail with an invalid abuse id', async function () { - await command.listMessages({ token: userToken, abuseId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non authenticated user', async function () { - await command.listMessages({ token: 'fake_token', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with an invalid logged in user', async function () { - await command.listMessages({ token: userToken2, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await command.listMessages({ token: userToken, abuseId }) - }) - }) - - describe('When deleting an abuse message', function () { - it('Should fail with an invalid abuse id', async function () { - await command.deleteMessage({ token: userToken, abuseId: 888, messageId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an invalid message id', async function () { - await command.deleteMessage({ token: userToken, abuseId, messageId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non authenticated user', async function () { - await command.deleteMessage({ token: 'fake_token', abuseId, messageId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with an invalid logged in user', async function () { - await command.deleteMessage({ token: userToken2, abuseId, messageId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await command.deleteMessage({ token: userToken, abuseId, messageId }) - }) - }) - - describe('When deleting a video abuse', function () { - - it('Should fail with a non authenticated user', async function () { - await command.delete({ token: 'blabla', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a non admin user', async function () { - await command.delete({ token: userToken, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad abuse id', async function () { - await command.delete({ abuseId: 45, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await command.delete({ abuseId }) - }) - }) - - describe('When trying to manage messages of a remote abuse', function () { - let remoteAbuseId: number - let anotherServer: PeerTubeServer - - before(async function () { - this.timeout(50000) - - anotherServer = await createSingleServer(2) - await setAccessTokensToServers([ anotherServer ]) - - await doubleFollow(anotherServer, server) - - const server2VideoId = await anotherServer.videos.getId({ uuid: server.store.videoCreated.uuid }) - await anotherServer.abuses.report({ reason: 'remote server', videoId: server2VideoId }) - - await waitJobs([ server, anotherServer ]) - - const body = await command.getAdminList({ sort: '-createdAt' }) - remoteAbuseId = body.data[0].id - }) - - it('Should fail when listing abuse messages of a remote abuse', async function () { - await command.listMessages({ abuseId: remoteAbuseId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail when creating abuse message of a remote abuse', async function () { - await command.addMessage({ abuseId: remoteAbuseId, message: 'message', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - after(async function () { - await cleanupTests([ anotherServer ]) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts deleted file mode 100644 index afc0049ff..000000000 --- a/server/tests/api/check-params/accounts.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' - -describe('Test accounts API validators', function () { - const path = '/api/v1/accounts/' - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - }) - - describe('When listing accounts', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - }) - - describe('When getting an account', function () { - - it('Should return 404 with a non existing name', async function () { - await server.accounts.get({ accountName: 'arfaze', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts deleted file mode 100644 index 169b591a3..000000000 --- a/server/tests/api/check-params/blocklist.ts +++ /dev/null @@ -1,556 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test blocklist API validators', function () { - let servers: PeerTubeServer[] - let server: PeerTubeServer - let userAccessToken: string - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - server = servers[0] - - const user = { username: 'user1', password: 'password' } - await server.users.create({ username: user.username, password: user.password }) - - userAccessToken = await server.login.getAccessToken(user) - - await doubleFollow(servers[0], servers[1]) - }) - - // --------------------------------------------------------------- - - describe('When managing user blocklist', function () { - - describe('When managing user accounts blocklist', function () { - const path = '/api/v1/users/me/blocklist/accounts' - - describe('When listing blocked accounts', function () { - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - }) - - describe('When blocking an account', function () { - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { accountName: 'user1' }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with an unknown account', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user2' }, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail to block ourselves', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'root' }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user1' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When unblocking an account', function () { - it('Should fail with an unauthenticated user', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with an unknown account block', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user2', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1', - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - }) - - describe('When managing user servers blocklist', function () { - const path = '/api/v1/users/me/blocklist/servers' - - describe('When listing blocked servers', function () { - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - }) - - describe('When blocking a server', function () { - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { host: '127.0.0.1:9002' }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with an unknown server', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: '127.0.0.1:9003' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should fail with our own server', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: server.host }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: servers[1].host }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When unblocking a server', function () { - it('Should fail with an unauthenticated user', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/' + servers[1].host, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with an unknown server block', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/127.0.0.1:9004', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/' + servers[1].host, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - }) - }) - - describe('When managing server blocklist', function () { - - describe('When managing server accounts blocklist', function () { - const path = '/api/v1/server/blocklist/accounts' - - describe('When listing blocked accounts', function () { - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makeGetRequest({ - url: server.url, - token: userAccessToken, - path, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - }) - - describe('When blocking an account', function () { - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { accountName: 'user1' }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makePostBodyRequest({ - url: server.url, - token: userAccessToken, - path, - fields: { accountName: 'user1' }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an unknown account', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user2' }, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail to block ourselves', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'root' }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user1' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When unblocking an account', function () { - it('Should fail with an unauthenticated user', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1', - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an unknown account block', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user2', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1', - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - }) - - describe('When managing server servers blocklist', function () { - const path = '/api/v1/server/blocklist/servers' - - describe('When listing blocked servers', function () { - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makeGetRequest({ - url: server.url, - token: userAccessToken, - path, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - }) - - describe('When blocking a server', function () { - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { host: servers[1].host }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makePostBodyRequest({ - url: server.url, - token: userAccessToken, - path, - fields: { host: servers[1].host }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with an unknown server', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: '127.0.0.1:9003' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should fail with our own server', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: server.host }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { host: servers[1].host }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When unblocking a server', function () { - it('Should fail with an unauthenticated user', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/' + servers[1].host, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a user without the appropriate rights', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/' + servers[1].host, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an unknown server block', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/127.0.0.1:9004', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/' + servers[1].host, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - }) - }) - - describe('When getting blocklist status', function () { - const path = '/api/v1/blocklist/status' - - it('Should fail with a bad token', async function () { - await makeGetRequest({ - url: server.url, - path, - token: 'false', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad accounts field', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - accounts: 1 - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url: server.url, - path, - query: { - accounts: [ 1 ] - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad hosts field', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - hosts: 1 - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url: server.url, - path, - query: { - hosts: [ 1 ] - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - query: {}, - expectedStatus: HttpStatusCode.OK_200 - }) - - await makeGetRequest({ - url: server.url, - path, - query: { - hosts: [ 'example.com' ], - accounts: [ 'john@example.com' ] - }, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/bulk.ts b/server/tests/api/check-params/bulk.ts deleted file mode 100644 index f03264b4f..000000000 --- a/server/tests/api/check-params/bulk.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Test bulk API validators', function () { - let server: PeerTubeServer - let userAccessToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - const user = { username: 'user1', password: 'password' } - await server.users.create({ username: user.username, password: user.password }) - - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When removing comments of', function () { - const path = '/api/v1/bulk/remove-comments-of' - - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { accountName: 'user1', scope: 'my-videos' }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with an unknown account', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user2', scope: 'my-videos' }, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an invalid scope', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user1', scope: 'my-videoss' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to delete comments of the instance without the appropriate rights', async function () { - await makePostBodyRequest({ - url: server.url, - token: userAccessToken, - path, - fields: { accountName: 'user1', scope: 'instance' }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path, - fields: { accountName: 'user1', scope: 'instance' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/channel-import-videos.ts b/server/tests/api/check-params/channel-import-videos.ts deleted file mode 100644 index 2de13b629..000000000 --- a/server/tests/api/check-params/channel-import-videos.ts +++ /dev/null @@ -1,209 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { FIXTURE_URLS } from '@server/tests/shared' -import { areHttpImportTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { - ChannelsCommand, - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test videos import in a channel API validator', function () { - let server: PeerTubeServer - const userInfo = { - accessToken: '', - channelName: 'fake_channel', - channelId: -1, - id: -1, - videoQuota: -1, - videoQuotaDaily: -1, - channelSyncId: -1 - } - let command: ChannelsCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableImports() - await server.config.enableChannelSync() - - const userCreds = { - username: 'fake', - password: 'fake_password' - } - - { - const user = await server.users.create({ username: userCreds.username, password: userCreds.password }) - userInfo.id = user.id - userInfo.accessToken = await server.login.getAccessToken(userCreds) - - const info = await server.users.getMyInfo({ token: userInfo.accessToken }) - userInfo.channelId = info.videoChannels[0].id - } - - { - const { videoChannelSync } = await server.channelSyncs.create({ - token: userInfo.accessToken, - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: userInfo.channelId - } - }) - userInfo.channelSyncId = videoChannelSync.id - } - - command = server.channels - }) - - it('Should fail when HTTP upload is disabled', async function () { - await server.config.disableChannelSync() - await server.config.disableImports() - - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: server.accessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - - await server.config.enableImports() - }) - - it('Should fail when externalChannelUrl is not provided', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: null, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail when externalChannelUrl is malformed', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: 'not-a-url', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad sync id', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelSyncId: 'toto' as any, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a unknown sync id', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelSyncId: 42, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a sync id of another channel', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelSyncId: userInfo.channelSyncId, - token: server.accessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with no authentication', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail when sync is not owned by the user', async function () { - await command.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: userInfo.accessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail when the user has no quota', async function () { - await server.users.update({ - userId: userInfo.id, - videoQuota: 0 - }) - - await command.importVideos({ - channelName: 'fake_channel', - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: userInfo.accessToken, - expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413 - }) - - await server.users.update({ - userId: userInfo.id, - videoQuota: userInfo.videoQuota - }) - }) - - it('Should fail when the user has no daily quota', async function () { - await server.users.update({ - userId: userInfo.id, - videoQuotaDaily: 0 - }) - - await command.importVideos({ - channelName: 'fake_channel', - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: userInfo.accessToken, - expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413 - }) - - await server.users.update({ - userId: userInfo.id, - videoQuotaDaily: userInfo.videoQuotaDaily - }) - }) - - it('Should succeed when sync is run by its owner', async function () { - if (!areHttpImportTestsDisabled()) return - - await command.importVideos({ - channelName: 'fake_channel', - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - token: userInfo.accessToken - }) - }) - - it('Should succeed when sync is run with root and for another user\'s channel', async function () { - if (!areHttpImportTestsDisabled()) return - - await command.importVideos({ - channelName: 'fake_channel', - externalChannelUrl: FIXTURE_URLS.youtubeChannel - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts deleted file mode 100644 index 2f523d4ce..000000000 --- a/server/tests/api/check-params/config.ts +++ /dev/null @@ -1,428 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { merge } from 'lodash' -import { omit } from '@shared/core-utils' -import { CustomConfig, HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test config API validators', function () { - const path = '/api/v1/config/custom' - let server: PeerTubeServer - let userAccessToken: string - const updateParams: CustomConfig = { - instance: { - name: 'PeerTube updated', - shortDescription: 'my short description', - description: 'my super description', - terms: 'my super terms', - codeOfConduct: 'my super coc', - - creationReason: 'my super reason', - moderationInformation: 'my super moderation information', - administrator: 'Kuja', - maintenanceLifetime: 'forever', - businessModel: 'my super business model', - hardwareInformation: '2vCore 3GB RAM', - - languages: [ 'en', 'es' ], - categories: [ 1, 2 ], - - isNSFW: true, - defaultNSFWPolicy: 'blur', - - defaultClientRoute: '/videos/recently-added', - - customizations: { - javascript: 'alert("coucou")', - css: 'body { background-color: red; }' - } - }, - theme: { - default: 'default' - }, - services: { - twitter: { - username: '@MySuperUsername', - whitelisted: true - } - }, - client: { - videos: { - miniature: { - preferAuthorDisplayName: false - } - }, - menu: { - login: { - redirectOnSingleExternalAuth: false - } - } - }, - cache: { - previews: { - size: 2 - }, - captions: { - size: 3 - }, - torrents: { - size: 4 - }, - storyboards: { - size: 5 - } - }, - signup: { - enabled: false, - limit: 5, - requiresApproval: false, - requiresEmailVerification: false, - minimumAge: 16 - }, - admin: { - email: 'superadmin1@example.com' - }, - contactForm: { - enabled: false - }, - user: { - history: { - videos: { - enabled: true - } - }, - videoQuota: 5242881, - videoQuotaDaily: 318742 - }, - videoChannels: { - maxPerUser: 20 - }, - transcoding: { - enabled: true, - remoteRunners: { - enabled: true - }, - allowAdditionalExtensions: true, - allowAudioFiles: true, - concurrency: 1, - threads: 1, - profile: 'vod_profile', - resolutions: { - '0p': false, - '144p': false, - '240p': false, - '360p': true, - '480p': true, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - alwaysTranscodeOriginalResolution: false, - webVideos: { - enabled: true - }, - hls: { - enabled: false - } - }, - live: { - enabled: true, - - allowReplay: false, - latencySetting: { - enabled: false - }, - maxDuration: 30, - maxInstanceLives: -1, - maxUserLives: 50, - - transcoding: { - enabled: true, - remoteRunners: { - enabled: true - }, - threads: 4, - profile: 'live_profile', - resolutions: { - '144p': true, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - }, - alwaysTranscodeOriginalResolution: false - } - }, - videoStudio: { - enabled: true, - remoteRunners: { - enabled: true - } - }, - videoFile: { - update: { - enabled: true - } - }, - import: { - videos: { - concurrency: 1, - http: { - enabled: false - }, - torrent: { - enabled: false - } - }, - videoChannelSynchronization: { - enabled: false, - maxPerUser: 10 - } - }, - trending: { - videos: { - algorithms: { - enabled: [ 'hot', 'most-viewed', 'most-liked' ], - default: 'most-viewed' - } - } - }, - autoBlacklist: { - videos: { - ofUsers: { - enabled: false - } - } - }, - followers: { - instance: { - enabled: false, - manualApproval: true - } - }, - followings: { - instance: { - autoFollowBack: { - enabled: true - }, - autoFollowIndex: { - enabled: true, - indexUrl: 'https://index.example.com' - } - } - }, - broadcastMessage: { - enabled: true, - dismissable: true, - message: 'super message', - level: 'warning' - }, - search: { - remoteUri: { - users: true, - anonymous: true - }, - searchIndex: { - enabled: true, - url: 'https://search.joinpeertube.org', - disableLocalSearch: true, - isDefaultSearch: true - } - } - } - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When getting the configuration', function () { - it('Should fail without token', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - describe('When updating the configuration', function () { - it('Should fail without token', async function () { - await makePutBodyRequest({ - url: server.url, - path, - fields: updateParams, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePutBodyRequest({ - url: server.url, - path, - fields: updateParams, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail if it misses a key', async function () { - const newUpdateParams = { ...updateParams, admin: omit(updateParams.admin, [ 'email' ]) } - - await makePutBodyRequest({ - url: server.url, - path, - fields: newUpdateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad default NSFW policy', async function () { - const newUpdateParams = { - ...updateParams, - - instance: { - defaultNSFWPolicy: 'hello' - } - } - - await makePutBodyRequest({ - url: server.url, - path, - fields: newUpdateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if email disabled and signup requires email verification', async function () { - // opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts - const newUpdateParams = { - ...updateParams, - - signup: { - enabled: true, - limit: 5, - requiresApproval: true, - requiresEmailVerification: true - } - } - - await makePutBodyRequest({ - url: server.url, - path, - fields: newUpdateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a disabled web videos & hls transcoding', async function () { - const newUpdateParams = { - ...updateParams, - - transcoding: { - hls: { - enabled: false - }, - web_videos: { - enabled: false - } - } - } - - await makePutBodyRequest({ - url: server.url, - path, - fields: newUpdateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a disabled http upload & enabled sync', async function () { - const newUpdateParams: CustomConfig = merge({}, updateParams, { - import: { - videos: { - http: { enabled: false } - }, - videoChannelSynchronization: { enabled: true } - } - }) - - await makePutBodyRequest({ - url: server.url, - path, - fields: newUpdateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePutBodyRequest({ - url: server.url, - path, - fields: updateParams, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When deleting the configuration', function () { - it('Should fail without token', async function () { - await makeDeleteRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeDeleteRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts deleted file mode 100644 index f0f8819b9..000000000 --- a/server/tests/api/check-params/contact-form.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { MockSmtpServer } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - ContactFormCommand, - createSingleServer, - killallServers, - PeerTubeServer -} from '@shared/server-commands' - -describe('Test contact form API validators', function () { - let server: PeerTubeServer - const emails: object[] = [] - const defaultBody = { - fromName: 'super name', - fromEmail: 'toto@example.com', - subject: 'my subject', - body: 'Hello, how are you?' - } - let emailPort: number - let command: ContactFormCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(60000) - - emailPort = await MockSmtpServer.Instance.collectEmails(emails) - - // Email is disabled - server = await createSingleServer(1) - command = server.contactForm - }) - - it('Should not accept a contact form if emails are disabled', async function () { - await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should not accept a contact form if it is disabled in the configuration', async function () { - this.timeout(25000) - - await killallServers([ server ]) - - // Contact form is disabled - await server.run({ ...ConfigCommand.getEmailOverrideConfig(emailPort), contact_form: { enabled: false } }) - await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should not accept a contact form if from email is invalid', async function () { - this.timeout(25000) - - await killallServers([ server ]) - - // Email & contact form enabled - await server.run(ConfigCommand.getEmailOverrideConfig(emailPort)) - - await command.send({ ...defaultBody, fromEmail: 'badEmail', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, fromEmail: 'badEmail@', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, fromEmail: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not accept a contact form if from name is invalid', async function () { - await command.send({ ...defaultBody, fromName: 'name'.repeat(100), expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, fromName: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, fromName: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not accept a contact form if body is invalid', async function () { - await command.send({ ...defaultBody, body: 'body'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, body: 'a', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.send({ ...defaultBody, body: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should accept a contact form with the correct parameters', async function () { - await command.send(defaultBody) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/custom-pages.ts b/server/tests/api/check-params/custom-pages.ts deleted file mode 100644 index 63e3da3d5..000000000 --- a/server/tests/api/check-params/custom-pages.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test custom pages validators', function () { - const path = '/api/v1/custom-pages/homepage/instance' - - let server: PeerTubeServer - let userAccessToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - const user = { username: 'user1', password: 'password' } - await server.users.create({ username: user.username, password: user.password }) - - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When updating instance homepage', function () { - - it('Should fail with an unauthenticated user', async function () { - await makePutBodyRequest({ - url: server.url, - path, - fields: { content: 'super content' }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: userAccessToken, - fields: { content: 'super content' }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { content: 'super content' }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When getting instance homapage', function () { - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts deleted file mode 100644 index d7b68f163..000000000 --- a/server/tests/api/check-params/debug.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Test debug API validators', function () { - const path = '/api/v1/server/debug' - let server: PeerTubeServer - let userAccessToken = '' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'my super password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When getting debug endpoint', function () { - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { startDate: new Date().toISOString() }, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts deleted file mode 100644 index 3c911dcee..000000000 --- a/server/tests/api/check-params/follows.ts +++ /dev/null @@ -1,369 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test server follows API validators', function () { - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - }) - - describe('When managing following', function () { - let userAccessToken = null - - before(async function () { - userAccessToken = await server.users.generateUserAndToken('user1') - }) - - describe('When adding follows', function () { - const path = '/api/v1/server/following' - - it('Should fail with nothing', async function () { - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if hosts is not composed by hosts', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { hosts: [ '127.0.0.1:9002', '127.0.0.1:coucou' ] }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if hosts is composed with http schemes', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { hosts: [ '127.0.0.1:9002', 'http://127.0.0.1:9003' ] }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if hosts are not unique', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { urls: [ '127.0.0.1:9002', '127.0.0.1:9002' ] }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if handles is not composed by handles', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { handles: [ 'hello@example.com', '127.0.0.1:9001' ] }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if handles are not unique', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { urls: [ 'hello@example.com', 'hello@example.com' ] }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an invalid token', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { hosts: [ '127.0.0.1:9002' ] }, - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { hosts: [ '127.0.0.1:9002' ] }, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - describe('When listing followings', function () { - const path = '/api/v1/server/following' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path) - }) - - it('Should fail with an incorrect state', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - state: 'blabla' - } - }) - }) - - it('Should fail with an incorrect actor type', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - actorType: 'blabla' - } - }) - }) - - it('Should fail succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.OK_200, - query: { - state: 'accepted', - actorType: 'Application' - } - }) - }) - }) - - describe('When listing followers', function () { - const path = '/api/v1/server/followers' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path) - }) - - it('Should fail with an incorrect actor type', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - actorType: 'blabla' - } - }) - }) - - it('Should fail with an incorrect state', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - state: 'blabla', - actorType: 'Application' - } - }) - }) - - it('Should fail succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.OK_200, - query: { - state: 'accepted' - } - }) - }) - }) - - describe('When removing a follower', function () { - const path = '/api/v1/server/followers' - - it('Should fail with an invalid token', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002', - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002', - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid follower', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/toto', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown follower', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9003', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - }) - - describe('When accepting a follower', function () { - const path = '/api/v1/server/followers' - - it('Should fail with an invalid token', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002/accept', - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002/accept', - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid follower', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto/accept', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown follower', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9003/accept', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - }) - - describe('When rejecting a follower', function () { - const path = '/api/v1/server/followers' - - it('Should fail with an invalid token', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002/reject', - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9002/reject', - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid follower', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto/reject', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown follower', async function () { - await makePostBodyRequest({ - url: server.url, - path: path + '/toto@127.0.0.1:9003/reject', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - }) - - describe('When removing following', function () { - const path = '/api/v1/server/following' - - it('Should fail with an invalid token', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/127.0.0.1:9002', - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/127.0.0.1:9002', - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail if we do not follow this server', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/example.com', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts deleted file mode 100644 index c2a7ccd78..000000000 --- a/server/tests/api/check-params/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import './abuses' -import './accounts' -import './blocklist' -import './bulk' -import './channel-import-videos' -import './config' -import './contact-form' -import './custom-pages' -import './debug' -import './follows' -import './jobs' -import './live' -import './logs' -import './metrics' -import './my-user' -import './plugins' -import './redundancy' -import './registrations' -import './runners' -import './search' -import './services' -import './transcoding' -import './two-factor' -import './upload-quota' -import './user-notifications' -import './user-subscriptions' -import './users-admin' -import './users-emails' -import './video-blacklist' -import './video-captions' -import './video-channel-syncs' -import './video-channels' -import './video-comments' -import './video-files' -import './video-imports' -import './video-playlists' -import './video-storyboards' -import './video-source' -import './video-studio' -import './video-token' -import './videos-common-filters' -import './videos-history' -import './videos-overviews' -import './videos' -import './views' diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts deleted file mode 100644 index 873da3955..000000000 --- a/server/tests/api/check-params/jobs.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test jobs API validators', function () { - const path = '/api/v1/jobs/failed' - let server: PeerTubeServer - let userAccessToken = '' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'my super password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When listing jobs', function () { - - it('Should fail with a bad state', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path: path + 'ade' - }) - }) - - it('Should fail with an incorrect job type', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { - jobType: 'toto' - } - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - describe('When pausing/resuming the job queue', async function () { - const commands = [ 'pause', 'resume' ] - - it('Should fail with a non authenticated user', async function () { - for (const command of commands) { - await makePostBodyRequest({ - url: server.url, - path: '/api/v1/jobs/' + command, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - } - }) - - it('Should fail with a non admin user', async function () { - for (const command of commands) { - await makePostBodyRequest({ - url: server.url, - path: '/api/v1/jobs/' + command, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - } - }) - - it('Should succeed with the correct params', async function () { - for (const command of commands) { - await makePostBodyRequest({ - url: server.url, - path: '/api/v1/jobs/' + command, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts deleted file mode 100644 index 5021db516..000000000 --- a/server/tests/api/check-params/live.ts +++ /dev/null @@ -1,589 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { buildAbsoluteFixturePath, omit } from '@shared/core-utils' -import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - LiveCommand, - makePostBodyRequest, - makeUploadRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - stopFfmpeg -} from '@shared/server-commands' - -describe('Test video lives API validator', function () { - const path = '/api/v1/videos/live' - let server: PeerTubeServer - let userAccessToken = '' - let channelId: number - let video: VideoCreateResult - let videoIdNotLive: number - let command: LiveCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - latencySetting: { - enabled: false - }, - maxInstanceLives: 20, - maxUserLives: 20, - allowReplay: true - } - } - }) - - const username = 'user1' - const password = 'my super password' - await server.users.create({ username, password }) - userAccessToken = await server.login.getAccessToken({ username, password }) - - { - const { videoChannels } = await server.users.getMyInfo() - channelId = videoChannels[0].id - } - - { - videoIdNotLive = (await server.videos.quickUpload({ name: 'not live' })).id - } - - command = server.live - }) - - describe('When creating a live', function () { - let baseCorrectParams - - before(function () { - baseCorrectParams = { - name: 'my super name', - category: 5, - licence: 1, - language: 'pt', - nsfw: false, - commentsEnabled: true, - downloadEnabled: true, - waitTranscoding: true, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag1', 'tag2' ], - privacy: VideoPrivacy.PUBLIC, - channelId, - saveReplay: false, - replaySettings: undefined, - permanentLive: false, - latencyMode: LiveVideoLatencyMode.DEFAULT - } - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad category', async function () { - const fields = { ...baseCorrectParams, category: 125 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad licence', async function () { - const fields = { ...baseCorrectParams, licence: 125 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad language', async function () { - const fields = { ...baseCorrectParams, language: 'a'.repeat(15) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail without a channel', async function () { - const fields = omit(baseCorrectParams, [ 'channelId' ]) - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad channel', async function () { - const fields = { ...baseCorrectParams, channelId: 545454 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad privacy for replay settings', async function () { - const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: 999 } } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with another user channel', async function () { - const user = { - username: 'fake', - password: 'fake_password' - } - await server.users.create({ username: user.username, password: user.password }) - - const accessTokenUser = await server.login.getAccessToken(user) - const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser }) - const customChannelId = videoChannels[0].id - - const fields = { ...baseCorrectParams, channelId: customChannelId } - - await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields }) - }) - - it('Should fail with too many tags', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too low', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too big', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: buildAbsoluteFixturePath('video_short.mp4') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with a big thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with an incorrect preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: buildAbsoluteFixturePath('video_short.mp4') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with a big preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: buildAbsoluteFixturePath('custom-preview-big.png') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with bad latency setting', async function () { - const fields = { ...baseCorrectParams, latencyMode: 42 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail to set latency if the server does not allow it', async function () { - const fields = { ...baseCorrectParams, latencyMode: LiveVideoLatencyMode.HIGH_LATENCY } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct parameters', async function () { - this.timeout(30000) - - const res = await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.OK_200 - }) - - video = res.body.video - }) - - it('Should forbid if live is disabled', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: false - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should forbid to save replay if not enabled by the admin', async function () { - const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } } - - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: false - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should allow to save replay if enabled by the admin', async function () { - const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } } - - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should not allow live if max instance lives is reached', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - maxInstanceLives: 1 - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should not allow live if max user lives is reached', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - maxInstanceLives: 20, - maxUserLives: 1 - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - describe('When getting live information', function () { - - it('Should fail with a bad access token', async function () { - await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not display private information without access token', async function () { - const live = await command.get({ token: '', videoId: video.id }) - - expect(live.rtmpUrl).to.not.exist - expect(live.streamKey).to.not.exist - expect(live.latencyMode).to.exist - }) - - it('Should not display private information with token of another user', async function () { - const live = await command.get({ token: userAccessToken, videoId: video.id }) - - expect(live.rtmpUrl).to.not.exist - expect(live.streamKey).to.not.exist - expect(live.latencyMode).to.exist - }) - - it('Should display private information with appropriate token', async function () { - const live = await command.get({ videoId: video.id }) - - expect(live.rtmpUrl).to.exist - expect(live.streamKey).to.exist - expect(live.latencyMode).to.exist - }) - - it('Should fail with a bad video id', async function () { - await command.get({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown video id', async function () { - await command.get({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non live video', async function () { - await command.get({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await command.get({ videoId: video.id }) - await command.get({ videoId: video.uuid }) - await command.get({ videoId: video.shortUUID }) - }) - }) - - describe('When getting live sessions', function () { - - it('Should fail with a bad access token', async function () { - await command.listSessions({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without token', async function () { - await command.listSessions({ token: null, videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with the token of another user', async function () { - await command.listSessions({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad video id', async function () { - await command.listSessions({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown video id', async function () { - await command.listSessions({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non live video', async function () { - await command.listSessions({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await command.listSessions({ videoId: video.id }) - }) - }) - - describe('When getting live session of a replay', function () { - - it('Should fail with a bad video id', async function () { - await command.getReplaySession({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown video id', async function () { - await command.getReplaySession({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non replay video', async function () { - await command.getReplaySession({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('When updating live information', async function () { - - it('Should fail without access token', async function () { - await command.update({ token: '', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a bad access token', async function () { - await command.update({ token: 'toto', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with access token of another user', async function () { - await command.update({ token: userAccessToken, videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad video id', async function () { - await command.update({ videoId: 'toto', fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown video id', async function () { - await command.update({ videoId: 454555, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a non live video', async function () { - await command.update({ videoId: videoIdNotLive, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with bad latency setting', async function () { - const fields = { latencyMode: 42 } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad privacy for replay settings', async function () { - const fields = { saveReplay: true, replaySettings: { privacy: 999 } } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with save replay enabled but without replay settings', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true - } - } - }) - - const fields = { saveReplay: true } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with save replay disabled and replay settings', async function () { - const fields = { saveReplay: false, replaySettings: { privacy: VideoPrivacy.INTERNAL } } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with only replay settings when save replay is disabled', async function () { - const fields = { replaySettings: { privacy: VideoPrivacy.INTERNAL } } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail to set latency if the server does not allow it', async function () { - const fields = { latencyMode: LiveVideoLatencyMode.HIGH_LATENCY } - - await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await command.update({ videoId: video.id, fields: { saveReplay: false } }) - await command.update({ videoId: video.uuid, fields: { saveReplay: false } }) - await command.update({ videoId: video.shortUUID, fields: { saveReplay: false } }) - - await command.update({ videoId: video.id, fields: { saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } } }) - - }) - - it('Should fail to update replay status if replay is not allowed on the instance', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: false - } - } - }) - - await command.update({ videoId: video.id, fields: { saveReplay: true }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail to update a live if it has already started', async function () { - this.timeout(40000) - - const live = await command.get({ videoId: video.id }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - - await command.waitUntilPublished({ videoId: video.id }) - await command.update({ videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should fail to change live privacy if it has already started', async function () { - this.timeout(40000) - - const live = await command.get({ videoId: video.id }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - - await command.waitUntilPublished({ videoId: video.id }) - - await server.videos.update({ - id: video.id, - attributes: { privacy: VideoPrivacy.PUBLIC } // Same privacy, it's fine - }) - - await server.videos.update({ - id: video.id, - attributes: { privacy: VideoPrivacy.UNLISTED }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should fail to stream twice in the save live', async function () { - this.timeout(40000) - - const live = await command.get({ videoId: video.id }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - - await command.waitUntilPublished({ videoId: video.id }) - - await command.runAndTestStreamError({ videoId: video.id, shouldHaveError: true }) - - await stopFfmpeg(ffmpegCommand) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts deleted file mode 100644 index 2496cee31..000000000 --- a/server/tests/api/check-params/logs.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test logs API validators', function () { - const path = '/api/v1/server/logs' - let server: PeerTubeServer - let userAccessToken = '' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'my super password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When getting logs', function () { - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a missing startDate query', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad startDate query', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { startDate: 'toto' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad endDate query', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { startDate: new Date().toISOString(), endDate: 'toto' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad level parameter', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { startDate: new Date().toISOString(), level: 'toto' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { startDate: new Date().toISOString() }, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When creating client logs', function () { - const base = { - level: 'warn' as 'warn', - message: 'my super message', - url: 'https://example.com/toto' - } - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - it('Should fail with an invalid level', async function () { - await server.logs.createLogClient({ payload: { ...base, level: '' as any }, expectedStatus }) - await server.logs.createLogClient({ payload: { ...base, level: undefined }, expectedStatus }) - await server.logs.createLogClient({ payload: { ...base, level: 'toto' as any }, expectedStatus }) - }) - - it('Should fail with an invalid message', async function () { - await server.logs.createLogClient({ payload: { ...base, message: undefined }, expectedStatus }) - await server.logs.createLogClient({ payload: { ...base, message: '' }, expectedStatus }) - await server.logs.createLogClient({ payload: { ...base, message: 'm'.repeat(2500) }, expectedStatus }) - }) - - it('Should fail with an invalid url', async function () { - await server.logs.createLogClient({ payload: { ...base, url: undefined }, expectedStatus }) - await server.logs.createLogClient({ payload: { ...base, url: 'toto' }, expectedStatus }) - }) - - it('Should fail with an invalid stackTrace', async function () { - await server.logs.createLogClient({ payload: { ...base, stackTrace: 's'.repeat(20000) }, expectedStatus }) - }) - - it('Should fail with an invalid userAgent', async function () { - await server.logs.createLogClient({ payload: { ...base, userAgent: 's'.repeat(500) }, expectedStatus }) - }) - - it('Should fail with an invalid meta', async function () { - await server.logs.createLogClient({ payload: { ...base, meta: 's'.repeat(10000) }, expectedStatus }) - }) - - it('Should succeed with the correct params', async function () { - await server.logs.createLogClient({ payload: { ...base, stackTrace: 'stackTrace', meta: '{toto}', userAgent: 'userAgent' } }) - }) - - it('Should rate limit log creation', async function () { - let fail = false - - for (let i = 0; i < 10; i++) { - try { - await server.logs.createLogClient({ token: null, payload: base }) - } catch { - fail = true - } - } - - expect(fail).to.be.true - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/metrics.ts b/server/tests/api/check-params/metrics.ts deleted file mode 100644 index 302bef4f5..000000000 --- a/server/tests/api/check-params/metrics.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { omit } from '@shared/core-utils' -import { HttpStatusCode, PlaybackMetricCreate, VideoResolution } from '@shared/models' -import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test metrics API validators', function () { - let server: PeerTubeServer - let videoUUID: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1, { - open_telemetry: { - metrics: { - enabled: true - } - } - }) - - await setAccessTokensToServers([ server ]) - - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - videoUUID = uuid - }) - - describe('When adding playback metrics', function () { - const path = '/api/v1/metrics/playback' - let baseParams: PlaybackMetricCreate - - before(function () { - baseParams = { - playerMode: 'p2p-media-loader', - resolution: VideoResolution.H_1080P, - fps: 30, - resolutionChanges: 1, - errors: 2, - p2pEnabled: true, - downloadedBytesP2P: 0, - downloadedBytesHTTP: 0, - uploadedBytesP2P: 0, - videoId: videoUUID - } - }) - - it('Should fail with an invalid resolution', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, resolution: 'toto' } - }) - }) - - it('Should fail with an invalid fps', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, fps: 'toto' } - }) - }) - - it('Should fail with a missing/invalid player mode', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'playerMode' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, playerMode: 'toto' } - }) - }) - - it('Should fail with an missing/invalid resolution changes', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'resolutionChanges' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, resolutionChanges: 'toto' } - }) - }) - - it('Should fail with an missing/invalid errors', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'errors' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, errors: 'toto' } - }) - }) - - it('Should fail with an missing/invalid downloadedBytesP2P', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'downloadedBytesP2P' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, downloadedBytesP2P: 'toto' } - }) - }) - - it('Should fail with an missing/invalid downloadedBytesHTTP', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'downloadedBytesHTTP' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, downloadedBytesHTTP: 'toto' } - }) - }) - - it('Should fail with an missing/invalid uploadedBytesP2P', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'uploadedBytesP2P' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, uploadedBytesP2P: 'toto' } - }) - }) - - it('Should fail with a missing/invalid p2pEnabled', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: omit(baseParams, [ 'p2pEnabled' ]) - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, p2pEnabled: 'toto' } - }) - }) - - it('Should fail with an invalid totalPeers', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, p2pPeers: 'toto' } - }) - }) - - it('Should fail with a bad video id', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, videoId: 'toto' } - }) - }) - - it('Should fail with an unknown video', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, videoId: 42 }, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: baseParams, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { ...baseParams, p2pEnabled: false, totalPeers: 32 }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/my-user.ts b/server/tests/api/check-params/my-user.ts deleted file mode 100644 index 18f32d46b..000000000 --- a/server/tests/api/check-params/my-user.ts +++ /dev/null @@ -1,491 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { HttpStatusCode, UserRole, VideoCreateResult } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePutBodyRequest, - makeUploadRequest, - PeerTubeServer, - setAccessTokensToServers, - UsersCommand -} from '@shared/server-commands' - -describe('Test my user API validators', function () { - const path = '/api/v1/users/' - let userId: number - let rootId: number - let moderatorId: number - let video: VideoCreateResult - let server: PeerTubeServer - let userToken = '' - let moderatorToken = '' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - { - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - } - - { - const result = await server.users.generate('user1') - userToken = result.token - userId = result.userId - } - - { - const result = await server.users.generate('moderator1', UserRole.MODERATOR) - moderatorToken = result.token - } - - { - const result = await server.users.generate('moderator2', UserRole.MODERATOR) - moderatorId = result.userId - } - - { - video = await server.videos.upload() - } - }) - - describe('When updating my account', function () { - - it('Should fail with an invalid email attribute', async function () { - const fields = { - email: 'blabla' - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: server.accessToken, fields }) - }) - - it('Should fail with a too small password', async function () { - const fields = { - currentPassword: 'password', - password: 'bla' - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with a too long password', async function () { - const fields = { - currentPassword: 'password', - password: 'super'.repeat(61) - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail without the current password', async function () { - const fields = { - currentPassword: 'password', - password: 'super'.repeat(61) - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an invalid current password', async function () { - const fields = { - currentPassword: 'my super password fail', - password: 'super'.repeat(61) - } - - await makePutBodyRequest({ - url: server.url, - path: path + 'me', - token: userToken, - fields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with an invalid NSFW policy attribute', async function () { - const fields = { - nsfwPolicy: 'hello' - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an invalid autoPlayVideo attribute', async function () { - const fields = { - autoPlayVideo: -1 - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an invalid autoPlayNextVideo attribute', async function () { - const fields = { - autoPlayNextVideo: -1 - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an invalid videosHistoryEnabled attribute', async function () { - const fields = { - videosHistoryEnabled: -1 - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an non authenticated user', async function () { - const fields = { - currentPassword: 'password', - password: 'my super password' - } - - await makePutBodyRequest({ - url: server.url, - path: path + 'me', - token: 'super token', - fields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a too long description', async function () { - const fields = { - description: 'super'.repeat(201) - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an invalid videoLanguages attribute', async function () { - { - const fields = { - videoLanguages: 'toto' - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - } - - { - const languages = [] - for (let i = 0; i < 1000; i++) { - languages.push('fr') - } - - const fields = { - videoLanguages: languages - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - } - }) - - it('Should fail with an invalid theme', async function () { - const fields = { theme: 'invalid' } - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with an unknown theme', async function () { - const fields = { theme: 'peertube-theme-unknown' } - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - }) - - it('Should fail with invalid no modal attributes', async function () { - const keys = [ - 'noInstanceConfigWarningModal', - 'noAccountSetupWarningModal', - 'noWelcomeModal' - ] - - for (const key of keys) { - const fields = { - [key]: -1 - } - - await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields }) - } - }) - - it('Should succeed to change password with the correct params', async function () { - const fields = { - currentPassword: 'password', - password: 'my super password', - nsfwPolicy: 'blur', - autoPlayVideo: false, - email: 'super_email@example.com', - theme: 'default', - noInstanceConfigWarningModal: true, - noWelcomeModal: true, - noAccountSetupWarningModal: true - } - - await makePutBodyRequest({ - url: server.url, - path: path + 'me', - token: userToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should succeed without password change with the correct params', async function () { - const fields = { - nsfwPolicy: 'blur', - autoPlayVideo: false - } - - await makePutBodyRequest({ - url: server.url, - path: path + 'me', - token: userToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When updating my avatar', function () { - it('Should fail without an incorrect input file', async function () { - const fields = {} - const attaches = { - avatarfile: buildAbsoluteFixturePath('video_short.mp4') - } - await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) - }) - - it('Should fail with a big file', async function () { - const fields = {} - const attaches = { - avatarfile: buildAbsoluteFixturePath('avatar-big.png') - } - await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) - }) - - it('Should fail with an unauthenticated user', async function () { - const fields = {} - const attaches = { - avatarfile: buildAbsoluteFixturePath('avatar.png') - } - await makeUploadRequest({ - url: server.url, - path: path + '/me/avatar/pick', - fields, - attaches, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct params', async function () { - const fields = {} - const attaches = { - avatarfile: buildAbsoluteFixturePath('avatar.png') - } - await makeUploadRequest({ - url: server.url, - path: path + '/me/avatar/pick', - token: server.accessToken, - fields, - attaches, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When managing my scoped tokens', function () { - - it('Should fail to get my scoped tokens with an non authenticated user', async function () { - await server.users.getMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail to get my scoped tokens with a bad token', async function () { - await server.users.getMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - - }) - - it('Should succeed to get my scoped tokens', async function () { - await server.users.getMyScopedTokens() - }) - - it('Should fail to renew my scoped tokens with an non authenticated user', async function () { - await server.users.renewMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail to renew my scoped tokens with a bad token', async function () { - await server.users.renewMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should succeed to renew my scoped tokens', async function () { - await server.users.renewMyScopedTokens() - }) - }) - - describe('When getting my information', function () { - it('Should fail with a non authenticated user', async function () { - await server.users.getMyInfo({ token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should success with the correct parameters', async function () { - await server.users.getMyInfo({ token: userToken }) - }) - }) - - describe('When getting my video rating', function () { - let command: UsersCommand - - before(function () { - command = server.users - }) - - it('Should fail with a non authenticated user', async function () { - await command.getMyRating({ token: 'fake_token', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with an incorrect video uuid', async function () { - await command.getMyRating({ videoId: 'blabla', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown video', async function () { - await command.getMyRating({ videoId: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct parameters', async function () { - await command.getMyRating({ videoId: video.id }) - await command.getMyRating({ videoId: video.uuid }) - await command.getMyRating({ videoId: video.shortUUID }) - }) - }) - - describe('When retrieving my global ratings', function () { - const path = '/api/v1/accounts/user1/ratings' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, userToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, userToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, userToken) - }) - - it('Should fail with a unauthenticated user', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a another user', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad type', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userToken, - query: { rating: 'toto ' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When getting my global followers', function () { - const path = '/api/v1/accounts/user1/followers' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, userToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, userToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, userToken) - }) - - it('Should fail with a unauthenticated user', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a another user', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When blocking/unblocking/removing user', function () { - - it('Should fail with an incorrect id', async function () { - const options = { userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - - await server.users.remove(options) - await server.users.banUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.users.unbanUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with the root user', async function () { - const options = { userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - - await server.users.remove(options) - await server.users.banUser(options) - await server.users.unbanUser(options) - }) - - it('Should return 404 with a non existing id', async function () { - const options = { userId: 4545454, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await server.users.remove(options) - await server.users.banUser(options) - await server.users.unbanUser(options) - }) - - it('Should fail with a non admin user', async function () { - const options = { userId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 } - - await server.users.remove(options) - await server.users.banUser(options) - await server.users.unbanUser(options) - }) - - it('Should fail on a moderator with a moderator', async function () { - const options = { userId: moderatorId, token: moderatorToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 } - - await server.users.remove(options) - await server.users.banUser(options) - await server.users.unbanUser(options) - }) - - it('Should succeed on a user with a moderator', async function () { - const options = { userId, token: moderatorToken } - - await server.users.banUser(options) - await server.users.unbanUser(options) - }) - }) - - describe('When deleting our account', function () { - - it('Should fail with with the root account', async function () { - await server.users.deleteMe({ expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts deleted file mode 100644 index e08cd7ab8..000000000 --- a/server/tests/api/check-params/plugins.ts +++ /dev/null @@ -1,490 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode, PeerTubePlugin, PluginType } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test server plugins API validators', function () { - let server: PeerTubeServer - let userAccessToken = null - - const npmPlugin = 'peertube-plugin-hello-world' - const pluginName = 'hello-world' - let npmVersion: string - - const themePlugin = 'peertube-theme-background-red' - const themeName = 'background-red' - let themeVersion: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(60000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'password' - } - - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - - { - const res = await server.plugins.install({ npmName: npmPlugin }) - const plugin = res.body as PeerTubePlugin - npmVersion = plugin.version - } - - { - const res = await server.plugins.install({ npmName: themePlugin }) - const plugin = res.body as PeerTubePlugin - themeVersion = plugin.version - } - }) - - describe('With static plugin routes', function () { - it('Should fail with an unknown plugin name/plugin version', async function () { - const paths = [ - '/plugins/' + pluginName + '/0.0.1/auth/fake-auth', - '/plugins/' + pluginName + '/0.0.1/static/images/chocobo.png', - '/plugins/' + pluginName + '/0.0.1/client-scripts/client/common-client-plugin.js', - '/themes/' + themeName + '/0.0.1/static/images/chocobo.png', - '/themes/' + themeName + '/0.0.1/client-scripts/client/video-watch-client-plugin.js', - '/themes/' + themeName + '/0.0.1/css/assets/style1.css' - ] - - for (const p of paths) { - await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - - it('Should fail when requesting a plugin in the theme path', async function () { - await makeGetRequest({ - url: server.url, - path: '/themes/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with invalid versions', async function () { - const paths = [ - '/plugins/' + pluginName + '/0.0.1.1/auth/fake-auth', - '/plugins/' + pluginName + '/0.0.1.1/static/images/chocobo.png', - '/plugins/' + pluginName + '/0.1/client-scripts/client/common-client-plugin.js', - '/themes/' + themeName + '/1/static/images/chocobo.png', - '/themes/' + themeName + '/0.0.1000a/client-scripts/client/video-watch-client-plugin.js', - '/themes/' + themeName + '/0.a.1/css/assets/style1.css' - ] - - for (const p of paths) { - await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - }) - - it('Should fail with invalid paths', async function () { - const paths = [ - '/plugins/' + pluginName + '/' + npmVersion + '/static/images/../chocobo.png', - '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/../client/common-client-plugin.js', - '/themes/' + themeName + '/' + themeVersion + '/static/../images/chocobo.png', - '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js/..', - '/themes/' + themeName + '/' + themeVersion + '/css/../assets/style1.css' - ] - - for (const p of paths) { - await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - }) - - it('Should fail with an unknown auth name', async function () { - const path = '/plugins/' + pluginName + '/' + npmVersion + '/auth/bad-auth' - - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an unknown static file', async function () { - const paths = [ - '/plugins/' + pluginName + '/' + npmVersion + '/static/fake/chocobo.png', - '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/fake.js', - '/themes/' + themeName + '/' + themeVersion + '/static/fake/chocobo.png', - '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/fake.js' - ] - - for (const p of paths) { - await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - - it('Should fail with an unknown CSS file', async function () { - await makeGetRequest({ - url: server.url, - path: '/themes/' + themeName + '/' + themeVersion + '/css/assets/fake.css', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - const paths = [ - '/plugins/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png', - '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/common-client-plugin.js', - '/themes/' + themeName + '/' + themeVersion + '/static/images/chocobo.png', - '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js', - '/themes/' + themeName + '/' + themeVersion + '/css/assets/style1.css' - ] - - for (const p of paths) { - await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.OK_200 }) - } - - const authPath = '/plugins/' + pluginName + '/' + npmVersion + '/auth/fake-auth' - await makeGetRequest({ url: server.url, path: authPath, expectedStatus: HttpStatusCode.FOUND_302 }) - }) - }) - - describe('When listing available plugins/themes', function () { - const path = '/api/v1/plugins/available' - const baseQuery = { - search: 'super search', - pluginType: PluginType.PLUGIN, - currentPeerTubeEngine: '1.2.3' - } - - it('Should fail with an invalid token', async function () { - await makeGetRequest({ - url: server.url, - path, - token: 'fake_token', - query: baseQuery, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - query: baseQuery, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an invalid plugin type', async function () { - const query = { ...baseQuery, pluginType: 5 } - - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query - }) - }) - - it('Should fail with an invalid current peertube engine', async function () { - const query = { ...baseQuery, currentPeerTubeEngine: '1.0' } - - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: baseQuery, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When listing local plugins/themes', function () { - const path = '/api/v1/plugins' - const baseQuery = { - pluginType: PluginType.THEME - } - - it('Should fail with an invalid token', async function () { - await makeGetRequest({ - url: server.url, - path, - token: 'fake_token', - query: baseQuery, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - query: baseQuery, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an invalid plugin type', async function () { - const query = { ...baseQuery, pluginType: 5 } - - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: baseQuery, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When getting a plugin or the registered settings or public settings', function () { - const path = '/api/v1/plugins/' - - it('Should fail with an invalid token', async function () { - for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - } - }) - - it('Should fail if the user is not an administrator', async function () { - for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - }) - - it('Should fail with an invalid npm name', async function () { - for (const suffix of [ 'toto', 'toto/registered-settings', 'toto/public-settings' ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - - for (const suffix of [ 'peertube-plugin-TOTO', 'peertube-plugin-TOTO/registered-settings', 'peertube-plugin-TOTO/public-settings' ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - }) - - it('Should fail with an unknown plugin', async function () { - for (const suffix of [ 'peertube-plugin-toto', 'peertube-plugin-toto/registered-settings', 'peertube-plugin-toto/public-settings' ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - } - }) - - it('Should succeed with the correct parameters', async function () { - for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings`, `${npmPlugin}/public-settings` ]) { - await makeGetRequest({ - url: server.url, - path: path + suffix, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - } - }) - }) - - describe('When updating plugin settings', function () { - const path = '/api/v1/plugins/' - const settings = { setting1: 'value1' } - - it('Should fail with an invalid token', async function () { - await makePutBodyRequest({ - url: server.url, - path: path + npmPlugin + '/settings', - fields: { settings }, - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePutBodyRequest({ - url: server.url, - path: path + npmPlugin + '/settings', - fields: { settings }, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid npm name', async function () { - await makePutBodyRequest({ - url: server.url, - path: path + 'toto/settings', - fields: { settings }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makePutBodyRequest({ - url: server.url, - path: path + 'peertube-plugin-TOTO/settings', - fields: { settings }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown plugin', async function () { - await makePutBodyRequest({ - url: server.url, - path: path + 'peertube-plugin-toto/settings', - fields: { settings }, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePutBodyRequest({ - url: server.url, - path: path + npmPlugin + '/settings', - fields: { settings }, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When installing/updating/uninstalling a plugin', function () { - const path = '/api/v1/plugins/' - - it('Should fail with an invalid token', async function () { - for (const suffix of [ 'install', 'update', 'uninstall' ]) { - await makePostBodyRequest({ - url: server.url, - path: path + suffix, - fields: { npmName: npmPlugin }, - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - } - }) - - it('Should fail if the user is not an administrator', async function () { - for (const suffix of [ 'install', 'update', 'uninstall' ]) { - await makePostBodyRequest({ - url: server.url, - path: path + suffix, - fields: { npmName: npmPlugin }, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - }) - - it('Should fail with an invalid npm name', async function () { - for (const suffix of [ 'install', 'update', 'uninstall' ]) { - await makePostBodyRequest({ - url: server.url, - path: path + suffix, - fields: { npmName: 'toto' }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - - for (const suffix of [ 'install', 'update', 'uninstall' ]) { - await makePostBodyRequest({ - url: server.url, - path: path + suffix, - fields: { npmName: 'peertube-plugin-TOTO' }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - }) - - it('Should succeed with the correct parameters', async function () { - const it = [ - { suffix: 'install', status: HttpStatusCode.OK_200 }, - { suffix: 'update', status: HttpStatusCode.OK_200 }, - { suffix: 'uninstall', status: HttpStatusCode.NO_CONTENT_204 } - ] - - for (const obj of it) { - await makePostBodyRequest({ - url: server.url, - path: path + obj.suffix, - fields: { npmName: npmPlugin }, - token: server.accessToken, - expectedStatus: obj.status - }) - } - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts deleted file mode 100644 index 73dfd489d..000000000 --- a/server/tests/api/check-params/redundancy.ts +++ /dev/null @@ -1,240 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode, VideoCreateResult } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test server redundancy API validators', function () { - let servers: PeerTubeServer[] - let userAccessToken = null - let videoIdLocal: number - let videoRemote: VideoCreateResult - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(160000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await doubleFollow(servers[0], servers[1]) - - const user = { - username: 'user1', - password: 'password' - } - - await servers[0].users.create({ username: user.username, password: user.password }) - userAccessToken = await servers[0].login.getAccessToken(user) - - videoIdLocal = (await servers[0].videos.quickUpload({ name: 'video' })).id - - const remoteUUID = (await servers[1].videos.quickUpload({ name: 'video' })).uuid - - await waitJobs(servers) - - videoRemote = await servers[0].videos.get({ id: remoteUUID }) - }) - - describe('When listing redundancies', function () { - const path = '/api/v1/server/redundancy/videos' - - let url: string - let token: string - - before(function () { - url = servers[0].url - token = servers[0].accessToken - }) - - it('Should fail with an invalid token', async function () { - await makeGetRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeGetRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(url, path, servers[0].accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(url, path, servers[0].accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(url, path, servers[0].accessToken) - }) - - it('Should fail with a bad target', async function () { - await makeGetRequest({ url, path, token, query: { target: 'bad target' } }) - }) - - it('Should fail without target', async function () { - await makeGetRequest({ url, path, token }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url, path, token, query: { target: 'my-videos' }, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When manually adding a redundancy', function () { - const path = '/api/v1/server/redundancy/videos' - - let url: string - let token: string - - before(function () { - url = servers[0].url - token = servers[0].accessToken - }) - - it('Should fail with an invalid token', async function () { - await makePostBodyRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePostBodyRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail without a video id', async function () { - await makePostBodyRequest({ url, path, token }) - }) - - it('Should fail with an incorrect video id', async function () { - await makePostBodyRequest({ url, path, token, fields: { videoId: 'peertube' } }) - }) - - it('Should fail with a not found video id', async function () { - await makePostBodyRequest({ url, path, token, fields: { videoId: 6565 }, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a local a video id', async function () { - await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdLocal } }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url, - path, - token, - fields: { videoId: videoRemote.shortUUID }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should fail if the video is already duplicated', async function () { - this.timeout(30000) - - await waitJobs(servers) - - await makePostBodyRequest({ - url, - path, - token, - fields: { videoId: videoRemote.uuid }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - }) - - describe('When manually removing a redundancy', function () { - const path = '/api/v1/server/redundancy/videos/' - - let url: string - let token: string - - before(function () { - url = servers[0].url - token = servers[0].accessToken - }) - - it('Should fail with an invalid token', async function () { - await makeDeleteRequest({ url, path: path + '1', token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makeDeleteRequest({ url, path: path + '1', token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with an incorrect video id', async function () { - await makeDeleteRequest({ url, path: path + 'toto', token }) - }) - - it('Should fail with a not found video redundancy', async function () { - await makeDeleteRequest({ url, path: path + '454545', token, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('When updating server redundancy', function () { - const path = '/api/v1/server/redundancy' - - it('Should fail with an invalid token', async function () { - await makePutBodyRequest({ - url: servers[0].url, - path: path + '/' + servers[1].host, - fields: { redundancyAllowed: true }, - token: 'fake_token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if the user is not an administrator', async function () { - await makePutBodyRequest({ - url: servers[0].url, - path: path + '/' + servers[1].host, - fields: { redundancyAllowed: true }, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail if we do not follow this server', async function () { - await makePutBodyRequest({ - url: servers[0].url, - path: path + '/example.com', - fields: { redundancyAllowed: true }, - token: servers[0].accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail without de redundancyAllowed param', async function () { - await makePutBodyRequest({ - url: servers[0].url, - path: path + '/' + servers[1].host, - fields: { blabla: true }, - token: servers[0].accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePutBodyRequest({ - url: servers[0].url, - path: path + '/' + servers[1].host, - fields: { redundancyAllowed: true }, - token: servers[0].accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/registrations.ts b/server/tests/api/check-params/registrations.ts deleted file mode 100644 index 8cbecdd07..000000000 --- a/server/tests/api/check-params/registrations.ts +++ /dev/null @@ -1,446 +0,0 @@ -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { omit } from '@shared/core-utils' -import { HttpStatusCode, UserRole } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar -} from '@shared/server-commands' - -describe('Test registrations API validators', function () { - let server: PeerTubeServer - let userToken: string - let moderatorToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultAccountAvatar([ server ]) - await setDefaultChannelAvatar([ server ]) - - await server.config.enableSignup(false); - - ({ token: moderatorToken } = await server.users.generate('moderator', UserRole.MODERATOR)); - ({ token: userToken } = await server.users.generate('user', UserRole.USER)) - }) - - describe('Register', function () { - const registrationPath = '/api/v1/users/register' - const registrationRequestPath = '/api/v1/users/registrations/request' - - const baseCorrectParams = { - username: 'user3', - displayName: 'super user', - email: 'test3@example.com', - password: 'my super password', - registrationReason: 'my super registration reason' - } - - describe('When registering a new user or requesting user registration', function () { - - async function check (fields: any, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { - await server.config.enableSignup(false) - await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus }) - - await server.config.enableSignup(true) - await makePostBodyRequest({ url: server.url, path: registrationRequestPath, fields, expectedStatus }) - } - - it('Should fail with a too small username', async function () { - const fields = { ...baseCorrectParams, username: '' } - - await check(fields) - }) - - it('Should fail with a too long username', async function () { - const fields = { ...baseCorrectParams, username: 'super'.repeat(50) } - - await check(fields) - }) - - it('Should fail with an incorrect username', async function () { - const fields = { ...baseCorrectParams, username: 'my username' } - - await check(fields) - }) - - it('Should fail with a missing email', async function () { - const fields = omit(baseCorrectParams, [ 'email' ]) - - await check(fields) - }) - - it('Should fail with an invalid email', async function () { - const fields = { ...baseCorrectParams, email: 'test_example.com' } - - await check(fields) - }) - - it('Should fail with a too small password', async function () { - const fields = { ...baseCorrectParams, password: 'bla' } - - await check(fields) - }) - - it('Should fail with a too long password', async function () { - const fields = { ...baseCorrectParams, password: 'super'.repeat(61) } - - await check(fields) - }) - - it('Should fail if we register a user with the same username', async function () { - const fields = { ...baseCorrectParams, username: 'root' } - - await check(fields, HttpStatusCode.CONFLICT_409) - }) - - it('Should fail with a "peertube" username', async function () { - const fields = { ...baseCorrectParams, username: 'peertube' } - - await check(fields, HttpStatusCode.CONFLICT_409) - }) - - it('Should fail if we register a user with the same email', async function () { - const fields = { ...baseCorrectParams, email: 'admin' + server.internalServerNumber + '@example.com' } - - await check(fields, HttpStatusCode.CONFLICT_409) - }) - - it('Should fail with a bad display name', async function () { - const fields = { ...baseCorrectParams, displayName: 'a'.repeat(150) } - - await check(fields) - }) - - it('Should fail with a bad channel name', async function () { - const fields = { ...baseCorrectParams, channel: { name: '[]azf', displayName: 'toto' } } - - await check(fields) - }) - - it('Should fail with a bad channel display name', async function () { - const fields = { ...baseCorrectParams, channel: { name: 'toto', displayName: '' } } - - await check(fields) - }) - - it('Should fail with a channel name that is the same as username', async function () { - const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } } - const fields = { ...baseCorrectParams, ...source } - - await check(fields) - }) - - it('Should fail with an existing channel', async function () { - const attributes = { name: 'existing_channel', displayName: 'hello', description: 'super description' } - await server.channels.create({ attributes }) - - const fields = { ...baseCorrectParams, channel: { name: 'existing_channel', displayName: 'toto' } } - - await check(fields, HttpStatusCode.CONFLICT_409) - }) - - it('Should fail on a server with registration disabled', async function () { - this.timeout(60000) - - await server.config.updateExistingSubConfig({ - newConfig: { - signup: { - enabled: false - } - } - }) - - await server.registrations.register({ username: 'user4', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await server.registrations.requestRegistration({ - username: 'user4', - registrationReason: 'reason', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail if the user limit is reached', async function () { - this.timeout(60000) - - const { total } = await server.users.list() - - await server.config.enableSignup(false, total) - await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - - await server.config.enableSignup(true, total) - await server.registrations.requestRegistration({ - username: 'user42', - registrationReason: 'reason', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed if the user limit is not reached', async function () { - this.timeout(60000) - - const { total } = await server.users.list() - - await server.config.enableSignup(false, total + 1) - await server.registrations.register({ username: 'user43', expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - - await server.config.enableSignup(true, total + 2) - await server.registrations.requestRegistration({ - username: 'user44', - registrationReason: 'reason', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('On direct registration', function () { - - it('Should succeed with the correct params', async function () { - await server.config.enableSignup(false) - - const fields = { - username: 'user_direct_1', - displayName: 'super user direct 1', - email: 'user_direct_1@example.com', - password: 'my super password', - channel: { name: 'super_user_direct_1_channel', displayName: 'super user direct 1 channel' } - } - - await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - }) - - it('Should fail if the instance requires approval', async function () { - this.timeout(60000) - - await server.config.enableSignup(true) - await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - }) - - describe('On registration request', function () { - - before(async function () { - this.timeout(60000) - - await server.config.enableSignup(true) - }) - - it('Should fail with an invalid registration reason', async function () { - for (const registrationReason of [ '', 't', 't'.repeat(5000) ]) { - await server.registrations.requestRegistration({ - username: 'user_request_1', - registrationReason, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - }) - - it('Should succeed with the correct params', async function () { - await server.registrations.requestRegistration({ - username: 'user_request_2', - registrationReason: 'tt', - channel: { - displayName: 'my user request 2 channel', - name: 'user_request_2_channel' - } - }) - }) - - it('Should fail if the username is already awaiting registration approval', async function () { - await server.registrations.requestRegistration({ - username: 'user_request_2', - registrationReason: 'tt', - channel: { - displayName: 'my user request 42 channel', - name: 'user_request_42_channel' - }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail if the email is already awaiting registration approval', async function () { - await server.registrations.requestRegistration({ - username: 'user42', - email: 'user_request_2@example.com', - registrationReason: 'tt', - channel: { - displayName: 'my user request 42 channel', - name: 'user_request_42_channel' - }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail if the channel is already awaiting registration approval', async function () { - await server.registrations.requestRegistration({ - username: 'user42', - registrationReason: 'tt', - channel: { - displayName: 'my user request 2 channel', - name: 'user_request_2_channel' - }, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail if the instance does not require approval', async function () { - this.timeout(60000) - - await server.config.enableSignup(false) - - await server.registrations.requestRegistration({ - username: 'user42', - registrationReason: 'toto', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - }) - - describe('Registrations accept/reject', function () { - let id1: number - let id2: number - - before(async function () { - this.timeout(60000) - - await server.config.enableSignup(true); - - ({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_2', registrationReason: 'toto' })); - ({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_3', registrationReason: 'toto' })) - }) - - it('Should fail to accept/reject registration without token', async function () { - const options = { id: id1, moderationResponse: 'tt', token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 } - await server.registrations.accept(options) - await server.registrations.reject(options) - }) - - it('Should fail to accept/reject registration with a non moderator user', async function () { - const options = { id: id1, moderationResponse: 'tt', token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 } - await server.registrations.accept(options) - await server.registrations.reject(options) - }) - - it('Should fail to accept/reject registration with a bad registration id', async function () { - { - const options = { id: 't' as any, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - await server.registrations.accept(options) - await server.registrations.reject(options) - } - - { - const options = { id: 42, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - await server.registrations.accept(options) - await server.registrations.reject(options) - } - }) - - it('Should fail to accept/reject registration with a bad moderation resposne', async function () { - for (const moderationResponse of [ '', 't', 't'.repeat(5000) ]) { - const options = { id: id1, moderationResponse, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - await server.registrations.accept(options) - await server.registrations.reject(options) - } - }) - - it('Should succeed to accept a registration', async function () { - await server.registrations.accept({ id: id1, moderationResponse: 'tt', token: moderatorToken }) - }) - - it('Should succeed to reject a registration', async function () { - await server.registrations.reject({ id: id2, moderationResponse: 'tt', token: moderatorToken }) - }) - - it('Should fail to accept/reject a registration that was already accepted/rejected', async function () { - for (const id of [ id1, id2 ]) { - const options = { id, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.CONFLICT_409 } - await server.registrations.accept(options) - await server.registrations.reject(options) - } - }) - }) - - describe('Registrations deletion', function () { - let id1: number - let id2: number - let id3: number - - before(async function () { - ({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_4', registrationReason: 'toto' })); - ({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_5', registrationReason: 'toto' })); - ({ id: id3 } = await server.registrations.requestRegistration({ username: 'request_6', registrationReason: 'toto' })) - - await server.registrations.accept({ id: id2, moderationResponse: 'tt' }) - await server.registrations.reject({ id: id3, moderationResponse: 'tt' }) - }) - - it('Should fail to delete registration without token', async function () { - await server.registrations.delete({ id: id1, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail to delete registration with a non moderator user', async function () { - await server.registrations.delete({ id: id1, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail to delete registration with a bad registration id', async function () { - await server.registrations.delete({ id: 't' as any, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.registrations.delete({ id: 42, token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await server.registrations.delete({ id: id1, token: moderatorToken }) - await server.registrations.delete({ id: id2, token: moderatorToken }) - await server.registrations.delete({ id: id3, token: moderatorToken }) - }) - }) - - describe('Listing registrations', function () { - const path = '/api/v1/users/registrations' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await server.registrations.list({ - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await server.registrations.list({ - token: userToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await server.registrations.list({ - token: moderatorToken, - search: 'toto' - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/runners.ts b/server/tests/api/check-params/runners.ts deleted file mode 100644 index 0e5012da5..000000000 --- a/server/tests/api/check-params/runners.ts +++ /dev/null @@ -1,910 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { basename } from 'path' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { - HttpStatusCode, - isVideoStudioTaskIntro, - RunnerJob, - RunnerJobState, - RunnerJobStudioTranscodingPayload, - RunnerJobSuccessPayload, - RunnerJobUpdatePayload, - VideoPrivacy, - VideoStudioTaskIntro -} from '@shared/models' -import { - cleanupTests, - createSingleServer, - makePostBodyRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - VideoStudioCommand, - waitJobs -} from '@shared/server-commands' - -const badUUID = '910ec12a-d9e6-458b-a274-0abb655f9464' - -describe('Test managing runners', function () { - let server: PeerTubeServer - - let userToken: string - - let registrationTokenId: number - let registrationToken: string - - let runnerToken: string - let runnerToken2: string - - let completedJobToken: string - let completedJobUUID: string - - let cancelledJobToken: string - let cancelledJobUUID: string - - before(async function () { - this.timeout(120000) - - const config = { - rates_limit: { - api: { - max: 5000 - } - } - } - - server = await createSingleServer(1, config) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - userToken = await server.users.generateUserAndToken('user1') - - const { data } = await server.runnerRegistrationTokens.list() - registrationToken = data[0].registrationToken - registrationTokenId = data[0].id - - await server.config.enableTranscoding({ hls: true, webVideo: true }) - await server.config.enableStudio() - await server.config.enableRemoteTranscoding() - await server.config.enableRemoteStudio() - - runnerToken = await server.runners.autoRegisterRunner() - runnerToken2 = await server.runners.autoRegisterRunner() - - { - await server.videos.quickUpload({ name: 'video 1' }) - await server.videos.quickUpload({ name: 'video 2' }) - - await waitJobs([ server ]) - - { - const job = await server.runnerJobs.autoProcessWebVideoJob(runnerToken) - completedJobToken = job.jobToken - completedJobUUID = job.uuid - } - - { - const { job } = await server.runnerJobs.autoAccept({ runnerToken }) - cancelledJobToken = job.jobToken - cancelledJobUUID = job.uuid - await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID }) - } - } - }) - - describe('Managing runner registration tokens', function () { - - describe('Common', function () { - - it('Should fail to generate, list or delete runner registration token without oauth token', async function () { - const expectedStatus = HttpStatusCode.UNAUTHORIZED_401 - - await server.runnerRegistrationTokens.generate({ token: null, expectedStatus }) - await server.runnerRegistrationTokens.list({ token: null, expectedStatus }) - await server.runnerRegistrationTokens.delete({ token: null, id: registrationTokenId, expectedStatus }) - }) - - it('Should fail to generate, list or delete runner registration token without admin rights', async function () { - const expectedStatus = HttpStatusCode.FORBIDDEN_403 - - await server.runnerRegistrationTokens.generate({ token: userToken, expectedStatus }) - await server.runnerRegistrationTokens.list({ token: userToken, expectedStatus }) - await server.runnerRegistrationTokens.delete({ token: userToken, id: registrationTokenId, expectedStatus }) - }) - }) - - describe('Delete', function () { - - it('Should fail to delete with a bad id', async function () { - await server.runnerRegistrationTokens.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('List', function () { - const path = '/api/v1/runners/registration-tokens' - - it('Should fail to list with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should succeed to list with the correct params', async function () { - await server.runnerRegistrationTokens.list({ start: 0, count: 5, sort: '-createdAt' }) - }) - }) - }) - - describe('Managing runners', function () { - let toDeleteId: number - - describe('Register', function () { - const name = 'runner name' - - it('Should fail with a bad registration token', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await server.runners.register({ name, registrationToken: 'a'.repeat(4000), expectedStatus }) - await server.runners.register({ name, registrationToken: null, expectedStatus }) - }) - - it('Should fail with an unknown registration token', async function () { - await server.runners.register({ name, registrationToken: 'aaa', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a bad name', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await server.runners.register({ name: '', registrationToken, expectedStatus }) - await server.runners.register({ name: 'a'.repeat(200), registrationToken, expectedStatus }) - }) - - it('Should fail with an invalid description', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await server.runners.register({ name, description: '', registrationToken, expectedStatus }) - await server.runners.register({ name, description: 'a'.repeat(5000), registrationToken, expectedStatus }) - }) - - it('Should succeed with the correct params', async function () { - const { id } = await server.runners.register({ name, description: 'super description', registrationToken }) - - toDeleteId = id - }) - - it('Should fail with the same runner name', async function () { - await server.runners.register({ - name, - description: 'super description', - registrationToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('Delete', function () { - - it('Should fail without oauth token', async function () { - await server.runners.delete({ token: null, id: toDeleteId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without admin rights', async function () { - await server.runners.delete({ token: userToken, id: toDeleteId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad id', async function () { - await server.runners.delete({ id: 'hi' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown id', async function () { - await server.runners.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await server.runners.delete({ id: toDeleteId }) - }) - }) - - describe('List', function () { - const path = '/api/v1/runners' - - it('Should fail without oauth token', async function () { - await server.runners.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without admin rights', async function () { - await server.runners.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail to list with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an invalid state', async function () { - await server.runners.list({ start: 0, count: 5, sort: '-createdAt' }) - }) - - it('Should succeed to list with the correct params', async function () { - await server.runners.list({ start: 0, count: 5, sort: '-createdAt' }) - }) - }) - - }) - - describe('Runner jobs by admin', function () { - - describe('Cancel', function () { - let jobUUID: string - - before(async function () { - this.timeout(60000) - - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - jobUUID = availableJobs[0].uuid - }) - - it('Should fail without oauth token', async function () { - await server.runnerJobs.cancelByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without admin rights', async function () { - await server.runnerJobs.cancelByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad job uuid', async function () { - await server.runnerJobs.cancelByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown job uuid', async function () { - const jobUUID = badUUID - await server.runnerJobs.cancelByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an already cancelled job', async function () { - await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct params', async function () { - await server.runnerJobs.cancelByAdmin({ jobUUID }) - }) - }) - - describe('List', function () { - const path = '/api/v1/runners/jobs' - - it('Should fail without oauth token', async function () { - await server.runnerJobs.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without admin rights', async function () { - await server.runnerJobs.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail to list with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail to list with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an invalid state', async function () { - await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: 42 as any }) - await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ 42 ] as any }) - }) - - it('Should succeed with the correct params', async function () { - await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ RunnerJobState.COMPLETED ] }) - }) - }) - - describe('Delete', function () { - let jobUUID: string - - before(async function () { - this.timeout(60000) - - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - jobUUID = availableJobs[0].uuid - }) - - it('Should fail without oauth token', async function () { - await server.runnerJobs.deleteByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail without admin rights', async function () { - await server.runnerJobs.deleteByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad job uuid', async function () { - await server.runnerJobs.deleteByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown job uuid', async function () { - const jobUUID = badUUID - await server.runnerJobs.deleteByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await server.runnerJobs.deleteByAdmin({ jobUUID }) - }) - }) - - }) - - describe('Runner jobs by runners', function () { - let jobUUID: string - let jobToken: string - let videoUUID: string - - let jobUUID2: string - let jobToken2: string - - let videoUUID2: string - - let pendingUUID: string - - let videoStudioUUID: string - let studioFile: string - - let liveAcceptedJob: RunnerJob & { jobToken: string } - let studioAcceptedJob: RunnerJob & { jobToken: string } - - async function fetchVideoInputFiles (options: { - jobUUID: string - videoUUID: string - runnerToken: string - jobToken: string - expectedStatus: HttpStatusCode - }) { - const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken } = options - - const basePath = '/api/v1/runners/jobs/' + jobUUID + '/files/videos/' + videoUUID - const paths = [ `${basePath}/max-quality`, `${basePath}/previews/max-quality` ] - - for (const path of paths) { - await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus }) - } - } - - async function fetchStudioFiles (options: { - jobUUID: string - videoUUID: string - runnerToken: string - jobToken: string - studioFile?: string - expectedStatus: HttpStatusCode - }) { - const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken, studioFile } = options - - const path = `/api/v1/runners/jobs/${jobUUID}/files/videos/${videoUUID}/studio/task-files/${studioFile}` - - await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus }) - } - - before(async function () { - this.timeout(120000) - - { - await server.runnerJobs.cancelAllJobs({ state: RunnerJobState.PENDING }) - } - - { - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - videoUUID = uuid - - await waitJobs([ server ]) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken }) - jobUUID = job.uuid - jobToken = job.jobToken - } - - { - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - videoUUID2 = uuid - - await waitJobs([ server ]) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken: runnerToken2 }) - jobUUID2 = job.uuid - jobToken2 = job.jobToken - } - - { - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - pendingUUID = availableJobs[0].uuid - } - - { - await server.config.disableTranscoding() - - const { uuid } = await server.videos.quickUpload({ name: 'video studio' }) - videoStudioUUID = uuid - - await server.config.enableTranscoding({ hls: true, webVideo: true }) - await server.config.enableStudio() - - await server.videoStudio.createEditionTasks({ - videoId: videoStudioUUID, - tasks: VideoStudioCommand.getComplexTask() - }) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'video-studio-transcoding' }) - studioAcceptedJob = job - - const tasks = (job.payload as RunnerJobStudioTranscodingPayload).tasks - const fileUrl = (tasks.find(t => isVideoStudioTaskIntro(t)) as VideoStudioTaskIntro).options.file as string - studioFile = basename(fileUrl) - } - - { - await server.config.enableLive({ - allowReplay: false, - resolutions: 'max', - transcoding: true - }) - - const { live } = await server.live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await waitJobs([ server ]) - - await server.runnerJobs.requestLiveJob(runnerToken) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'live-rtmp-hls-transcoding' }) - liveAcceptedJob = job - - await stopFfmpeg(ffmpegCommand) - } - }) - - describe('Common runner tokens validations', function () { - - async function testEndpoints (options: { - jobUUID: string - runnerToken: string - jobToken: string - expectedStatus: HttpStatusCode - }) { - await server.runnerJobs.abort({ ...options, reason: 'reason' }) - await server.runnerJobs.update({ ...options }) - await server.runnerJobs.error({ ...options, message: 'message' }) - await server.runnerJobs.success({ ...options, payload: { videoFile: 'video_short.mp4' } }) - } - - it('Should fail with an invalid job uuid', async function () { - const options = { jobUUID: 'a', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - - await testEndpoints({ ...options, jobToken }) - await fetchVideoInputFiles({ ...options, videoUUID, jobToken }) - await fetchStudioFiles({ ...options, videoUUID, jobToken: studioAcceptedJob.jobToken, studioFile }) - }) - - it('Should fail with an unknown job uuid', async function () { - const options = { jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobToken }) - await fetchVideoInputFiles({ ...options, videoUUID, jobToken }) - await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID, studioFile }) - }) - - it('Should fail with an invalid runner token', async function () { - const options = { runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - - await testEndpoints({ ...options, jobUUID, jobToken }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) - await fetchStudioFiles({ - ...options, - jobToken: studioAcceptedJob.jobToken, - jobUUID: studioAcceptedJob.uuid, - videoUUID: videoStudioUUID, - studioFile - }) - }) - - it('Should fail with an unknown runner token', async function () { - const options = { runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobUUID, jobToken }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) - await fetchStudioFiles({ - ...options, - jobToken: studioAcceptedJob.jobToken, - jobUUID: studioAcceptedJob.uuid, - videoUUID: videoStudioUUID, - studioFile - }) - }) - - it('Should fail with an invalid job token job uuid', async function () { - const options = { runnerToken, jobToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 } - - await testEndpoints({ ...options, jobUUID }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) - await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) - }) - - it('Should fail with an unknown job token job uuid', async function () { - const options = { runnerToken, jobToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobUUID }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) - await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) - }) - - it('Should fail with a runner token not associated to this job', async function () { - const options = { runnerToken: runnerToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobUUID, jobToken }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) - await fetchStudioFiles({ - ...options, - jobToken: studioAcceptedJob.jobToken, - jobUUID: studioAcceptedJob.uuid, - videoUUID: videoStudioUUID, - studioFile - }) - }) - - it('Should fail with a job uuid not associated to the job token', async function () { - { - const options = { jobUUID: jobUUID2, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobToken }) - await fetchVideoInputFiles({ ...options, jobToken, videoUUID }) - await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID: videoStudioUUID, studioFile }) - } - - { - const options = { runnerToken, jobToken: jobToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 } - - await testEndpoints({ ...options, jobUUID }) - await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) - await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) - } - }) - }) - - describe('Unregister', function () { - - it('Should fail without a runner token', async function () { - await server.runners.unregister({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad a runner token', async function () { - await server.runners.unregister({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown runner token', async function () { - await server.runners.unregister({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Request', function () { - - it('Should fail without a runner token', async function () { - await server.runnerJobs.request({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad a runner token', async function () { - await server.runnerJobs.request({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown runner token', async function () { - await server.runnerJobs.request({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Accept', function () { - - it('Should fail with a bad a job uuid', async function () { - await server.runnerJobs.accept({ jobUUID: '', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown job uuid', async function () { - await server.runnerJobs.accept({ jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a job not in pending state', async function () { - await server.runnerJobs.accept({ jobUUID: completedJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.runnerJobs.accept({ jobUUID: cancelledJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail without a runner token', async function () { - await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad a runner token', async function () { - await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown runner token', async function () { - await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Abort', function () { - - it('Should fail without a reason', async function () { - await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a bad reason', async function () { - const reason = 'reason'.repeat(5000) - await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a job not in processing state', async function () { - await server.runnerJobs.abort({ - jobUUID: completedJobUUID, - jobToken: completedJobToken, - runnerToken, - reason: 'reason', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('Update', function () { - - describe('Common', function () { - - it('Should fail with an invalid progress', async function () { - await server.runnerJobs.update({ jobUUID, jobToken, runnerToken, progress: 101, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a job not in processing state', async function () { - await server.runnerJobs.update({ - jobUUID: cancelledJobUUID, - jobToken: cancelledJobToken, - runnerToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - }) - - describe('Live RTMP to HLS', function () { - const base: RunnerJobUpdatePayload = { - masterPlaylistFile: 'live/master.m3u8', - resolutionPlaylistFilename: '0.m3u8', - resolutionPlaylistFile: 'live/1.m3u8', - type: 'add-chunk', - videoChunkFile: 'live/1-000069.ts', - videoChunkFilename: '1-000068.ts' - } - - function testUpdate (payload: RunnerJobUpdatePayload) { - return server.runnerJobs.update({ - jobUUID: liveAcceptedJob.uuid, - jobToken: liveAcceptedJob.jobToken, - payload, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - - it('Should fail with an invalid resolutionPlaylistFilename', async function () { - await testUpdate({ ...base, resolutionPlaylistFilename: undefined }) - await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' }) - await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' }) - }) - - it('Should fail with an invalid videoChunkFilename', async function () { - await testUpdate({ ...base, resolutionPlaylistFilename: undefined }) - await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' }) - await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' }) - }) - - it('Should fail with an invalid type', async function () { - await testUpdate({ ...base, type: undefined }) - await testUpdate({ ...base, type: 'toto' as any }) - }) - }) - }) - - describe('Error', function () { - - it('Should fail with a missing error message', async function () { - await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an invalid error messgae', async function () { - const message = 'a'.repeat(6000) - await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a job not in processing state', async function () { - await server.runnerJobs.error({ - jobUUID: completedJobUUID, - jobToken: completedJobToken, - message: 'my message', - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('Success', function () { - let vodJobUUID: string - let vodJobToken: string - - describe('Common', function () { - - it('Should fail with a job not in processing state', async function () { - await server.runnerJobs.success({ - jobUUID: completedJobUUID, - jobToken: completedJobToken, - payload: { videoFile: 'video_short.mp4' }, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('VOD', function () { - - it('Should fail with an invalid vod web video payload', async function () { - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-web-video-transcoding' }) - - await server.runnerJobs.success({ - jobUUID: job.uuid, - jobToken: job.jobToken, - payload: { hello: 'video_short.mp4' } as any, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - vodJobUUID = job.uuid - vodJobToken = job.jobToken - }) - - it('Should fail with an invalid vod hls payload', async function () { - // To create HLS jobs - const payload: RunnerJobSuccessPayload = { videoFile: 'video_short.mp4' } - await server.runnerJobs.success({ runnerToken, jobUUID: vodJobUUID, jobToken: vodJobToken, payload }) - - await waitJobs([ server ]) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-hls-transcoding' }) - - await server.runnerJobs.success({ - jobUUID: job.uuid, - jobToken: job.jobToken, - payload: { videoFile: 'video_short.mp4' } as any, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an invalid vod audio merge payload', async function () { - const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' } - await server.videos.upload({ attributes, mode: 'legacy' }) - - await waitJobs([ server ]) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-audio-merge-transcoding' }) - - await server.runnerJobs.success({ - jobUUID: job.uuid, - jobToken: job.jobToken, - payload: { hello: 'video_short.mp4' } as any, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('Video studio', function () { - - it('Should fail with an invalid video studio transcoding payload', async function () { - await server.runnerJobs.success({ - jobUUID: studioAcceptedJob.uuid, - jobToken: studioAcceptedJob.jobToken, - payload: { hello: 'video_short.mp4' } as any, - runnerToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - }) - - describe('Job files', function () { - - describe('Check video param for common job file routes', function () { - - async function fetchFiles (options: { - videoUUID?: string - expectedStatus: HttpStatusCode - }) { - await fetchVideoInputFiles({ videoUUID, ...options, jobToken, jobUUID, runnerToken }) - - await fetchStudioFiles({ - videoUUID: videoStudioUUID, - - ...options, - - jobToken: studioAcceptedJob.jobToken, - jobUUID: studioAcceptedJob.uuid, - runnerToken, - studioFile - }) - } - - it('Should fail with an invalid video id', async function () { - await fetchFiles({ - videoUUID: 'a', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown video id', async function () { - const videoUUID = '910ec12a-d9e6-458b-a274-0abb655f9464' - - await fetchFiles({ - videoUUID, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a video id not associated to this job', async function () { - await fetchFiles({ - videoUUID: videoUUID2, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await fetchFiles({ expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('Video studio tasks file routes', function () { - - it('Should fail with an invalid studio filename', async function () { - await fetchStudioFiles({ - videoUUID: videoStudioUUID, - jobUUID: studioAcceptedJob.uuid, - runnerToken, - jobToken: studioAcceptedJob.jobToken, - studioFile: 'toto', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts deleted file mode 100644 index b04d30b7f..000000000 --- a/server/tests/api/check-params/search.ts +++ /dev/null @@ -1,272 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -function updateSearchIndex (server: PeerTubeServer, enabled: boolean, disableLocalSearch = false) { - return server.config.updateCustomSubConfig({ - newConfig: { - search: { - searchIndex: { - enabled, - disableLocalSearch - } - } - } - }) -} - -describe('Test videos API validator', function () { - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - }) - - describe('When searching videos', function () { - const path = '/api/v1/search/videos/' - - const query = { - search: 'coucou' - } - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, null, query) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, null, query) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, null, query) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should fail with an invalid category', async function () { - const customQuery1 = { ...query, categoryOneOf: [ 'aa', 'b' ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery2 = { ...query, categoryOneOf: 'a' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with a valid category', async function () { - const customQuery1 = { ...query, categoryOneOf: [ 1, 7 ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery2 = { ...query, categoryOneOf: 1 } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should fail with an invalid licence', async function () { - const customQuery1 = { ...query, licenceOneOf: [ 'aa', 'b' ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery2 = { ...query, licenceOneOf: 'a' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with a valid licence', async function () { - const customQuery1 = { ...query, licenceOneOf: [ 1, 2 ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery2 = { ...query, licenceOneOf: 1 } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should succeed with a valid language', async function () { - const customQuery1 = { ...query, languageOneOf: [ 'fr', 'en' ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery2 = { ...query, languageOneOf: 'fr' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should succeed with valid tags', async function () { - const customQuery1 = { ...query, tagsOneOf: [ 'tag1', 'tag2' ] } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery2 = { ...query, tagsOneOf: 'tag1' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery3 = { ...query, tagsAllOf: [ 'tag1', 'tag2' ] } - await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.OK_200 }) - - const customQuery4 = { ...query, tagsAllOf: 'tag1' } - await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should fail with invalid durations', async function () { - const customQuery1 = { ...query, durationMin: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery2 = { ...query, durationMax: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with invalid dates', async function () { - const customQuery1 = { ...query, startDate: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery2 = { ...query, endDate: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery3 = { ...query, originallyPublishedStartDate: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - const customQuery4 = { ...query, originallyPublishedEndDate: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an invalid host', async function () { - const customQuery = { ...query, host: '6565' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with a host', async function () { - const customQuery = { ...query, host: 'example.com' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should fail with invalid uuids', async function () { - const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with valid uuids', async function () { - const customQuery = { ...query, uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When searching video playlists', function () { - const path = '/api/v1/search/video-playlists/' - - const query = { - search: 'coucou', - host: 'example.com' - } - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, null, query) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, null, query) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, null, query) - }) - - it('Should fail with an invalid host', async function () { - await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with invalid uuids', async function () { - const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When searching video channels', function () { - const path = '/api/v1/search/video-channels/' - - const query = { - search: 'coucou', - host: 'example.com' - } - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, null, query) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, null, query) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, null, query) - }) - - it('Should fail with an invalid host', async function () { - await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with invalid handles', async function () { - await makeGetRequest({ url: server.url, path, query: { ...query, handles: [ '' ] }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('Search target', function () { - - it('Should fail/succeed depending on the search target', async function () { - const query = { search: 'coucou' } - const paths = [ - '/api/v1/search/video-playlists/', - '/api/v1/search/video-channels/', - '/api/v1/search/videos/' - ] - - for (const path of paths) { - { - const customQuery = { ...query, searchTarget: 'hello' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - - { - const customQuery = { ...query, searchTarget: undefined } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - } - - { - const customQuery = { ...query, searchTarget: 'local' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - } - - { - const customQuery = { ...query, searchTarget: 'search-index' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - - await updateSearchIndex(server, true, true) - - { - const customQuery = { ...query, searchTarget: 'search-index' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - } - - await updateSearchIndex(server, true, false) - - { - const customQuery = { ...query, searchTarget: 'local' } - await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 }) - } - - await updateSearchIndex(server, false, false) - } - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts deleted file mode 100644 index d45868f36..000000000 --- a/server/tests/api/check-params/services.ts +++ /dev/null @@ -1,195 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, VideoCreateResult, VideoPlaylistCreateResult, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test services API validators', function () { - let server: PeerTubeServer - let playlistUUID: string - - let privateVideo: VideoCreateResult - let unlistedVideo: VideoCreateResult - - let privatePlaylist: VideoPlaylistCreateResult - let unlistedPlaylist: VideoPlaylistCreateResult - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(60000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - server.store.videoCreated = await server.videos.upload({ attributes: { name: 'my super name' } }) - - privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE }) - unlistedVideo = await server.videos.quickUpload({ name: 'unlisted', privacy: VideoPrivacy.UNLISTED }) - - { - const created = await server.playlists.create({ - attributes: { - displayName: 'super playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id - } - }) - - playlistUUID = created.uuid - - privatePlaylist = await server.playlists.create({ - attributes: { - displayName: 'private', - privacy: VideoPlaylistPrivacy.PRIVATE, - videoChannelId: server.store.channel.id - } - }) - - unlistedPlaylist = await server.playlists.create({ - attributes: { - displayName: 'unlisted', - privacy: VideoPlaylistPrivacy.UNLISTED, - videoChannelId: server.store.channel.id - } - }) - } - }) - - describe('Test oEmbed API validators', function () { - - it('Should fail with an invalid url', async function () { - const embedUrl = 'hello.com' - await checkParamEmbed(server, embedUrl) - }) - - it('Should fail with an invalid host', async function () { - const embedUrl = 'http://hello.com/videos/watch/' + server.store.videoCreated.uuid - await checkParamEmbed(server, embedUrl) - }) - - it('Should fail with an invalid element id', async function () { - const embedUrl = `${server.url}/videos/watch/blabla` - await checkParamEmbed(server, embedUrl) - }) - - it('Should fail with an unknown element', async function () { - const embedUrl = `${server.url}/videos/watch/88fc0165-d1f0-4a35-a51a-3b47f668689c` - await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_FOUND_404) - }) - - it('Should fail with an invalid path', async function () { - const embedUrl = `${server.url}/videos/watchs/${server.store.videoCreated.uuid}` - - await checkParamEmbed(server, embedUrl) - }) - - it('Should fail with an invalid max height', async function () { - const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxheight: 'hello' }) - }) - - it('Should fail with an invalid max width', async function () { - const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxwidth: 'hello' }) - }) - - it('Should fail with an invalid format', async function () { - const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { format: 'blabla' }) - }) - - it('Should fail with a non supported format', async function () { - const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_IMPLEMENTED_501, { format: 'xml' }) - }) - - it('Should fail with a private video', async function () { - const embedUrl = `${server.url}/videos/watch/${privateVideo.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403) - }) - - it('Should fail with an unlisted video with the int id', async function () { - const embedUrl = `${server.url}/videos/watch/${unlistedVideo.id}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403) - }) - - it('Should succeed with an unlisted video using the uuid id', async function () { - for (const uuid of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) { - const embedUrl = `${server.url}/videos/watch/${uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200) - } - }) - - it('Should fail with a private playlist', async function () { - const embedUrl = `${server.url}/videos/watch/playlist/${privatePlaylist.uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403) - }) - - it('Should fail with an unlisted playlist using the int id', async function () { - const embedUrl = `${server.url}/videos/watch/playlist/${unlistedPlaylist.id}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403) - }) - - it('Should succeed with an unlisted playlist using the uuid id', async function () { - for (const uuid of [ unlistedPlaylist.uuid, unlistedPlaylist.shortUUID ]) { - const embedUrl = `${server.url}/videos/watch/playlist/${uuid}` - - await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200) - } - }) - - it('Should succeed with the correct params with a video', async function () { - const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}` - const query = { - format: 'json', - maxheight: 400, - maxwidth: 400 - } - - await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query) - }) - - it('Should succeed with the correct params with a playlist', async function () { - const embedUrl = `${server.url}/videos/watch/playlist/${playlistUUID}` - const query = { - format: 'json', - maxheight: 400, - maxwidth: 400 - } - - await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) - -function checkParamEmbed (server: PeerTubeServer, embedUrl: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400, query = {}) { - const path = '/services/oembed' - - return makeGetRequest({ - url: server.url, - path, - query: Object.assign(query, { url: embedUrl }), - expectedStatus - }) -} diff --git a/server/tests/api/check-params/transcoding.ts b/server/tests/api/check-params/transcoding.ts deleted file mode 100644 index d5899e11b..000000000 --- a/server/tests/api/check-params/transcoding.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, UserRole } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test transcoding API validators', function () { - let servers: PeerTubeServer[] - - let userToken: string - let moderatorToken: string - - let remoteId: string - let validId: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER) - moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR) - - { - const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) - remoteId = uuid - } - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) - validId = uuid - } - - await waitJobs(servers) - - await servers[0].config.enableTranscoding() - }) - - it('Should not run transcoding of a unknown video', async function () { - await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'hls', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'web-video', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should not run transcoding of a remote video', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'hls', expectedStatus }) - await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'web-video', expectedStatus }) - }) - - it('Should not run transcoding by a non admin user', async function () { - const expectedStatus = HttpStatusCode.FORBIDDEN_403 - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', token: userToken, expectedStatus }) - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', token: moderatorToken, expectedStatus }) - }) - - it('Should not run transcoding without transcoding type', async function () { - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not run transcoding with an incorrect transcoding type', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'toto' as any, expectedStatus }) - }) - - it('Should not run transcoding if the instance disabled it', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await servers[0].config.disableTranscoding() - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', expectedStatus }) - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus }) - }) - - it('Should run transcoding', async function () { - this.timeout(120_000) - - await servers[0].config.enableTranscoding() - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls' }) - await waitJobs(servers) - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true }) - await waitJobs(servers) - }) - - it('Should not run transcoding on a video that is already being transcoded if forceTranscoding is not set', async function () { - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video' }) - - const expectedStatus = HttpStatusCode.CONFLICT_409 - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus }) - - await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/two-factor.ts b/server/tests/api/check-params/two-factor.ts deleted file mode 100644 index f8365f1b5..000000000 --- a/server/tests/api/check-params/two-factor.ts +++ /dev/null @@ -1,288 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands' - -describe('Test two factor API validators', function () { - let server: PeerTubeServer - - let rootId: number - let rootPassword: string - let rootRequestToken: string - let rootOTPToken: string - - let userId: number - let userToken = '' - let userPassword: string - let userRequestToken: string - let userOTPToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - { - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - } - - { - const result = await server.users.generate('user1') - userToken = result.token - userId = result.userId - userPassword = result.password - } - - { - const { id } = await server.users.getMyInfo() - rootId = id - rootPassword = server.store.user.password - } - }) - - describe('When requesting two factor', function () { - - it('Should fail with an unknown user id', async function () { - await server.twoFactor.request({ userId: 42, currentPassword: rootPassword, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an invalid user id', async function () { - await server.twoFactor.request({ - userId: 'invalid' as any, - currentPassword: rootPassword, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to request another user two factor without the appropriate rights', async function () { - await server.twoFactor.request({ - userId: rootId, - token: userToken, - currentPassword: userPassword, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to request another user two factor with the appropriate rights', async function () { - await server.twoFactor.request({ userId, currentPassword: rootPassword }) - }) - - it('Should fail to request two factor without a password', async function () { - await server.twoFactor.request({ - userId, - token: userToken, - currentPassword: undefined, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to request two factor with an incorrect password', async function () { - await server.twoFactor.request({ - userId, - token: userToken, - currentPassword: rootPassword, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to request two factor without a password when targeting a remote user with an admin account', async function () { - await server.twoFactor.request({ userId }) - }) - - it('Should fail to request two factor without a password when targeting myself with an admin account', async function () { - await server.twoFactor.request({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.twoFactor.request({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed to request my two factor auth', async function () { - { - const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword }) - userRequestToken = otpRequest.requestToken - userOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate() - } - - { - const { otpRequest } = await server.twoFactor.request({ userId: rootId, currentPassword: rootPassword }) - rootRequestToken = otpRequest.requestToken - rootOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate() - } - }) - }) - - describe('When confirming two factor request', function () { - - it('Should fail with an unknown user id', async function () { - await server.twoFactor.confirmRequest({ - userId: 42, - requestToken: rootRequestToken, - otpToken: rootOTPToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an invalid user id', async function () { - await server.twoFactor.confirmRequest({ - userId: 'invalid' as any, - requestToken: rootRequestToken, - otpToken: rootOTPToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to confirm another user two factor request without the appropriate rights', async function () { - await server.twoFactor.confirmRequest({ - userId: rootId, - token: userToken, - requestToken: rootRequestToken, - otpToken: rootOTPToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail without request token', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: undefined, - otpToken: userOTPToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an invalid request token', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: 'toto', - otpToken: userOTPToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with request token of another user', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: rootRequestToken, - otpToken: userOTPToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail without an otp token', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: userRequestToken, - otpToken: undefined, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad otp token', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: userRequestToken, - otpToken: '123456', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to confirm another user two factor request with the appropriate rights', async function () { - await server.twoFactor.confirmRequest({ - userId, - requestToken: userRequestToken, - otpToken: userOTPToken - }) - - // Reinit - await server.twoFactor.disable({ userId, currentPassword: rootPassword }) - }) - - it('Should succeed to confirm my two factor request', async function () { - await server.twoFactor.confirmRequest({ - userId, - token: userToken, - requestToken: userRequestToken, - otpToken: userOTPToken - }) - }) - - it('Should fail to confirm again two factor request', async function () { - await server.twoFactor.confirmRequest({ - userId, - token: userToken, - requestToken: userRequestToken, - otpToken: userOTPToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - describe('When disabling two factor', function () { - - it('Should fail with an unknown user id', async function () { - await server.twoFactor.disable({ - userId: 42, - currentPassword: rootPassword, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an invalid user id', async function () { - await server.twoFactor.disable({ - userId: 'invalid' as any, - currentPassword: rootPassword, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to disable another user two factor without the appropriate rights', async function () { - await server.twoFactor.disable({ - userId: rootId, - token: userToken, - currentPassword: userPassword, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail to disable two factor with an incorrect password', async function () { - await server.twoFactor.disable({ - userId, - token: userToken, - currentPassword: rootPassword, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to disable two factor without a password when targeting a remote user with an admin account', async function () { - await server.twoFactor.disable({ userId }) - await server.twoFactor.requestAndConfirm({ userId }) - }) - - it('Should fail to disable two factor without a password when targeting myself with an admin account', async function () { - await server.twoFactor.disable({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.twoFactor.disable({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed to disable another user two factor with the appropriate rights', async function () { - await server.twoFactor.disable({ userId, currentPassword: rootPassword }) - - await server.twoFactor.requestAndConfirm({ userId }) - }) - - it('Should succeed to update my two factor auth', async function () { - await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword }) - }) - - it('Should fail to disable again two factor', async function () { - await server.twoFactor.disable({ - userId, - token: userToken, - currentPassword: userPassword, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/upload-quota.ts b/server/tests/api/check-params/upload-quota.ts deleted file mode 100644 index 06698c056..000000000 --- a/server/tests/api/check-params/upload-quota.ts +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FIXTURE_URLS } from '@server/tests/shared' -import { randomInt } from '@shared/core-utils' -import { HttpStatusCode, VideoImportState, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - VideosCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test upload quota', function () { - let server: PeerTubeServer - let rootId: number - let command: VideosCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - const user = await server.users.getMyInfo() - rootId = user.id - - await server.users.update({ userId: rootId, videoQuota: 42 }) - - command = server.videos - }) - - describe('When having a video quota', function () { - - it('Should fail with a registered user having too many videos with legacy upload', async function () { - this.timeout(120000) - - const user = { username: 'registered' + randomInt(1, 1500), password: 'password' } - await server.registrations.register(user) - const userToken = await server.login.getAccessToken(user) - - const attributes = { fixture: 'video_short2.webm' } - for (let i = 0; i < 5; i++) { - await command.upload({ token: userToken, attributes }) - } - - await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' }) - }) - - it('Should fail with a registered user having too many videos with resumable upload', async function () { - this.timeout(120000) - - const user = { username: 'registered' + randomInt(1, 1500), password: 'password' } - await server.registrations.register(user) - const userToken = await server.login.getAccessToken(user) - - const attributes = { fixture: 'video_short2.webm' } - for (let i = 0; i < 5; i++) { - await command.upload({ token: userToken, attributes }) - } - - await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' }) - }) - - it('Should fail to import with HTTP/Torrent/magnet', async function () { - this.timeout(120_000) - - const baseAttributes = { - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - await server.imports.importVideo({ attributes: { ...baseAttributes, targetUrl: FIXTURE_URLS.goodVideo } }) - await server.imports.importVideo({ attributes: { ...baseAttributes, magnetUri: FIXTURE_URLS.magnet } }) - await server.imports.importVideo({ attributes: { ...baseAttributes, torrentfile: 'video-720p.torrent' as any } }) - - await waitJobs([ server ]) - - const { total, data: videoImports } = await server.imports.getMyVideoImports() - expect(total).to.equal(3) - - expect(videoImports).to.have.lengthOf(3) - - for (const videoImport of videoImports) { - expect(videoImport.state.id).to.equal(VideoImportState.FAILED) - expect(videoImport.error).not.to.be.undefined - expect(videoImport.error).to.contain('user video quota is exceeded') - } - }) - }) - - describe('When having a daily video quota', function () { - - it('Should fail with a user having too many videos daily', async function () { - await server.users.update({ userId: rootId, videoQuotaDaily: 42 }) - - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' }) - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' }) - }) - }) - - describe('When having an absolute and daily video quota', function () { - it('Should fail if exceeding total quota', async function () { - await server.users.update({ - userId: rootId, - videoQuota: 42, - videoQuotaDaily: 1024 * 1024 * 1024 - }) - - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' }) - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' }) - }) - - it('Should fail if exceeding daily quota', async function () { - await server.users.update({ - userId: rootId, - videoQuota: 1024 * 1024 * 1024, - videoQuotaDaily: 42 - }) - - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' }) - await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts deleted file mode 100644 index 6a588e446..000000000 --- a/server/tests/api/check-params/user-notifications.ts +++ /dev/null @@ -1,290 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { io } from 'socket.io-client' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, UserNotificationSetting, UserNotificationSettingValue } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test user notifications API validators', function () { - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - }) - - describe('When listing my notifications', function () { - const path = '/api/v1/users/me/notifications' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect unread parameter', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { - unread: 'toto' - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When marking as read my notifications', function () { - const path = '/api/v1/users/me/notifications/read' - - it('Should fail with wrong ids parameters', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { - ids: [ 'hello' ] - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { - ids: [ ] - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makePostBodyRequest({ - url: server.url, - path, - fields: { - ids: 5 - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a non authenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { - ids: [ 5 ] - }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { - ids: [ 5 ] - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When marking as read my notifications', function () { - const path = '/api/v1/users/me/notifications/read-all' - - it('Should fail with a non authenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When updating my notification settings', function () { - const path = '/api/v1/users/me/notification-settings' - const correctFields: UserNotificationSetting = { - newVideoFromSubscription: UserNotificationSettingValue.WEB, - newCommentOnMyVideo: UserNotificationSettingValue.WEB, - abuseAsModerator: UserNotificationSettingValue.WEB, - videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB, - blacklistOnMyVideo: UserNotificationSettingValue.WEB, - myVideoImportFinished: UserNotificationSettingValue.WEB, - myVideoPublished: UserNotificationSettingValue.WEB, - commentMention: UserNotificationSettingValue.WEB, - newFollow: UserNotificationSettingValue.WEB, - newUserRegistration: UserNotificationSettingValue.WEB, - newInstanceFollower: UserNotificationSettingValue.WEB, - autoInstanceFollowing: UserNotificationSettingValue.WEB, - abuseNewMessage: UserNotificationSettingValue.WEB, - abuseStateChange: UserNotificationSettingValue.WEB, - newPeerTubeVersion: UserNotificationSettingValue.WEB, - myVideoStudioEditionFinished: UserNotificationSettingValue.WEB, - newPluginVersion: UserNotificationSettingValue.WEB - } - - it('Should fail with missing fields', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { newVideoFromSubscription: UserNotificationSettingValue.WEB }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with incorrect field values', async function () { - { - const fields = { ...correctFields, newCommentOnMyVideo: 15 } - - await makePutBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - - { - const fields = { ...correctFields, newCommentOnMyVideo: 'toto' } - - await makePutBodyRequest({ - url: server.url, - path, - fields, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - } - }) - - it('Should fail with a non authenticated user', async function () { - await makePutBodyRequest({ - url: server.url, - path, - fields: correctFields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: correctFields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When connecting to my notification socket', function () { - - it('Should fail with no token', function (next) { - const socket = io(`${server.url}/user-notifications`, { reconnection: false }) - - socket.once('connect_error', function () { - socket.disconnect() - next() - }) - - socket.on('connect', () => { - socket.disconnect() - next(new Error('Connected with a missing token.')) - }) - }) - - it('Should fail with an invalid token', function (next) { - const socket = io(`${server.url}/user-notifications`, { - query: { accessToken: 'bad_access_token' }, - reconnection: false - }) - - socket.once('connect_error', function () { - socket.disconnect() - next() - }) - - socket.on('connect', () => { - socket.disconnect() - next(new Error('Connected with an invalid token.')) - }) - }) - - it('Should success with the correct token', function (next) { - const socket = io(`${server.url}/user-notifications`, { - query: { accessToken: server.accessToken }, - reconnection: false - }) - - function errorListener (err) { - next(new Error('Error in connection: ' + err)) - } - - socket.on('connect_error', errorListener) - - socket.once('connect', async () => { - socket.disconnect() - - await wait(500) - next() - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts deleted file mode 100644 index c4922c7a2..000000000 --- a/server/tests/api/check-params/user-subscriptions.ts +++ /dev/null @@ -1,298 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' -import { checkBadStartPagination, checkBadCountPagination, checkBadSortPagination } from '@server/tests/shared' - -describe('Test user subscriptions API validators', function () { - const path = '/api/v1/users/me/subscriptions' - let server: PeerTubeServer - let userAccessToken = '' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const user = { - username: 'user1', - password: 'my super password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - }) - - describe('When listing my subscriptions', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When listing my subscriptions videos', function () { - const path = '/api/v1/users/me/subscriptions/videos' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When adding a subscription', function () { - it('Should fail with a non authenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - fields: { uri: 'user1_channel@' + server.host }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with bad URIs', async function () { - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { uri: 'root' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { uri: 'root@' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { uri: 'root@hello@' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - this.timeout(20000) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: { uri: 'user1_channel@' + server.host }, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - - await waitJobs([ server ]) - }) - }) - - describe('When getting a subscription', function () { - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path: path + '/user1_channel@' + server.host, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with bad URIs', async function () { - await makeGetRequest({ - url: server.url, - path: path + '/root', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url: server.url, - path: path + '/root@', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url: server.url, - path: path + '/root@hello@', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown subscription', async function () { - await makeGetRequest({ - url: server.url, - path: path + '/root1@' + server.host, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path: path + '/user1_channel@' + server.host, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When checking if subscriptions exist', function () { - const existPath = path + '/exist' - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path: existPath, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with bad URIs', async function () { - await makeGetRequest({ - url: server.url, - path: existPath, - query: { uris: 'toto' }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url: server.url, - path: existPath, - query: { 'uris[]': 1 }, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path: existPath, - query: { 'uris[]': 'coucou@' + server.host }, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When removing a subscription', function () { - it('Should fail with a non authenticated user', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1_channel@' + server.host, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with bad URIs', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/root', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeDeleteRequest({ - url: server.url, - path: path + '/root@', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeDeleteRequest({ - url: server.url, - path: path + '/root@hello@', - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown subscription', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/root1@' + server.host, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '/user1_channel@' + server.host, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/users-admin.ts b/server/tests/api/check-params/users-admin.ts deleted file mode 100644 index 819da0bb2..000000000 --- a/server/tests/api/check-params/users-admin.ts +++ /dev/null @@ -1,456 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared' -import { omit } from '@shared/core-utils' -import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createSingleServer, - killallServers, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test users admin API validators', function () { - const path = '/api/v1/users/' - let userId: number - let rootId: number - let moderatorId: number - let server: PeerTubeServer - let userToken = '' - let moderatorToken = '' - let emailPort: number - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - const emails: object[] = [] - emailPort = await MockSmtpServer.Instance.collectEmails(emails) - - { - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - } - - { - const result = await server.users.generate('user1') - userToken = result.token - userId = result.userId - } - - { - const result = await server.users.generate('moderator1', UserRole.MODERATOR) - moderatorToken = result.token - } - - { - const result = await server.users.generate('moderator2', UserRole.MODERATOR) - moderatorId = result.userId - } - }) - - describe('When listing users', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - describe('When adding a new user', function () { - const baseCorrectParams = { - username: 'user2', - email: 'test@example.com', - password: 'my super password', - videoQuota: -1, - videoQuotaDaily: -1, - role: UserRole.USER, - adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST - } - - it('Should fail with a too small username', async function () { - const fields = { ...baseCorrectParams, username: '' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a too long username', async function () { - const fields = { ...baseCorrectParams, username: 'super'.repeat(50) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a not lowercase username', async function () { - const fields = { ...baseCorrectParams, username: 'Toto' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect username', async function () { - const fields = { ...baseCorrectParams, username: 'my username' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a missing email', async function () { - const fields = omit(baseCorrectParams, [ 'email' ]) - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid email', async function () { - const fields = { ...baseCorrectParams, email: 'test_example.com' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a too small password', async function () { - const fields = { ...baseCorrectParams, password: 'bla' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a too long password', async function () { - const fields = { ...baseCorrectParams, password: 'super'.repeat(61) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with empty password and no smtp configured', async function () { - const fields = { ...baseCorrectParams, password: '' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should succeed with no password on a server with smtp enabled', async function () { - this.timeout(20000) - - await killallServers([ server ]) - - await server.run(ConfigCommand.getEmailOverrideConfig(emailPort)) - - const fields = { - ...baseCorrectParams, - - password: '', - username: 'create_password', - email: 'create_password@example.com' - } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should fail with invalid admin flags', async function () { - const fields = { ...baseCorrectParams, adminFlags: 'toto' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an non authenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path, - token: 'super token', - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail if we add a user with the same username', async function () { - const fields = { ...baseCorrectParams, username: 'user1' } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail if we add a user with the same email', async function () { - const fields = { ...baseCorrectParams, email: 'user1@example.com' } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail with an invalid videoQuota', async function () { - const fields = { ...baseCorrectParams, videoQuota: -5 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid videoQuotaDaily', async function () { - const fields = { ...baseCorrectParams, videoQuotaDaily: -7 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail without a user role', async function () { - const fields = omit(baseCorrectParams, [ 'role' ]) - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid user role', async function () { - const fields = { ...baseCorrectParams, role: 88989 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a "peertube" username', async function () { - const fields = { ...baseCorrectParams, username: 'peertube' } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should fail to create a moderator or an admin with a moderator', async function () { - for (const role of [ UserRole.MODERATOR, UserRole.ADMINISTRATOR ]) { - const fields = { ...baseCorrectParams, role } - - await makePostBodyRequest({ - url: server.url, - path, - token: moderatorToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - }) - - it('Should succeed to create a user with a moderator', async function () { - const fields = { ...baseCorrectParams, username: 'a4656', email: 'a4656@example.com', role: UserRole.USER } - - await makePostBodyRequest({ - url: server.url, - path, - token: moderatorToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should succeed with the correct params', async function () { - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should fail with a non admin user', async function () { - const user = { username: 'user1' } - userToken = await server.login.getAccessToken(user) - - const fields = { - username: 'user3', - email: 'test@example.com', - password: 'my super password', - videoQuota: 42000000 - } - await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - }) - - describe('When getting a user', function () { - - it('Should fail with an non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path: path + userId, - token: 'super token', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url: server.url, path: path + userId, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When updating a user', function () { - - it('Should fail with an invalid email attribute', async function () { - const fields = { - email: 'blabla' - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid emailVerified attribute', async function () { - const fields = { - emailVerified: 'yes' - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid videoQuota attribute', async function () { - const fields = { - videoQuota: -90 - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with an invalid user role attribute', async function () { - const fields = { - role: 54878 - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with a too small password', async function () { - const fields = { - currentPassword: 'password', - password: 'bla' - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with a too long password', async function () { - const fields = { - currentPassword: 'password', - password: 'super'.repeat(61) - } - - await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) - }) - - it('Should fail with an non authenticated user', async function () { - const fields = { - videoQuota: 42 - } - - await makePutBodyRequest({ - url: server.url, - path: path + userId, - token: 'super token', - fields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail when updating root role', async function () { - const fields = { - role: UserRole.MODERATOR - } - - await makePutBodyRequest({ url: server.url, path: path + rootId, token: server.accessToken, fields }) - }) - - it('Should fail with invalid admin flags', async function () { - const fields = { adminFlags: 'toto' } - - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail to update an admin with a moderator', async function () { - const fields = { - videoQuota: 42 - } - - await makePutBodyRequest({ - url: server.url, - path: path + moderatorId, - token: moderatorToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to update a user with a moderator', async function () { - const fields = { - videoQuota: 42 - } - - await makePutBodyRequest({ - url: server.url, - path: path + userId, - token: moderatorToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should succeed with the correct params', async function () { - const fields = { - email: 'email@example.com', - emailVerified: true, - videoQuota: 42, - role: UserRole.USER - } - - await makePutBodyRequest({ - url: server.url, - path: path + userId, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/users-emails.ts b/server/tests/api/check-params/users-emails.ts deleted file mode 100644 index 6ebcc8ffe..000000000 --- a/server/tests/api/check-params/users-emails.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { HttpStatusCode, UserRole } from '@shared/models' -import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test users API validators', function () { - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { - rates_limit: { - ask_send_email: { - max: 10 - } - } - }) - - await setAccessTokensToServers([ server ]) - await server.config.enableSignup(true) - - await server.users.generate('moderator2', UserRole.MODERATOR) - - await server.registrations.requestRegistration({ - username: 'request1', - registrationReason: 'tt' - }) - }) - - describe('When asking a password reset', function () { - const path = '/api/v1/users/ask-reset-password' - - it('Should fail with a missing email', async function () { - const fields = {} - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should fail with an invalid email', async function () { - const fields = { email: 'hello' } - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should success with the correct params', async function () { - const fields = { email: 'admin@example.com' } - - await makePostBodyRequest({ - url: server.url, - path, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When asking for an account verification email', function () { - const path = '/api/v1/users/ask-send-verify-email' - - it('Should fail with a missing email', async function () { - const fields = {} - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should fail with an invalid email', async function () { - const fields = { email: 'hello' } - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should succeed with the correct params', async function () { - const fields = { email: 'admin@example.com' } - - await makePostBodyRequest({ - url: server.url, - path, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When asking for a registration verification email', function () { - const path = '/api/v1/users/registrations/ask-send-verify-email' - - it('Should fail with a missing email', async function () { - const fields = {} - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should fail with an invalid email', async function () { - const fields = { email: 'hello' } - - await makePostBodyRequest({ url: server.url, path, fields }) - }) - - it('Should succeed with the correct params', async function () { - const fields = { email: 'request1@example.com' } - - await makePostBodyRequest({ - url: server.url, - path, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts deleted file mode 100644 index 8e9f61596..000000000 --- a/server/tests/api/check-params/video-blacklist.ts +++ /dev/null @@ -1,292 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode, VideoBlacklistType } from '@shared/models' -import { - BlacklistCommand, - cleanupTests, - createMultipleServers, - doubleFollow, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test video blacklist API validators', function () { - let servers: PeerTubeServer[] - let notBlacklistedVideoId: string - let remoteVideoUUID: string - let userAccessToken1 = '' - let userAccessToken2 = '' - let command: BlacklistCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await doubleFollow(servers[0], servers[1]) - - { - const username = 'user1' - const password = 'my super password' - await servers[0].users.create({ username, password }) - userAccessToken1 = await servers[0].login.getAccessToken({ username, password }) - } - - { - const username = 'user2' - const password = 'my super password' - await servers[0].users.create({ username, password }) - userAccessToken2 = await servers[0].login.getAccessToken({ username, password }) - } - - { - servers[0].store.videoCreated = await servers[0].videos.upload({ token: userAccessToken1 }) - } - - { - const { uuid } = await servers[0].videos.upload() - notBlacklistedVideoId = uuid - } - - { - const { uuid } = await servers[1].videos.upload() - remoteVideoUUID = uuid - } - - await waitJobs(servers) - - command = servers[0].blacklist - }) - - describe('When adding a video in blacklist', function () { - const basePath = '/api/v1/videos/' - - it('Should fail with nothing', async function () { - const path = basePath + servers[0].store.videoCreated + '/blacklist' - const fields = {} - await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields }) - }) - - it('Should fail with a wrong video', async function () { - const wrongPath = '/api/v1/videos/blabla/blacklist' - const fields = {} - await makePostBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields }) - }) - - it('Should fail with a non authenticated user', async function () { - const path = basePath + servers[0].store.videoCreated + '/blacklist' - const fields = {} - await makePostBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a non admin user', async function () { - const path = basePath + servers[0].store.videoCreated + '/blacklist' - const fields = {} - await makePostBodyRequest({ - url: servers[0].url, - path, - token: userAccessToken2, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid reason', async function () { - const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist' - const fields = { reason: 'a'.repeat(305) } - - await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields }) - }) - - it('Should fail to unfederate a remote video', async function () { - const path = basePath + remoteVideoUUID + '/blacklist' - const fields = { unfederate: true } - - await makePostBodyRequest({ - url: servers[0].url, - path, - token: servers[0].accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should succeed with the correct params', async function () { - const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist' - const fields = {} - - await makePostBodyRequest({ - url: servers[0].url, - path, - token: servers[0].accessToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When updating a video in blacklist', function () { - const basePath = '/api/v1/videos/' - - it('Should fail with a wrong video', async function () { - const wrongPath = '/api/v1/videos/blabla/blacklist' - const fields = {} - await makePutBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields }) - }) - - it('Should fail with a video not blacklisted', async function () { - const path = '/api/v1/videos/' + notBlacklistedVideoId + '/blacklist' - const fields = {} - await makePutBodyRequest({ - url: servers[0].url, - path, - token: servers[0].accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a non authenticated user', async function () { - const path = basePath + servers[0].store.videoCreated + '/blacklist' - const fields = {} - await makePutBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a non admin user', async function () { - const path = basePath + servers[0].store.videoCreated + '/blacklist' - const fields = {} - await makePutBodyRequest({ - url: servers[0].url, - path, - token: userAccessToken2, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid reason', async function () { - const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist' - const fields = { reason: 'a'.repeat(305) } - - await makePutBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields }) - }) - - it('Should succeed with the correct params', async function () { - const path = basePath + servers[0].store.videoCreated.shortUUID + '/blacklist' - const fields = { reason: 'hello' } - - await makePutBodyRequest({ - url: servers[0].url, - path, - token: servers[0].accessToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When getting blacklisted video', function () { - - it('Should fail with a non authenticated user', async function () { - await servers[0].videos.get({ id: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another user', async function () { - await servers[0].videos.getWithToken({ - token: userAccessToken2, - id: servers[0].store.videoCreated.uuid, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the owner authenticated user', async function () { - const video = await servers[0].videos.getWithToken({ token: userAccessToken1, id: servers[0].store.videoCreated.uuid }) - expect(video.blacklisted).to.be.true - }) - - it('Should succeed with an admin', async function () { - const video = servers[0].store.videoCreated - - for (const id of [ video.id, video.uuid, video.shortUUID ]) { - const video = await servers[0].videos.getWithToken({ id, expectedStatus: HttpStatusCode.OK_200 }) - expect(video.blacklisted).to.be.true - } - }) - }) - - describe('When removing a video in blacklist', function () { - - it('Should fail with a non authenticated user', async function () { - await command.remove({ - token: 'fake token', - videoId: servers[0].store.videoCreated.uuid, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await command.remove({ - token: userAccessToken2, - videoId: servers[0].store.videoCreated.uuid, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an incorrect id', async function () { - await command.remove({ videoId: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a not blacklisted video', async function () { - // The video was not added to the blacklist so it should fail - await command.remove({ videoId: notBlacklistedVideoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct params', async function () { - await command.remove({ videoId: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - }) - }) - - describe('When listing videos in blacklist', function () { - const basePath = '/api/v1/videos/blacklist/' - - it('Should fail with a non authenticated user', async function () { - await servers[0].blacklist.list({ token: 'fake token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a non admin user', async function () { - await servers[0].blacklist.list({ token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(servers[0].url, basePath, servers[0].accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(servers[0].url, basePath, servers[0].accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(servers[0].url, basePath, servers[0].accessToken) - }) - - it('Should fail with an invalid type', async function () { - await servers[0].blacklist.list({ type: 0 as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct parameters', async function () { - await servers[0].blacklist.list({ type: VideoBlacklistType.MANUAL }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts deleted file mode 100644 index 532dab1c4..000000000 --- a/server/tests/api/check-params/video-captions.ts +++ /dev/null @@ -1,307 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makeUploadRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test video captions API validator', function () { - const path = '/api/v1/videos/' - - let server: PeerTubeServer - let userAccessToken: string - let video: VideoCreateResult - let privateVideo: VideoCreateResult - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - video = await server.videos.upload() - privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } }) - - { - const user = { - username: 'user1', - password: 'my super password' - } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - } - }) - - describe('When adding video caption', function () { - const fields = { } - const attaches = { - captionfile: buildAbsoluteFixturePath('subtitle-good1.vtt') - } - - it('Should fail without a valid uuid', async function () { - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr', - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with an unknown id', async function () { - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr', - token: server.accessToken, - fields, - attaches, - expectedStatus: 404 - }) - }) - - it('Should fail with a missing language in path', async function () { - const captionPath = path + video.uuid + '/captions' - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: captionPath, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with an unknown language', async function () { - const captionPath = path + video.uuid + '/captions/15' - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: captionPath, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail without access token', async function () { - const captionPath = path + video.uuid + '/captions/fr' - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: captionPath, - fields, - attaches, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad access token', async function () { - const captionPath = path + video.uuid + '/captions/fr' - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: captionPath, - token: 'blabla', - fields, - attaches, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - // We accept any file now - // it('Should fail with an invalid captionfile extension', async function () { - // const attaches = { - // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt') - // } - // - // const captionPath = path + video.uuid + '/captions/fr' - // await makeUploadRequest({ - // method: 'PUT', - // url: server.url, - // path: captionPath, - // token: server.accessToken, - // fields, - // attaches, - // expectedStatus: HttpStatusCode.BAD_REQUEST_400 - // }) - // }) - - // We don't check the extension yet - // it('Should fail with an invalid captionfile extension and octet-stream mime type', async function () { - // await createVideoCaption({ - // url: server.url, - // accessToken: server.accessToken, - // language: 'zh', - // videoId: video.uuid, - // fixture: 'subtitle-bad.txt', - // mimeType: 'application/octet-stream', - // expectedStatus: HttpStatusCode.BAD_REQUEST_400 - // }) - // }) - - it('Should succeed with a valid captionfile extension and octet-stream mime type', async function () { - await server.captions.add({ - language: 'zh', - videoId: video.uuid, - fixture: 'subtitle-good.srt', - mimeType: 'application/octet-stream' - }) - }) - - // We don't check the file validity yet - // it('Should fail with an invalid captionfile srt', async function () { - // const attaches = { - // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt') - // } - // - // const captionPath = path + video.uuid + '/captions/fr' - // await makeUploadRequest({ - // method: 'PUT', - // url: server.url, - // path: captionPath, - // token: server.accessToken, - // fields, - // attaches, - // expectedStatus: HttpStatusCode.INTERNAL_SERVER_ERROR_500 - // }) - // }) - - it('Should success with the correct parameters', async function () { - const captionPath = path + video.uuid + '/captions/fr' - await makeUploadRequest({ - method: 'PUT', - url: server.url, - path: captionPath, - token: server.accessToken, - fields, - attaches, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When listing video captions', function () { - it('Should fail without a valid uuid', async function () { - await makeGetRequest({ url: server.url, path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions' }) - }) - - it('Should fail with an unknown id', async function () { - await makeGetRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a private video without token', async function () { - await makeGetRequest({ - url: server.url, - path: path + privateVideo.shortUUID + '/captions', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another user token', async function () { - await makeGetRequest({ - url: server.url, - token: userAccessToken, - path: path + privateVideo.shortUUID + '/captions', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', expectedStatus: HttpStatusCode.OK_200 }) - - await makeGetRequest({ - url: server.url, - path: path + privateVideo.shortUUID + '/captions', - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When deleting video caption', function () { - it('Should fail without a valid uuid', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr', - token: server.accessToken - }) - }) - - it('Should fail with an unknown id', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr', - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an invalid language', async function () { - await makeDeleteRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/16', - token: server.accessToken - }) - }) - - it('Should fail with a missing language', async function () { - const captionPath = path + video.shortUUID + '/captions' - await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken }) - }) - - it('Should fail with an unknown language', async function () { - const captionPath = path + video.shortUUID + '/captions/15' - await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken }) - }) - - it('Should fail without access token', async function () { - const captionPath = path + video.shortUUID + '/captions/fr' - await makeDeleteRequest({ url: server.url, path: captionPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a bad access token', async function () { - const captionPath = path + video.shortUUID + '/captions/fr' - await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another user', async function () { - const captionPath = path + video.shortUUID + '/captions/fr' - await makeDeleteRequest({ - url: server.url, - path: captionPath, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should success with the correct parameters', async function () { - const captionPath = path + video.shortUUID + '/captions/fr' - await makeDeleteRequest({ - url: server.url, - path: captionPath, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-channel-syncs.ts b/server/tests/api/check-params/video-channel-syncs.ts deleted file mode 100644 index bcd8984df..000000000 --- a/server/tests/api/check-params/video-channel-syncs.ts +++ /dev/null @@ -1,318 +0,0 @@ -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, FIXTURE_URLS } from '@server/tests/shared' -import { HttpStatusCode, VideoChannelSyncCreate } from '@shared/models' -import { - ChannelSyncsCommand, - createSingleServer, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test video channel sync API validator', () => { - const path = '/api/v1/video-channel-syncs' - let server: PeerTubeServer - let command: ChannelSyncsCommand - let rootChannelId: number - let rootChannelSyncId: number - const userInfo = { - accessToken: '', - username: 'user1', - id: -1, - channelId: -1, - syncId: -1 - } - - async function withChannelSyncDisabled (callback: () => Promise): Promise { - try { - await server.config.disableChannelSync() - await callback() - } finally { - await server.config.enableChannelSync() - } - } - - async function withMaxSyncsPerUser (maxSync: number, callback: () => Promise): Promise { - const origConfig = await server.config.getCustomConfig() - - await server.config.updateExistingSubConfig({ - newConfig: { - import: { - videoChannelSynchronization: { - maxPerUser: maxSync - } - } - } - }) - - try { - await callback() - } finally { - await server.config.updateCustomConfig({ newCustomConfig: origConfig }) - } - } - - before(async function () { - this.timeout(30_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - command = server.channelSyncs - - rootChannelId = server.store.channel.id - - { - userInfo.accessToken = await server.users.generateUserAndToken(userInfo.username) - - const { videoChannels, id: userId } = await server.users.getMyInfo({ token: userInfo.accessToken }) - userInfo.id = userId - userInfo.channelId = videoChannels[0].id - } - - await server.config.enableChannelSync() - }) - - describe('When creating a sync', function () { - let baseCorrectParams: VideoChannelSyncCreate - - before(function () { - baseCorrectParams = { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: rootChannelId - } - }) - - it('Should fail when sync is disabled', async function () { - await withChannelSyncDisabled(async () => { - await command.create({ - token: server.accessToken, - attributes: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with no authentication', async function () { - await command.create({ - token: null, - attributes: baseCorrectParams, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail without a target url', async function () { - const attributes: VideoChannelSyncCreate = { - ...baseCorrectParams, - externalChannelUrl: null - } - await command.create({ - token: server.accessToken, - attributes, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail without a channelId', async function () { - const attributes: VideoChannelSyncCreate = { - ...baseCorrectParams, - videoChannelId: null - } - await command.create({ - token: server.accessToken, - attributes, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a channelId refering nothing', async function () { - const attributes: VideoChannelSyncCreate = { - ...baseCorrectParams, - videoChannelId: 42 - } - await command.create({ - token: server.accessToken, - attributes, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail to create a sync when the user does not own the channel', async function () { - await command.create({ - token: userInfo.accessToken, - attributes: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed to create a sync with root and for another user\'s channel', async function () { - const { videoChannelSync } = await command.create({ - token: server.accessToken, - attributes: { - ...baseCorrectParams, - videoChannelId: userInfo.channelId - }, - expectedStatus: HttpStatusCode.OK_200 - }) - userInfo.syncId = videoChannelSync.id - }) - - it('Should succeed with the correct parameters', async function () { - const { videoChannelSync } = await command.create({ - token: server.accessToken, - attributes: baseCorrectParams, - expectedStatus: HttpStatusCode.OK_200 - }) - rootChannelSyncId = videoChannelSync.id - }) - - it('Should fail when the user exceeds allowed number of synchronizations', async function () { - await withMaxSyncsPerUser(1, async () => { - await command.create({ - token: server.accessToken, - attributes: { - ...baseCorrectParams, - videoChannelId: userInfo.channelId - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - }) - - describe('When listing my channel syncs', function () { - const myPath = '/api/v1/accounts/root/video-channel-syncs' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, myPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, myPath, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, myPath, server.accessToken) - }) - - it('Should succeed with the correct parameters', async function () { - await command.listByAccount({ - accountName: 'root', - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should fail with no authentication', async function () { - await command.listByAccount({ - accountName: 'root', - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail when a simple user lists another user\'s synchronizations', async function () { - await command.listByAccount({ - accountName: 'root', - token: userInfo.accessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed when root lists another user\'s synchronizations', async function () { - await command.listByAccount({ - accountName: userInfo.username, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should succeed even with synchronization disabled', async function () { - await withChannelSyncDisabled(async function () { - await command.listByAccount({ - accountName: 'root', - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - }) - - describe('When triggering deletion', function () { - it('should fail with no authentication', async function () { - await command.delete({ - channelSyncId: userInfo.syncId, - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail when channelSyncId does not refer to any sync', async function () { - await command.delete({ - channelSyncId: 42, - token: server.accessToken, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail when sync is not owned by the user', async function () { - await command.delete({ - channelSyncId: rootChannelSyncId, - token: userInfo.accessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed when root delete a sync they do not own', async function () { - await command.delete({ - channelSyncId: userInfo.syncId, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('should succeed when user delete a sync they own', async function () { - const { videoChannelSync } = await command.create({ - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: userInfo.channelId - }, - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200 - }) - - await command.delete({ - channelSyncId: videoChannelSync.id, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should succeed even when synchronization is disabled', async function () { - await withChannelSyncDisabled(async function () { - await command.delete({ - channelSyncId: rootChannelSyncId, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - }) - - after(async function () { - await server?.kill() - }) -}) diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts deleted file mode 100644 index 1782474fd..000000000 --- a/server/tests/api/check-params/video-channels.ts +++ /dev/null @@ -1,378 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { buildAbsoluteFixturePath, omit } from '@shared/core-utils' -import { HttpStatusCode, VideoChannelUpdate } from '@shared/models' -import { - ChannelsCommand, - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - makeUploadRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test video channels API validator', function () { - const videoChannelPath = '/api/v1/video-channels' - let server: PeerTubeServer - const userInfo = { - accessToken: '', - channelName: 'fake_channel', - id: -1, - videoQuota: -1, - videoQuotaDaily: -1 - } - let command: ChannelsCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const userCreds = { - username: 'fake', - password: 'fake_password' - } - - { - const user = await server.users.create({ username: userCreds.username, password: userCreds.password }) - userInfo.id = user.id - userInfo.accessToken = await server.login.getAccessToken(userCreds) - } - - command = server.channels - }) - - describe('When listing a video channels', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, videoChannelPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, videoChannelPath, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, videoChannelPath, server.accessToken) - }) - }) - - describe('When listing account video channels', function () { - const accountChannelPath = '/api/v1/accounts/fake/video-channels' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, accountChannelPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, accountChannelPath, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, accountChannelPath, server.accessToken) - }) - - it('Should fail with a unknown account', async function () { - await server.channels.listByAccount({ accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path: accountChannelPath, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When adding a video channel', function () { - const baseCorrectParams = { - name: 'super_channel', - displayName: 'hello', - description: 'super description', - support: 'super support text' - } - - it('Should fail with a non authenticated user', async function () { - await makePostBodyRequest({ - url: server.url, - path: videoChannelPath, - token: 'none', - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail without a name', async function () { - const fields = omit(baseCorrectParams, [ 'name' ]) - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail with a bad name', async function () { - const fields = { ...baseCorrectParams, name: 'super name' } - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail without a name', async function () { - const fields = omit(baseCorrectParams, [ 'displayName' ]) - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) } - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(201) } - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePostBodyRequest({ - url: server.url, - path: videoChannelPath, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should fail when adding a channel with the same username', async function () { - await makePostBodyRequest({ - url: server.url, - path: videoChannelPath, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - }) - - describe('When updating a video channel', function () { - const baseCorrectParams: VideoChannelUpdate = { - displayName: 'hello', - description: 'super description', - support: 'toto', - bulkVideosSupportUpdate: false - } - let path: string - - before(async function () { - path = videoChannelPath + '/super_channel' - }) - - it('Should fail with a non authenticated user', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: 'hi', - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another authenticated user', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: userInfo.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) } - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(201) } - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad bulkVideosSupportUpdate field', async function () { - const fields = { ...baseCorrectParams, bulkVideosSupportUpdate: 'super' } - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should succeed with the correct parameters', async function () { - await makePutBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When updating video channel avatars/banners', function () { - const types = [ 'avatar', 'banner' ] - let path: string - - before(async function () { - path = videoChannelPath + '/super_channel' - }) - - it('Should fail with an incorrect input file', async function () { - for (const type of types) { - const fields = {} - const attaches = { - [type + 'file']: buildAbsoluteFixturePath('video_short.mp4') - } - - await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches }) - } - }) - - it('Should fail with a big file', async function () { - for (const type of types) { - const fields = {} - const attaches = { - [type + 'file']: buildAbsoluteFixturePath('avatar-big.png') - } - await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches }) - } - }) - - it('Should fail with an unauthenticated user', async function () { - for (const type of types) { - const fields = {} - const attaches = { - [type + 'file']: buildAbsoluteFixturePath('avatar.png') - } - await makeUploadRequest({ - url: server.url, - path: `${path}/${type}/pick`, - fields, - attaches, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - } - }) - - it('Should succeed with the correct params', async function () { - for (const type of types) { - const fields = {} - const attaches = { - [type + 'file']: buildAbsoluteFixturePath('avatar.png') - } - await makeUploadRequest({ - url: server.url, - path: `${path}/${type}/pick`, - token: server.accessToken, - fields, - attaches, - expectedStatus: HttpStatusCode.OK_200 - }) - } - }) - }) - - describe('When getting a video channel', function () { - it('Should return the list of the video channels with nothing', async function () { - const res = await makeGetRequest({ - url: server.url, - path: videoChannelPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.data).to.be.an('array') - }) - - it('Should return 404 with an incorrect video channel', async function () { - await makeGetRequest({ - url: server.url, - path: videoChannelPath + '/super_channel2', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeGetRequest({ - url: server.url, - path: videoChannelPath + '/super_channel', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When getting channel followers', function () { - const path = '/api/v1/video-channels/super_channel/followers' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a unauthenticated user', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a another user', async function () { - await makeGetRequest({ url: server.url, path, token: userInfo.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When deleting a video channel', function () { - it('Should fail with a non authenticated user', async function () { - await command.delete({ token: 'coucou', channelName: 'super_channel', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another authenticated user', async function () { - await command.delete({ token: userInfo.accessToken, channelName: 'super_channel', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with an unknown video channel id', async function () { - await command.delete({ channelName: 'super_channel2', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the correct parameters', async function () { - await command.delete({ channelName: 'super_channel' }) - }) - - it('Should fail to delete the last user video channel', async function () { - await command.delete({ channelName: 'root_channel', expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts deleted file mode 100644 index 9f497c0cf..000000000 --- a/server/tests/api/check-params/video-comments.ts +++ /dev/null @@ -1,484 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test video comments API validator', function () { - let pathThread: string - let pathComment: string - - let server: PeerTubeServer - - let video: VideoCreateResult - - let userAccessToken: string - let userAccessToken2: string - - let commentId: number - let privateCommentId: number - let privateVideo: VideoCreateResult - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - { - video = await server.videos.upload({ attributes: {} }) - pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads' - } - - { - privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } }) - } - - { - const created = await server.comments.createThread({ videoId: video.uuid, text: 'coucou' }) - commentId = created.id - pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId - } - - { - const created = await server.comments.createThread({ videoId: privateVideo.uuid, text: 'coucou' }) - privateCommentId = created.id - } - - { - const user = { username: 'user1', password: 'my super password' } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - } - - { - const user = { username: 'user2', password: 'my super password' } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken2 = await server.login.getAccessToken(user) - } - }) - - describe('When listing video comment threads', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, pathThread, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, pathThread, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, pathThread, server.accessToken) - }) - - it('Should fail with an incorrect video', async function () { - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a private video without token', async function () { - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another user token', async function () { - await makeGetRequest({ - url: server.url, - token: userAccessToken, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When listing comments of a thread', function () { - it('Should fail with an incorrect video', async function () { - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads/' + commentId, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an incorrect thread id', async function () { - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/156', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a private video without token', async function () { - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another user token', async function () { - await makeGetRequest({ - url: server.url, - token: userAccessToken, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should success with the correct params', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId, - expectedStatus: HttpStatusCode.OK_200 - }) - - await makeGetRequest({ - url: server.url, - path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/' + commentId, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When adding a video thread', function () { - - it('Should fail with a non authenticated user', async function () { - const fields = { - text: 'text' - } - await makePostBodyRequest({ - url: server.url, - path: pathThread, - token: 'none', - fields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields }) - }) - - it('Should fail with a short comment', async function () { - const fields = { - text: '' - } - await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields }) - }) - - it('Should fail with a long comment', async function () { - const fields = { - text: 'h'.repeat(10001) - } - await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect video', async function () { - const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads' - const fields = { text: 'super comment' } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a private video of another user', async function () { - const fields = { text: 'super comment' } - - await makePostBodyRequest({ - url: server.url, - path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads', - token: userAccessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct parameters', async function () { - const fields = { text: 'super comment' } - - await makePostBodyRequest({ - url: server.url, - path: pathThread, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When adding a comment to a thread', function () { - - it('Should fail with a non authenticated user', async function () { - const fields = { - text: 'text' - } - await makePostBodyRequest({ - url: server.url, - path: pathComment, - token: 'none', - fields, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields }) - }) - - it('Should fail with a short comment', async function () { - const fields = { - text: '' - } - await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields }) - }) - - it('Should fail with a long comment', async function () { - const fields = { - text: 'h'.repeat(10001) - } - await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect video', async function () { - const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId - const fields = { - text: 'super comment' - } - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a private video of another user', async function () { - const fields = { text: 'super comment' } - - await makePostBodyRequest({ - url: server.url, - path: '/api/v1/videos/' + privateVideo.uuid + '/comments/' + privateCommentId, - token: userAccessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an incorrect comment', async function () { - const path = '/api/v1/videos/' + video.uuid + '/comments/124' - const fields = { - text: 'super comment' - } - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should succeed with the correct parameters', async function () { - const fields = { - text: 'super comment' - } - await makePostBodyRequest({ - url: server.url, - path: pathComment, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When removing video comments', function () { - it('Should fail with a non authenticated user', async function () { - await makeDeleteRequest({ url: server.url, path: pathComment, token: 'none', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another user', async function () { - await makeDeleteRequest({ - url: server.url, - path: pathComment, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an incorrect video', async function () { - const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId - await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an incorrect comment', async function () { - const path = '/api/v1/videos/' + video.uuid + '/comments/124' - await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with the same user', async function () { - let commentToDelete: number - - { - const created = await server.comments.createThread({ videoId: video.uuid, token: userAccessToken, text: 'hello' }) - commentToDelete = created.id - } - - const path = '/api/v1/videos/' + video.uuid + '/comments/' + commentToDelete - - await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - }) - - it('Should succeed with the owner of the video', async function () { - let commentToDelete: number - let anotherVideoUUID: string - - { - const { uuid } = await server.videos.upload({ token: userAccessToken, attributes: { name: 'video' } }) - anotherVideoUUID = uuid - } - - { - const created = await server.comments.createThread({ videoId: anotherVideoUUID, text: 'hello' }) - commentToDelete = created.id - } - - const path = '/api/v1/videos/' + anotherVideoUUID + '/comments/' + commentToDelete - - await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeDeleteRequest({ - url: server.url, - path: pathComment, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When a video has comments disabled', function () { - before(async function () { - video = await server.videos.upload({ attributes: { commentsEnabled: false } }) - pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads' - }) - - it('Should return an empty thread list', async function () { - const res = await makeGetRequest({ - url: server.url, - path: pathThread, - expectedStatus: HttpStatusCode.OK_200 - }) - expect(res.body.total).to.equal(0) - expect(res.body.data).to.have.lengthOf(0) - }) - - it('Should return an thread comments list') - - it('Should return conflict on thread add', async function () { - const fields = { - text: 'super comment' - } - await makePostBodyRequest({ - url: server.url, - path: pathThread, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should return conflict on comment thread add') - }) - - describe('When listing admin comments threads', function () { - const path = '/api/v1/videos/comments' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a non authenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a non admin user', async function () { - await makeGetRequest({ - url: server.url, - path, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - path, - token: server.accessToken, - query: { - isLocal: false, - search: 'toto', - searchAccount: 'toto', - searchVideo: 'toto' - }, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-files.ts b/server/tests/api/check-params/video-files.ts deleted file mode 100644 index 01d6a912b..000000000 --- a/server/tests/api/check-params/video-files.ts +++ /dev/null @@ -1,195 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { getAllFiles } from '@shared/core-utils' -import { HttpStatusCode, UserRole, VideoDetails, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeRawRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test videos files', function () { - let servers: PeerTubeServer[] - - let userToken: string - let moderatorToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(300_000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER) - moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR) - }) - - describe('Getting metadata', function () { - let video: VideoDetails - - before(async function () { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - video = await servers[0].videos.getWithToken({ id: uuid }) - }) - - it('Should not get metadata of private video without token', async function () { - for (const file of getAllFiles(video)) { - await makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - } - }) - - it('Should not get metadata of private video without the appropriate token', async function () { - for (const file of getAllFiles(video)) { - await makeRawRequest({ url: file.metadataUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - } - }) - - it('Should get metadata of private video with the appropriate token', async function () { - for (const file of getAllFiles(video)) { - await makeRawRequest({ url: file.metadataUrl, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - }) - - describe('Deleting files', function () { - let webVideoId: string - let hlsId: string - let remoteId: string - - let validId1: string - let validId2: string - - let hlsFileId: number - let webVideoFileId: number - - let remoteHLSFileId: number - let remoteWebVideoFileId: number - - before(async function () { - this.timeout(300_000) - - { - const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) - await waitJobs(servers) - - const video = await servers[1].videos.get({ id: uuid }) - remoteId = video.uuid - remoteHLSFileId = video.streamingPlaylists[0].files[0].id - remoteWebVideoFileId = video.files[0].id - } - - { - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - validId1 = video.uuid - hlsFileId = video.streamingPlaylists[0].files[0].id - webVideoFileId = video.files[0].id - } - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' }) - validId2 = uuid - } - } - - await waitJobs(servers) - - { - await servers[0].config.enableTranscoding({ hls: true, webVideo: false }) - const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) - hlsId = uuid - } - - await waitJobs(servers) - - { - await servers[0].config.enableTranscoding({ webVideo: true, hls: false }) - const { uuid } = await servers[0].videos.quickUpload({ name: 'web-video' }) - webVideoId = uuid - } - - await waitJobs(servers) - }) - - it('Should not delete files of a unknown video', async function () { - const expectedStatus = HttpStatusCode.NOT_FOUND_404 - - await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: 404, expectedStatus }) - - await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus }) - await servers[0].videos.removeWebVideoFile({ videoId: 404, fileId: webVideoFileId, expectedStatus }) - }) - - it('Should not delete unknown files', async function () { - const expectedStatus = HttpStatusCode.NOT_FOUND_404 - - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webVideoFileId, expectedStatus }) - await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: hlsFileId, expectedStatus }) - }) - - it('Should not delete files of a remote video', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - - await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: remoteId, expectedStatus }) - - await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus }) - await servers[0].videos.removeWebVideoFile({ videoId: remoteId, fileId: remoteWebVideoFileId, expectedStatus }) - }) - - it('Should not delete files by a non admin user', async function () { - const expectedStatus = HttpStatusCode.FORBIDDEN_403 - - await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus }) - await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus }) - - await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: userToken, expectedStatus }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: moderatorToken, expectedStatus }) - - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus }) - - await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: userToken, expectedStatus }) - await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: moderatorToken, expectedStatus }) - }) - - it('Should not delete files if the files are not available', async function () { - await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should not delete files if no both versions are available', async function () { - await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should delete files if both versions are available', async function () { - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId }) - await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId }) - - await servers[0].videos.removeHLSPlaylist({ videoId: validId1 }) - await servers[0].videos.removeAllWebVideoFiles({ videoId: validId2 }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts deleted file mode 100644 index 8c6f43c12..000000000 --- a/server/tests/api/check-params/video-imports.ts +++ /dev/null @@ -1,431 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, FIXTURE_URLS } from '@server/tests/shared' -import { buildAbsoluteFixturePath, omit } from '@shared/core-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - makeUploadRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test video imports API validator', function () { - const path = '/api/v1/videos/imports' - let server: PeerTubeServer - let userAccessToken = '' - let channelId: number - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - const username = 'user1' - const password = 'my super password' - await server.users.create({ username, password }) - userAccessToken = await server.login.getAccessToken({ username, password }) - - { - const { videoChannels } = await server.users.getMyInfo() - channelId = videoChannels[0].id - } - }) - - describe('When listing my video imports', function () { - const myPath = '/api/v1/users/me/videos/imports' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, myPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, myPath, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, myPath, server.accessToken) - }) - - it('Should fail with a bad videoChannelSyncId param', async function () { - await makeGetRequest({ - url: server.url, - path: myPath, - query: { videoChannelSyncId: 'toto' }, - token: server.accessToken - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path: myPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken }) - }) - }) - - describe('When adding a video import', function () { - let baseCorrectParams - - before(function () { - baseCorrectParams = { - targetUrl: FIXTURE_URLS.goodVideo, - name: 'my super name', - category: 5, - licence: 1, - language: 'pt', - nsfw: false, - commentsEnabled: true, - downloadEnabled: true, - waitTranscoding: true, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag1', 'tag2' ], - privacy: VideoPrivacy.PUBLIC, - channelId - } - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail without a target url', async function () { - const fields = omit(baseCorrectParams, [ 'targetUrl' ]) - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad target url', async function () { - const fields = { ...baseCorrectParams, targetUrl: 'htt://hello' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with localhost', async function () { - const fields = { ...baseCorrectParams, targetUrl: 'http://localhost:8000' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a private IP target urls', async function () { - const targetUrls = [ - 'http://127.0.0.1:8000', - 'http://127.0.0.1', - 'http://127.0.0.1/hello', - 'https://192.168.1.42', - 'http://192.168.1.42', - 'http://127.0.0.1.cpy.re' - ] - - for (const targetUrl of targetUrls) { - const fields = { ...baseCorrectParams, targetUrl } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad category', async function () { - const fields = { ...baseCorrectParams, category: 125 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad licence', async function () { - const fields = { ...baseCorrectParams, licence: 125 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad language', async function () { - const fields = { ...baseCorrectParams, language: 'a'.repeat(15) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail without a channel', async function () { - const fields = omit(baseCorrectParams, [ 'channelId' ]) - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a bad channel', async function () { - const fields = { ...baseCorrectParams, channelId: 545454 } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with another user channel', async function () { - const user = { - username: 'fake', - password: 'fake_password' - } - await server.users.create({ username: user.username, password: user.password }) - - const accessTokenUser = await server.login.getAccessToken(user) - const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser }) - const customChannelId = videoChannels[0].id - - const fields = { ...baseCorrectParams, channelId: customChannelId } - - await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields }) - }) - - it('Should fail with too many tags', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too low', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too big', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: buildAbsoluteFixturePath('video_short.mp4') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with a big thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with an incorrect preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: buildAbsoluteFixturePath('video_short.mp4') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with a big preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: buildAbsoluteFixturePath('custom-preview-big.png') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with an invalid torrent file', async function () { - const fields = omit(baseCorrectParams, [ 'targetUrl' ]) - const attaches = { - torrentfile: buildAbsoluteFixturePath('avatar-big.png') - } - - await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) - }) - - it('Should fail with an invalid magnet URI', async function () { - let fields = omit(baseCorrectParams, [ 'targetUrl' ]) - fields = { ...fields, magnetUri: 'blabla' } - - await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should succeed with the correct parameters', async function () { - this.timeout(120000) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should forbid to import http videos', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - import: { - videos: { - http: { - enabled: false - }, - torrent: { - enabled: true - } - } - } - } - }) - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields: baseCorrectParams, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - - it('Should forbid to import torrent videos', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - import: { - videos: { - http: { - enabled: true - }, - torrent: { - enabled: false - } - } - } - } - }) - - let fields = omit(baseCorrectParams, [ 'targetUrl' ]) - fields = { ...fields, magnetUri: FIXTURE_URLS.magnet } - - await makePostBodyRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - - fields = omit(fields, [ 'magnetUri' ]) - const attaches = { - torrentfile: buildAbsoluteFixturePath('video-720p.torrent') - } - - await makeUploadRequest({ - url: server.url, - path, - token: server.accessToken, - fields, - attaches, - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - }) - }) - - describe('Deleting/cancelling a video import', function () { - let importId: number - - async function importVideo () { - const attributes = { channelId: server.store.channel.id, targetUrl: FIXTURE_URLS.goodVideo } - const res = await server.imports.importVideo({ attributes }) - - return res.id - } - - before(async function () { - importId = await importVideo() - }) - - it('Should fail with an invalid import id', async function () { - await server.imports.cancel({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.imports.delete({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown import id', async function () { - await server.imports.cancel({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await server.imports.delete({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail without token', async function () { - await server.imports.cancel({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await server.imports.delete({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another user token', async function () { - await server.imports.cancel({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await server.imports.delete({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail to cancel non pending import', async function () { - this.timeout(60000) - - await waitJobs([ server ]) - - await server.imports.cancel({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should succeed to delete an import', async function () { - await server.imports.delete({ importId }) - }) - - it('Should fail to delete a pending import', async function () { - await server.jobs.pauseJobQueue() - - importId = await importVideo() - - await server.imports.delete({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should succeed to cancel an import', async function () { - importId = await importVideo() - - await server.imports.cancel({ importId }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-passwords.ts b/server/tests/api/check-params/video-passwords.ts deleted file mode 100644 index 50b0bacb3..000000000 --- a/server/tests/api/check-params/video-passwords.ts +++ /dev/null @@ -1,609 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { - FIXTURE_URLS, - checkBadCountPagination, - checkBadSortPagination, - checkBadStartPagination, - checkUploadVideoParam -} from '@server/tests/shared' -import { root } from '@shared/core-utils' -import { - HttpStatusCode, - PeerTubeProblemDocument, - ServerErrorCode, - VideoCreateResult, - VideoPrivacy -} from '@shared/models' -import { - cleanupTests, - createSingleServer, - makePostBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' -import { expect } from 'chai' -import { join } from 'path' - -describe('Test video passwords validator', function () { - let path: string - let server: PeerTubeServer - let userAccessToken = '' - let video: VideoCreateResult - let channelId: number - let publicVideo: VideoCreateResult - let commentId: number - // --------------------------------------------------------------- - - before(async function () { - this.timeout(50000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - latencySetting: { - enabled: false - }, - allowReplay: false - }, - import: { - videos: { - http:{ - enabled: true - } - } - } - } - }) - - userAccessToken = await server.users.generateUserAndToken('user1') - - { - const body = await server.users.getMyInfo() - channelId = body.videoChannels[0].id - } - - { - video = await server.videos.quickUpload({ - name: 'password protected video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ 'password1', 'password2' ] - }) - } - path = '/api/v1/videos/' - }) - - async function checkVideoPasswordOptions (options: { - server: PeerTubeServer - token: string - videoPasswords: string[] - expectedStatus: HttpStatusCode - mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live' - }) { - const { server, token, videoPasswords, expectedStatus = HttpStatusCode.OK_200, mode } = options - const attaches = { - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') - } - const baseCorrectParams = { - name: 'my super name', - category: 5, - licence: 1, - language: 'pt', - nsfw: false, - commentsEnabled: true, - downloadEnabled: true, - waitTranscoding: true, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag1', 'tag2' ], - privacy: VideoPrivacy.PASSWORD_PROTECTED, - channelId, - originallyPublishedAt: new Date().toISOString() - } - if (mode === 'uploadLegacy') { - const fields = { ...baseCorrectParams, videoPasswords } - return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'legacy' }) - } - - if (mode === 'uploadResumable') { - const fields = { ...baseCorrectParams, videoPasswords } - return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'resumable' }) - } - - if (mode === 'import') { - const attributes = { ...baseCorrectParams, targetUrl: FIXTURE_URLS.goodVideo, videoPasswords } - return server.imports.importVideo({ attributes, expectedStatus }) - } - - if (mode === 'updateVideo') { - const attributes = { ...baseCorrectParams, videoPasswords } - return server.videos.update({ token, expectedStatus, id: video.id, attributes }) - } - - if (mode === 'updatePasswords') { - return server.videoPasswords.updateAll({ token, expectedStatus, videoId: video.id, passwords: videoPasswords }) - } - - if (mode === 'live') { - const fields = { ...baseCorrectParams, videoPasswords } - - return server.live.create({ fields, expectedStatus }) - } - } - - function validateVideoPasswordList (mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live') { - - it('Should fail with a password protected privacy without providing a password', async function () { - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords: undefined, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - it('Should fail with a password protected privacy and an empty password list', async function () { - const videoPasswords = [] - - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - it('Should fail with a password protected privacy and a too short password', async function () { - const videoPasswords = [ 'p' ] - - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - it('Should fail with a password protected privacy and a too long password', async function () { - const videoPasswords = [ 'Very very very very very very very very very very very very very very very very very very long password' ] - - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - it('Should fail with a password protected privacy and an empty password', async function () { - const videoPasswords = [ '' ] - - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - it('Should fail with a password protected privacy and duplicated passwords', async function () { - const videoPasswords = [ 'password', 'password' ] - - await checkVideoPasswordOptions({ - server, - token: server.accessToken, - videoPasswords, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - }) - }) - - if (mode === 'updatePasswords') { - it('Should fail for an unauthenticated user', async function () { - const videoPasswords = [ 'password' ] - await checkVideoPasswordOptions({ - server, - token: null, - videoPasswords, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401, - mode - }) - }) - - it('Should fail for an unauthorized user', async function () { - const videoPasswords = [ 'password' ] - await checkVideoPasswordOptions({ - server, - token: userAccessToken, - videoPasswords, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - mode - }) - }) - } - - it('Should succeed with a password protected privacy and correct passwords', async function () { - const videoPasswords = [ 'password1', 'password2' ] - const expectedStatus = mode === 'updatePasswords' || mode === 'updateVideo' - ? HttpStatusCode.NO_CONTENT_204 - : HttpStatusCode.OK_200 - - await checkVideoPasswordOptions({ server, token: server.accessToken, videoPasswords, expectedStatus, mode }) - }) - } - - describe('When adding or updating a video', function () { - describe('Resumable upload', function () { - validateVideoPasswordList('uploadResumable') - }) - - describe('Legacy upload', function () { - validateVideoPasswordList('uploadLegacy') - }) - - describe('When importing a video', function () { - validateVideoPasswordList('import') - }) - - describe('When updating a video', function () { - validateVideoPasswordList('updateVideo') - }) - - describe('When updating the password list of a video', function () { - validateVideoPasswordList('updatePasswords') - }) - - describe('When creating a live', function () { - validateVideoPasswordList('live') - }) - }) - - async function checkVideoAccessOptions (options: { - server: PeerTubeServer - token?: string - videoPassword?: string - expectedStatus: HttpStatusCode - mode: 'get' | 'getWithPassword' | 'getWithToken' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token' - }) { - const { server, token = null, videoPassword, expectedStatus, mode } = options - - if (mode === 'get') { - return server.videos.get({ id: video.id, expectedStatus }) - } - - if (mode === 'getWithToken') { - return server.videos.getWithToken({ - id: video.id, - token, - expectedStatus - }) - } - - if (mode === 'getWithPassword') { - return server.videos.getWithPassword({ - id: video.id, - token, - expectedStatus, - password: videoPassword - }) - } - - if (mode === 'rate') { - return server.videos.rate({ - id: video.id, - token, - expectedStatus, - rating: 'like', - videoPassword - }) - } - - if (mode === 'createThread') { - const fields = { text: 'super comment' } - const headers = videoPassword !== undefined && videoPassword !== null - ? { 'x-peertube-video-password': videoPassword } - : undefined - const body = await makePostBodyRequest({ - url: server.url, - path: path + video.uuid + '/comment-threads', - token, - fields, - headers, - expectedStatus - }) - return JSON.parse(body.text) - } - - if (mode === 'replyThread') { - const fields = { text: 'super reply' } - const headers = videoPassword !== undefined && videoPassword !== null - ? { 'x-peertube-video-password': videoPassword } - : undefined - return makePostBodyRequest({ - url: server.url, - path: path + video.uuid + '/comments/' + commentId, - token, - fields, - headers, - expectedStatus - }) - } - if (mode === 'listThreads') { - return server.comments.listThreads({ - videoId: video.id, - token, - expectedStatus, - videoPassword - }) - } - - if (mode === 'listCaptions') { - return server.captions.list({ - videoId: video.id, - token, - expectedStatus, - videoPassword - }) - } - - if (mode === 'token') { - return server.videoToken.create({ - videoId: video.id, - token, - expectedStatus, - videoPassword - }) - } - } - - function checkVideoError (error: any, mode: 'providePassword' | 'incorrectPassword') { - const serverCode = mode === 'providePassword' - ? ServerErrorCode.VIDEO_REQUIRES_PASSWORD - : ServerErrorCode.INCORRECT_VIDEO_PASSWORD - - const message = mode === 'providePassword' - ? 'Please provide a password to access this password protected video' - : 'Incorrect video password. Access to the video is denied.' - - if (!error.code) { - error = JSON.parse(error.text) - } - - expect(error.code).to.equal(serverCode) - expect(error.detail).to.equal(message) - expect(error.error).to.equal(message) - - expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403) - } - - function validateVideoAccess (mode: 'get' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token') { - const requiresUserAuth = [ 'createThread', 'replyThread', 'rate' ].includes(mode) - let tokens: string[] - if (!requiresUserAuth) { - it('Should fail without providing a password for an unlogged user', async function () { - const body = await checkVideoAccessOptions({ server, expectedStatus: HttpStatusCode.FORBIDDEN_403, mode }) - const error = body as unknown as PeerTubeProblemDocument - - checkVideoError(error, 'providePassword') - }) - } - - it('Should fail without providing a password for an unauthorised user', async function () { - const tmp = mode === 'get' ? 'getWithToken' : mode - - const body = await checkVideoAccessOptions({ - server, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - mode: tmp - }) - - const error = body as unknown as PeerTubeProblemDocument - - checkVideoError(error, 'providePassword') - }) - - it('Should fail if a wrong password is entered', async function () { - const tmp = mode === 'get' ? 'getWithPassword' : mode - tokens = [ userAccessToken, server.accessToken ] - - if (!requiresUserAuth) tokens.push(null) - - for (const token of tokens) { - const body = await checkVideoAccessOptions({ - server, - token, - videoPassword: 'toto', - expectedStatus: HttpStatusCode.FORBIDDEN_403, - mode: tmp - }) - const error = body as unknown as PeerTubeProblemDocument - - checkVideoError(error, 'incorrectPassword') - } - }) - - it('Should fail if an empty password is entered', async function () { - const tmp = mode === 'get' ? 'getWithPassword' : mode - - for (const token of tokens) { - const body = await checkVideoAccessOptions({ - server, - token, - videoPassword: '', - expectedStatus: HttpStatusCode.FORBIDDEN_403, - mode: tmp - }) - const error = body as unknown as PeerTubeProblemDocument - - checkVideoError(error, 'incorrectPassword') - } - }) - - it('Should fail if an inccorect password containing the correct password is entered', async function () { - const tmp = mode === 'get' ? 'getWithPassword' : mode - - for (const token of tokens) { - const body = await checkVideoAccessOptions({ - server, - token, - videoPassword: 'password11', - expectedStatus: HttpStatusCode.FORBIDDEN_403, - mode: tmp - }) - const error = body as unknown as PeerTubeProblemDocument - - checkVideoError(error, 'incorrectPassword') - } - }) - - it('Should succeed without providing a password for an authorised user', async function () { - const tmp = mode === 'get' ? 'getWithToken' : mode - const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200 - - const body = await checkVideoAccessOptions({ server, token: server.accessToken, expectedStatus, mode: tmp }) - - if (mode === 'createThread') commentId = body.comment.id - }) - - it('Should succeed using correct passwords', async function () { - const tmp = mode === 'get' ? 'getWithPassword' : mode - const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200 - - for (const token of tokens) { - await checkVideoAccessOptions({ server, videoPassword: 'password1', token, expectedStatus, mode: tmp }) - await checkVideoAccessOptions({ server, videoPassword: 'password2', token, expectedStatus, mode: tmp }) - } - }) - } - - describe('When accessing password protected video', function () { - - describe('For getting a password protected video', function () { - validateVideoAccess('get') - }) - - describe('For rating a video', function () { - validateVideoAccess('rate') - }) - - describe('For creating a thread', function () { - validateVideoAccess('createThread') - }) - - describe('For replying to a thread', function () { - validateVideoAccess('replyThread') - }) - - describe('For listing threads', function () { - validateVideoAccess('listThreads') - }) - - describe('For getting captions', function () { - validateVideoAccess('listCaptions') - }) - - describe('For creating video file token', function () { - validateVideoAccess('token') - }) - }) - - describe('When listing passwords', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path + video.uuid + '/passwords', server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path + video.uuid + '/passwords', server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path + video.uuid + '/passwords', server.accessToken) - }) - - it('Should fail for unauthenticated user', async function () { - await server.videoPasswords.list({ - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401, - videoId: video.id - }) - }) - - it('Should fail for unauthorized user', async function () { - await server.videoPasswords.list({ - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - videoId: video.id - }) - }) - - it('Should succeed with the correct parameters', async function () { - await server.videoPasswords.list({ - token: server.accessToken, - expectedStatus: HttpStatusCode.OK_200, - videoId: video.id - }) - }) - }) - - describe('When deleting a password', async function () { - const passwords = (await server.videoPasswords.list({ videoId: video.id })).data - - it('Should fail with wrong password id', async function () { - await server.videoPasswords.remove({ id: -1, videoId: video.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail for unauthenticated user', async function () { - await server.videoPasswords.remove({ - id: passwords[0].id, - token: null, - videoId: video.id, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail for unauthorized user', async function () { - await server.videoPasswords.remove({ - id: passwords[0].id, - token: userAccessToken, - videoId: video.id, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail for non password protected video', async function () { - publicVideo = await server.videos.quickUpload({ name: 'public video' }) - await server.videoPasswords.remove({ id: passwords[0].id, videoId: publicVideo.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail for password not linked to correct video', async function () { - const video2 = await server.videos.quickUpload({ - name: 'password protected video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ 'password1', 'password2' ] - }) - await server.videoPasswords.remove({ id: passwords[0].id, videoId: video2.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should succeed with correct parameter', async function () { - await server.videoPasswords.remove({ id: passwords[0].id, videoId: video.id, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - }) - - it('Should fail for last password of a video', async function () { - await server.videoPasswords.remove({ id: passwords[1].id, videoId: video.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts deleted file mode 100644 index 8c3233e0b..000000000 --- a/server/tests/api/check-params/video-playlists.ts +++ /dev/null @@ -1,695 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' -import { - HttpStatusCode, - VideoPlaylistCreate, - VideoPlaylistCreateResult, - VideoPlaylistElementCreate, - VideoPlaylistElementUpdate, - VideoPlaylistPrivacy, - VideoPlaylistReorder, - VideoPlaylistType -} from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - PlaylistsCommand, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test video playlists API validator', function () { - let server: PeerTubeServer - let userAccessToken: string - - let playlist: VideoPlaylistCreateResult - let privatePlaylistUUID: string - - let watchLaterPlaylistId: number - let videoId: number - let elementId: number - - let command: PlaylistsCommand - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - userAccessToken = await server.users.generateUserAndToken('user1') - videoId = (await server.videos.quickUpload({ name: 'video 1' })).id - - command = server.playlists - - { - const { data } = await command.listByAccount({ - token: server.accessToken, - handle: 'root', - start: 0, - count: 5, - playlistType: VideoPlaylistType.WATCH_LATER - }) - watchLaterPlaylistId = data[0].id - } - - { - playlist = await command.create({ - attributes: { - displayName: 'super playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id - } - }) - } - - { - const created = await command.create({ - attributes: { - displayName: 'private', - privacy: VideoPlaylistPrivacy.PRIVATE - } - }) - privatePlaylistUUID = created.uuid - } - }) - - describe('When listing playlists', function () { - const globalPath = '/api/v1/video-playlists' - const accountPath = '/api/v1/accounts/root/video-playlists' - const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, globalPath, server.accessToken) - await checkBadStartPagination(server.url, accountPath, server.accessToken) - await checkBadStartPagination(server.url, videoChannelPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, globalPath, server.accessToken) - await checkBadCountPagination(server.url, accountPath, server.accessToken) - await checkBadCountPagination(server.url, videoChannelPath, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, globalPath, server.accessToken) - await checkBadSortPagination(server.url, accountPath, server.accessToken) - await checkBadSortPagination(server.url, videoChannelPath, server.accessToken) - }) - - it('Should fail with a bad playlist type', async function () { - await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } }) - await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } }) - await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } }) - }) - - it('Should fail with a bad account parameter', async function () { - const accountPath = '/api/v1/accounts/root2/video-playlists' - - await makeGetRequest({ - url: server.url, - path: accountPath, - expectedStatus: HttpStatusCode.NOT_FOUND_404, - token: server.accessToken - }) - }) - - it('Should fail with a bad video channel parameter', async function () { - const accountPath = '/api/v1/video-channels/bad_channel/video-playlists' - - await makeGetRequest({ - url: server.url, - path: accountPath, - expectedStatus: HttpStatusCode.NOT_FOUND_404, - token: server.accessToken - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path: globalPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken }) - await makeGetRequest({ url: server.url, path: accountPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken }) - await makeGetRequest({ - url: server.url, - path: videoChannelPath, - expectedStatus: HttpStatusCode.OK_200, - token: server.accessToken - }) - }) - }) - - describe('When listing videos of a playlist', function () { - const path = '/api/v1/video-playlists/' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When getting a video playlist', function () { - it('Should fail with a bad id or uuid', async function () { - await command.get({ playlistId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an unknown playlist', async function () { - await command.get({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail to get an unlisted playlist with the number id', async function () { - const playlist = await command.create({ - attributes: { - displayName: 'super playlist', - videoChannelId: server.store.channel.id, - privacy: VideoPlaylistPrivacy.UNLISTED - } - }) - - await command.get({ playlistId: playlist.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should succeed with the correct params', async function () { - await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When creating/updating a video playlist', function () { - const getBase = ( - attributes?: Partial, - wrapper?: Partial[0]> - ) => { - return { - attributes: { - displayName: 'display name', - privacy: VideoPlaylistPrivacy.UNLISTED, - thumbnailfile: 'custom-thumbnail.jpg', - videoChannelId: server.store.channel.id, - - ...attributes - }, - - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - - ...wrapper - } - } - const getUpdate = (params: any, playlistId: number | string) => { - return { ...params, playlistId } - } - - it('Should fail with an unauthenticated user', async function () { - const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail without displayName', async function () { - const params = getBase({ displayName: undefined }) - - await command.create(params) - }) - - it('Should fail with an incorrect display name', async function () { - const params = getBase({ displayName: 's'.repeat(300) }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail with an incorrect description', async function () { - const params = getBase({ description: 't' }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail with an incorrect privacy', async function () { - const params = getBase({ privacy: 45 as any }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail with an unknown video channel id', async function () { - const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail with an incorrect thumbnail file', async function () { - const params = getBase({ thumbnailfile: 'video_short.mp4' }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail with a thumbnail file too big', async function () { - const params = getBase({ thumbnailfile: 'custom-preview-big.png' }) - - await command.create(params) - await command.update(getUpdate(params, playlist.shortUUID)) - }) - - it('Should fail to set "public" a playlist not assigned to a channel', async function () { - const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined }) - const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' as any }) - const params3 = getBase({ privacy: undefined, videoChannelId: 'null' as any }) - - await command.create(params) - await command.create(params2) - await command.update(getUpdate(params, privatePlaylistUUID)) - await command.update(getUpdate(params2, playlist.shortUUID)) - await command.update(getUpdate(params3, playlist.shortUUID)) - }) - - it('Should fail with an unknown playlist to update', async function () { - await command.update(getUpdate( - getBase({}, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }), - 42 - )) - }) - - it('Should fail to update a playlist of another user', async function () { - await command.update(getUpdate( - getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }), - playlist.shortUUID - )) - }) - - it('Should fail to update the watch later playlist', async function () { - await command.update(getUpdate( - getBase({}, { expectedStatus: HttpStatusCode.BAD_REQUEST_400 }), - watchLaterPlaylistId - )) - }) - - it('Should succeed with the correct params', async function () { - { - const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 }) - await command.create(params) - } - - { - const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - await command.update(getUpdate(params, playlist.shortUUID)) - } - }) - }) - - describe('When adding an element in a playlist', function () { - const getBase = ( - attributes?: Partial, - wrapper?: Partial[0]> - ) => { - return { - attributes: { - videoId, - startTimestamp: 2, - stopTimestamp: 3, - - ...attributes - }, - - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - playlistId: playlist.id, - - ...wrapper - } - } - - it('Should fail with an unauthenticated user', async function () { - const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await command.addElement(params) - }) - - it('Should fail with the playlist of another user', async function () { - const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await command.addElement(params) - }) - - it('Should fail with an unknown or incorrect playlist id', async function () { - { - const params = getBase({}, { playlistId: 'toto' }) - await command.addElement(params) - } - - { - const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.addElement(params) - } - }) - - it('Should fail with an unknown or incorrect video id', async function () { - const params = getBase({ videoId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.addElement(params) - }) - - it('Should fail with a bad start/stop timestamp', async function () { - { - const params = getBase({ startTimestamp: -42 }) - await command.addElement(params) - } - - { - const params = getBase({ stopTimestamp: 'toto' as any }) - await command.addElement(params) - } - }) - - it('Succeed with the correct params', async function () { - const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 }) - const created = await command.addElement(params) - elementId = created.id - }) - }) - - describe('When updating an element in a playlist', function () { - const getBase = ( - attributes?: Partial, - wrapper?: Partial[0]> - ) => { - return { - attributes: { - startTimestamp: 1, - stopTimestamp: 2, - - ...attributes - }, - - elementId, - playlistId: playlist.id, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - - ...wrapper - } - } - - it('Should fail with an unauthenticated user', async function () { - const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await command.updateElement(params) - }) - - it('Should fail with the playlist of another user', async function () { - const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await command.updateElement(params) - }) - - it('Should fail with an unknown or incorrect playlist id', async function () { - { - const params = getBase({}, { playlistId: 'toto' }) - await command.updateElement(params) - } - - { - const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.updateElement(params) - } - }) - - it('Should fail with an unknown or incorrect playlistElement id', async function () { - { - const params = getBase({}, { elementId: 'toto' }) - await command.updateElement(params) - } - - { - const params = getBase({}, { elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.updateElement(params) - } - }) - - it('Should fail with a bad start/stop timestamp', async function () { - { - const params = getBase({ startTimestamp: 'toto' as any }) - await command.updateElement(params) - } - - { - const params = getBase({ stopTimestamp: -42 }) - await command.updateElement(params) - } - }) - - it('Should fail with an unknown element', async function () { - const params = getBase({}, { elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.updateElement(params) - }) - - it('Succeed with the correct params', async function () { - const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - await command.updateElement(params) - }) - }) - - describe('When reordering elements of a playlist', function () { - let videoId3: number - let videoId4: number - - const getBase = ( - attributes?: Partial, - wrapper?: Partial[0]> - ) => { - return { - attributes: { - startPosition: 1, - insertAfterPosition: 2, - reorderLength: 3, - - ...attributes - }, - - playlistId: playlist.shortUUID, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - - ...wrapper - } - } - - before(async function () { - videoId3 = (await server.videos.quickUpload({ name: 'video 3' })).id - videoId4 = (await server.videos.quickUpload({ name: 'video 4' })).id - - for (const id of [ videoId3, videoId4 ]) { - await command.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: id } }) - } - }) - - it('Should fail with an unauthenticated user', async function () { - const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await command.reorderElements(params) - }) - - it('Should fail with the playlist of another user', async function () { - const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await command.reorderElements(params) - }) - - it('Should fail with an invalid playlist', async function () { - { - const params = getBase({}, { playlistId: 'toto' }) - await command.reorderElements(params) - } - - { - const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.reorderElements(params) - } - }) - - it('Should fail with an invalid start position', async function () { - { - const params = getBase({ startPosition: -1 }) - await command.reorderElements(params) - } - - { - const params = getBase({ startPosition: 'toto' as any }) - await command.reorderElements(params) - } - - { - const params = getBase({ startPosition: 42 }) - await command.reorderElements(params) - } - }) - - it('Should fail with an invalid insert after position', async function () { - { - const params = getBase({ insertAfterPosition: 'toto' as any }) - await command.reorderElements(params) - } - - { - const params = getBase({ insertAfterPosition: -2 }) - await command.reorderElements(params) - } - - { - const params = getBase({ insertAfterPosition: 42 }) - await command.reorderElements(params) - } - }) - - it('Should fail with an invalid reorder length', async function () { - { - const params = getBase({ reorderLength: 'toto' as any }) - await command.reorderElements(params) - } - - { - const params = getBase({ reorderLength: -2 }) - await command.reorderElements(params) - } - - { - const params = getBase({ reorderLength: 42 }) - await command.reorderElements(params) - } - }) - - it('Succeed with the correct params', async function () { - const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - await command.reorderElements(params) - }) - }) - - describe('When checking exists in playlist endpoint', function () { - const path = '/api/v1/users/me/video-playlists/videos-exist' - - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ - url: server.url, - path, - query: { videoIds: [ 1, 2 ] }, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with invalid video ids', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { videoIds: 'toto' } - }) - - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { videoIds: [ 'toto' ] } - }) - - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { videoIds: [ 1, 'toto' ] } - }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { videoIds: [ 1, 2 ] }, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - }) - - describe('When deleting an element in a playlist', function () { - const getBase = (wrapper: Partial[0]>) => { - return { - elementId, - playlistId: playlist.uuid, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - - ...wrapper - } - } - - it('Should fail with an unauthenticated user', async function () { - const params = getBase({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await command.removeElement(params) - }) - - it('Should fail with the playlist of another user', async function () { - const params = getBase({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await command.removeElement(params) - }) - - it('Should fail with an unknown or incorrect playlist id', async function () { - { - const params = getBase({ playlistId: 'toto' }) - await command.removeElement(params) - } - - { - const params = getBase({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.removeElement(params) - } - }) - - it('Should fail with an unknown or incorrect video id', async function () { - { - const params = getBase({ elementId: 'toto' as any }) - await command.removeElement(params) - } - - { - const params = getBase({ elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.removeElement(params) - } - }) - - it('Should fail with an unknown element', async function () { - const params = getBase({ elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await command.removeElement(params) - }) - - it('Succeed with the correct params', async function () { - const params = getBase({ expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - await command.removeElement(params) - }) - }) - - describe('When deleting a playlist', function () { - it('Should fail with an unknown playlist', async function () { - await command.delete({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a playlist of another user', async function () { - await command.delete({ token: userAccessToken, playlistId: playlist.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with the watch later playlist', async function () { - await command.delete({ playlistId: watchLaterPlaylistId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct params', async function () { - await command.delete({ playlistId: playlist.uuid }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-source.ts b/server/tests/api/check-params/video-source.ts deleted file mode 100644 index 767590d5e..000000000 --- a/server/tests/api/check-params/video-source.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test video sources API validator', function () { - let server: PeerTubeServer = null - let uuid: string - let userToken: string - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - userToken = await server.users.generateUserAndToken('user1') - }) - - describe('When getting latest source', function () { - - before(async function () { - const created = await server.videos.quickUpload({ name: 'video' }) - uuid = created.uuid - }) - - it('Should fail without a valid uuid', async function () { - await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should receive 404 when passing a non existing video id', async function () { - await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should not get the source as unauthenticated', async function () { - await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null }) - }) - - it('Should not get the source with another user', async function () { - await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: userToken }) - }) - - it('Should succeed with the correct parameters get the source as another user', async function () { - await server.videos.getSource({ id: uuid }) - }) - }) - - describe('When updating source video file', function () { - let userAccessToken: string - let userId: number - - let videoId: string - let userVideoId: string - - before(async function () { - const res = await server.users.generate('user2') - userAccessToken = res.token - userId = res.userId - - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - videoId = uuid - - await waitJobs([ server ]) - }) - - it('Should fail if not enabled on the instance', async function () { - await server.config.disableFileUpdate() - - await server.videos.replaceSourceFile({ videoId, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail on an unknown video', async function () { - await server.config.enableFileUpdate() - - await server.videos.replaceSourceFile({ videoId: 404, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with an invalid video', async function () { - await server.config.enableLive({ allowReplay: false }) - - const { video } = await server.live.quickCreate({ saveReplay: false, permanentLive: true }) - await server.videos.replaceSourceFile({ - videoId: video.uuid, - fixture: 'video_short.mp4', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail without token', async function () { - await server.videos.replaceSourceFile({ - token: null, - videoId, - fixture: 'video_short.mp4', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another user', async function () { - await server.videos.replaceSourceFile({ - token: userAccessToken, - videoId, - fixture: 'video_short.mp4', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an incorrect input file', async function () { - await server.videos.replaceSourceFile({ - fixture: 'video_short_fake.webm', - videoId, - completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422 - }) - - await server.videos.replaceSourceFile({ - fixture: 'video_short.mkv', - videoId, - expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 - }) - }) - - it('Should fail if quota is exceeded', async function () { - this.timeout(60000) - - const { uuid } = await server.videos.quickUpload({ name: 'user video' }) - userVideoId = uuid - await waitJobs([ server ]) - - await server.users.update({ userId, videoQuota: 1 }) - await server.videos.replaceSourceFile({ - token: userAccessToken, - videoId: uuid, - fixture: 'video_short.mp4', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct params', async function () { - this.timeout(60000) - - await server.users.update({ userId, videoQuota: 1000 * 1000 * 1000 }) - await server.videos.replaceSourceFile({ videoId: userVideoId, fixture: 'video_short.mp4' }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-storyboards.ts b/server/tests/api/check-params/video-storyboards.ts deleted file mode 100644 index c038e7370..000000000 --- a/server/tests/api/check-params/video-storyboards.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test video storyboards API validator', function () { - let server: PeerTubeServer - - let publicVideo: { uuid: string } - let privateVideo: { uuid: string } - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - publicVideo = await server.videos.quickUpload({ name: 'public' }) - privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE }) - }) - - it('Should fail without a valid uuid', async function () { - await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should receive 404 when passing a non existing video id', async function () { - await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should not get the private storyboard without the appropriate token', async function () { - await server.storyboard.list({ id: privateVideo.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null }) - await server.storyboard.list({ id: publicVideo.uuid, expectedStatus: HttpStatusCode.OK_200, token: null }) - }) - - it('Should succeed with the correct parameters', async function () { - await server.storyboard.list({ id: privateVideo.uuid }) - await server.storyboard.list({ id: publicVideo.uuid }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-studio.ts b/server/tests/api/check-params/video-studio.ts deleted file mode 100644 index 4ac0d93ed..000000000 --- a/server/tests/api/check-params/video-studio.ts +++ /dev/null @@ -1,388 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, VideoStudioTask } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - VideoStudioCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test video studio API validator', function () { - let server: PeerTubeServer - let command: VideoStudioCommand - let userAccessToken: string - let videoUUID: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - userAccessToken = await server.users.generateUserAndToken('user1') - - await server.config.enableMinimumTranscoding() - - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - videoUUID = uuid - - command = server.videoStudio - - await waitJobs([ server ]) - }) - - describe('Task creation', function () { - - describe('Config settings', function () { - - it('Should fail if studio is disabled', async function () { - await server.config.updateExistingSubConfig({ - newConfig: { - videoStudio: { - enabled: false - } - } - }) - - await command.createEditionTasks({ - videoId: videoUUID, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail to enable studio if transcoding is disabled', async function () { - await server.config.updateExistingSubConfig({ - newConfig: { - videoStudio: { - enabled: true - }, - transcoding: { - enabled: false - } - }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed to enable video studio', async function () { - await server.config.updateExistingSubConfig({ - newConfig: { - videoStudio: { - enabled: true - }, - transcoding: { - enabled: true - } - } - }) - }) - }) - - describe('Common tasks', function () { - - it('Should fail without token', async function () { - await command.createEditionTasks({ - token: null, - videoId: videoUUID, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another user token', async function () { - await command.createEditionTasks({ - token: userAccessToken, - videoId: videoUUID, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid video', async function () { - await command.createEditionTasks({ - videoId: 'tintin', - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an unknown video', async function () { - await command.createEditionTasks({ - videoId: 42, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with an already in transcoding state video', async function () { - this.timeout(60000) - - const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' }) - await waitJobs([ server ]) - - await server.jobs.pauseJobQueue() - await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' }) - - await command.createEditionTasks({ - videoId: uuid, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - - await server.jobs.resumeJobQueue() - }) - - it('Should fail with a bad complex task', async function () { - await command.createEditionTasks({ - videoId: videoUUID, - tasks: [ - { - name: 'cut', - options: { - start: 1, - end: 2 - } - }, - { - name: 'hadock', - options: { - start: 1, - end: 2 - } - } - ] as any, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail without task', async function () { - await command.createEditionTasks({ - videoId: videoUUID, - tasks: [], - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with too many tasks', async function () { - const tasks: VideoStudioTask[] = [] - - for (let i = 0; i < 110; i++) { - tasks.push({ - name: 'cut', - options: { - start: 1 - } - }) - } - - await command.createEditionTasks({ - videoId: videoUUID, - tasks, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with correct parameters', async function () { - await server.jobs.pauseJobQueue() - - await command.createEditionTasks({ - videoId: videoUUID, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should fail with a video that is already waiting for edition', async function () { - this.timeout(120000) - - await command.createEditionTasks({ - videoId: videoUUID, - tasks: VideoStudioCommand.getComplexTask(), - expectedStatus: HttpStatusCode.CONFLICT_409 - }) - - await server.jobs.resumeJobQueue() - - await waitJobs([ server ]) - }) - }) - - describe('Cut task', function () { - - async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { - await command.createEditionTasks({ - videoId: videoUUID, - tasks: [ - { - name: 'cut', - options: { - start, - end - } - } - ], - expectedStatus - }) - } - - it('Should fail with bad start/end', async function () { - const invalid = [ - 'tintin', - -1, - undefined - ] - - for (const value of invalid) { - await cut(value as any, undefined) - await cut(undefined, value as any) - } - }) - - it('Should fail with the same start/end', async function () { - await cut(2, 2) - }) - - it('Should fail with inconsistents start/end', async function () { - await cut(2, 1) - }) - - it('Should fail without start and end', async function () { - await cut(undefined, undefined) - }) - - it('Should succeed with the correct params', async function () { - this.timeout(120000) - - await cut(0, 2, HttpStatusCode.NO_CONTENT_204) - - await waitJobs([ server ]) - }) - }) - - describe('Watermark task', function () { - - async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { - await command.createEditionTasks({ - videoId: videoUUID, - tasks: [ - { - name: 'add-watermark', - options: { - file - } - } - ], - expectedStatus - }) - } - - it('Should fail without waterkmark', async function () { - await addWatermark(undefined) - }) - - it('Should fail with an invalid watermark', async function () { - await addWatermark('video_short.mp4') - }) - - it('Should succeed with the correct params', async function () { - this.timeout(120000) - - await addWatermark('custom-thumbnail.jpg', HttpStatusCode.NO_CONTENT_204) - - await waitJobs([ server ]) - }) - }) - - describe('Intro/Outro task', function () { - - async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { - await command.createEditionTasks({ - videoId: videoUUID, - tasks: [ - { - name: type, - options: { - file - } - } - ], - expectedStatus - }) - } - - it('Should fail without file', async function () { - await addIntroOutro('add-intro', undefined) - await addIntroOutro('add-outro', undefined) - }) - - it('Should fail with an invalid file', async function () { - await addIntroOutro('add-intro', 'custom-thumbnail.jpg') - await addIntroOutro('add-outro', 'custom-thumbnail.jpg') - }) - - it('Should fail with a file that does not contain video stream', async function () { - await addIntroOutro('add-intro', 'sample.ogg') - await addIntroOutro('add-outro', 'sample.ogg') - - }) - - it('Should succeed with the correct params', async function () { - this.timeout(120000) - - await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) - await waitJobs([ server ]) - - await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) - await waitJobs([ server ]) - }) - - it('Should check total quota when creating the task', async function () { - this.timeout(120000) - - const user = await server.users.create({ username: 'user_quota_1' }) - const token = await server.login.getAccessToken('user_quota_1') - const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' }) - - const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => { - return command.createEditionTasks({ - token, - videoId: uuid, - tasks: [ - { - name: type, - options: { - file: 'video_short.mp4' - } - } - ], - expectedStatus - }) - } - - await waitJobs([ server ]) - - const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token }) - await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) }) - - // Still valid - await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204) - - await waitJobs([ server ]) - - // Too much quota - await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) - await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/video-token.ts b/server/tests/api/check-params/video-token.ts deleted file mode 100644 index 7cb3e84a2..000000000 --- a/server/tests/api/check-params/video-token.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test video tokens', function () { - let server: PeerTubeServer - let privateVideoId: string - let passwordProtectedVideoId: string - let userToken: string - - const videoPassword = 'password' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(300_000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - { - const { uuid } = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE }) - privateVideoId = uuid - } - { - const { uuid } = await server.videos.quickUpload({ - name: 'password protected video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ videoPassword ] - }) - passwordProtectedVideoId = uuid - } - userToken = await server.users.generateUserAndToken('user1') - }) - - it('Should not generate tokens on private video for unauthenticated user', async function () { - await server.videoToken.create({ videoId: privateVideoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not generate tokens of unknown video', async function () { - await server.videoToken.create({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should not generate tokens with incorrect password', async function () { - await server.videoToken.create({ - videoId: passwordProtectedVideoId, - token: null, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - videoPassword: 'incorrectPassword' - }) - }) - - it('Should not generate tokens of a non owned video', async function () { - await server.videoToken.create({ videoId: privateVideoId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should generate token', async function () { - await server.videoToken.create({ videoId: privateVideoId }) - }) - - it('Should generate token on password protected video', async function () { - await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: null }) - await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: userToken }) - await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/videos-common-filters.ts b/server/tests/api/check-params/videos-common-filters.ts deleted file mode 100644 index 603f7f777..000000000 --- a/server/tests/api/check-params/videos-common-filters.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, UserRole, VideoInclude, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test video filters validators', function () { - let server: PeerTubeServer - let userAccessToken: string - let moderatorAccessToken: string - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - const user = { username: 'user1', password: 'my super password' } - await server.users.create({ username: user.username, password: user.password }) - userAccessToken = await server.login.getAccessToken(user) - - const moderator = { username: 'moderator', password: 'my super password' } - await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR }) - - moderatorAccessToken = await server.login.getAccessToken(moderator) - }) - - describe('When setting video filters', function () { - - const validIncludes = [ - VideoInclude.NONE, - VideoInclude.BLOCKED_OWNER, - VideoInclude.NOT_PUBLISHED_STATE | VideoInclude.BLACKLISTED - ] - - async function testEndpoints (options: { - token?: string - isLocal?: boolean - include?: VideoInclude - privacyOneOf?: VideoPrivacy[] - expectedStatus: HttpStatusCode - excludeAlreadyWatched?: boolean - unauthenticatedUser?: boolean - }) { - const paths = [ - '/api/v1/video-channels/root_channel/videos', - '/api/v1/accounts/root/videos', - '/api/v1/videos', - '/api/v1/search/videos' - ] - - for (const path of paths) { - const token = options.unauthenticatedUser - ? undefined - : options.token || server.accessToken - - await makeGetRequest({ - url: server.url, - path, - token, - query: { - isLocal: options.isLocal, - privacyOneOf: options.privacyOneOf, - include: options.include, - excludeAlreadyWatched: options.excludeAlreadyWatched - }, - expectedStatus: options.expectedStatus - }) - } - } - - it('Should fail with a bad privacyOneOf', async function () { - await testEndpoints({ privacyOneOf: [ 'toto' ] as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with a good privacyOneOf', async function () { - await testEndpoints({ privacyOneOf: [ VideoPrivacy.INTERNAL ], expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should fail to use privacyOneOf with a simple user', async function () { - await testEndpoints({ - privacyOneOf: [ VideoPrivacy.INTERNAL ], - token: userAccessToken, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with a bad include', async function () { - await testEndpoints({ include: 'toto' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with a good include', async function () { - for (const include of validIncludes) { - await testEndpoints({ include, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should fail to include more videos with a simple user', async function () { - for (const include of validIncludes) { - await testEndpoints({ token: userAccessToken, include, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - } - }) - - it('Should succeed to list all local/all with a moderator', async function () { - for (const include of validIncludes) { - await testEndpoints({ token: moderatorAccessToken, include, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should succeed to list all local/all with an admin', async function () { - for (const include of validIncludes) { - await testEndpoints({ token: server.accessToken, include, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - // Because we cannot authenticate the user on the RSS endpoint - it('Should fail on the feeds endpoint with the all filter', async function () { - for (const include of [ VideoInclude.NOT_PUBLISHED_STATE ]) { - await makeGetRequest({ - url: server.url, - path: '/feeds/videos.json', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401, - query: { - include - } - }) - } - }) - - it('Should succeed on the feeds endpoint with the local filter', async function () { - await makeGetRequest({ - url: server.url, - path: '/feeds/videos.json', - expectedStatus: HttpStatusCode.OK_200, - query: { - isLocal: true - } - }) - }) - - it('Should fail when trying to exclude already watched videos for an unlogged user', async function () { - await testEndpoints({ excludeAlreadyWatched: true, unauthenticatedUser: true, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed when trying to exclude already watched videos for a logged user', async function () { - await testEndpoints({ token: userAccessToken, excludeAlreadyWatched: true, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts deleted file mode 100644 index d96fe7ca9..000000000 --- a/server/tests/api/check-params/videos-history.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { checkBadCountPagination, checkBadStartPagination } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePostBodyRequest, - makePutBodyRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test videos history API validator', function () { - const myHistoryPath = '/api/v1/users/me/history/videos' - const myHistoryRemove = myHistoryPath + '/remove' - let viewPath: string - let server: PeerTubeServer - let videoId: number - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const { id, uuid } = await server.videos.upload() - viewPath = '/api/v1/videos/' + uuid + '/views' - videoId = id - }) - - describe('When notifying a user is watching a video', function () { - - it('Should fail with a bad token', async function () { - const fields = { currentTime: 5 } - await makePutBodyRequest({ url: server.url, path: viewPath, fields, token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should succeed with the correct parameters', async function () { - const fields = { currentTime: 5 } - - await makePutBodyRequest({ - url: server.url, - path: viewPath, - fields, - token: server.accessToken, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When listing user videos history', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, myHistoryPath, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, myHistoryPath, server.accessToken) - }) - - it('Should fail with an unauthenticated user', async function () { - await makeGetRequest({ url: server.url, path: myHistoryPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should succeed with the correct params', async function () { - await makeGetRequest({ url: server.url, token: server.accessToken, path: myHistoryPath, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When removing a specific user video history element', function () { - let path: string - - before(function () { - path = myHistoryPath + '/' + videoId - }) - - it('Should fail with an unauthenticated user', async function () { - await makeDeleteRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a bad videoId parameter', async function () { - await makeDeleteRequest({ - url: server.url, - token: server.accessToken, - path: myHistoryRemove + '/hi', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await makeDeleteRequest({ - url: server.url, - token: server.accessToken, - path, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When removing all user videos history', function () { - it('Should fail with an unauthenticated user', async function () { - await makePostBodyRequest({ url: server.url, path: myHistoryPath + '/remove', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with a bad beforeDate parameter', async function () { - const body = { beforeDate: '15' } - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path: myHistoryRemove, - fields: body, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with a valid beforeDate param', async function () { - const body = { beforeDate: new Date().toISOString() } - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path: myHistoryRemove, - fields: body, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - - it('Should succeed without body', async function () { - await makePostBodyRequest({ - url: server.url, - token: server.accessToken, - path: myHistoryRemove, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/videos-overviews.ts b/server/tests/api/check-params/videos-overviews.ts deleted file mode 100644 index ae7de24dd..000000000 --- a/server/tests/api/check-params/videos-overviews.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' - -describe('Test videos overview API validator', function () { - let server: PeerTubeServer - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - }) - - describe('When getting videos overview', function () { - - it('Should fail with a bad pagination', async function () { - await server.overviews.getVideos({ page: 0, expectedStatus: 400 }) - await server.overviews.getVideos({ page: 100, expectedStatus: 400 }) - }) - - it('Should succeed with a good pagination', async function () { - await server.overviews.getVideos({ page: 1 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts deleted file mode 100644 index f00698fe3..000000000 --- a/server/tests/api/check-params/videos.ts +++ /dev/null @@ -1,881 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { join } from 'path' -import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, checkUploadVideoParam } from '@server/tests/shared' -import { omit, randomInt, root } from '@shared/core-utils' -import { HttpStatusCode, PeerTubeProblemDocument, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeDeleteRequest, - makeGetRequest, - makePutBodyRequest, - makeUploadRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test videos API validator', function () { - const path = '/api/v1/videos/' - let server: PeerTubeServer - let userAccessToken = '' - let accountName: string - let channelId: number - let channelName: string - let video: VideoCreateResult - let privateVideo: VideoCreateResult - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - userAccessToken = await server.users.generateUserAndToken('user1') - - { - const body = await server.users.getMyInfo() - channelId = body.videoChannels[0].id - channelName = body.videoChannels[0].name - accountName = body.account.name + '@' + body.account.host - } - - { - privateVideo = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE }) - } - }) - - describe('When listing videos', function () { - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path) - }) - - it('Should fail with a bad skipVideos query', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: 'toto' } }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: false } }) - }) - }) - - describe('When searching a video', function () { - - it('Should fail with nothing', async function () { - await makeGetRequest({ - url: server.url, - path: join(path, 'search'), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, join(path, 'search', 'test')) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, join(path, 'search', 'test')) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, join(path, 'search', 'test')) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When listing my videos', function () { - const path = '/api/v1/users/me/videos' - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an invalid channel', async function () { - await makeGetRequest({ url: server.url, token: server.accessToken, path, query: { channelId: 'toto' } }) - }) - - it('Should fail with an unknown channel', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path, - query: { channelId: 89898 }, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, token: server.accessToken, path, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When listing account videos', function () { - let path: string - - before(async function () { - path = '/api/v1/accounts/' + accountName + '/videos' - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When listing video channel videos', function () { - let path: string - - before(async function () { - path = '/api/v1/video-channels/' + channelName + '/videos' - }) - - it('Should fail with a bad start pagination', async function () { - await checkBadStartPagination(server.url, path, server.accessToken) - }) - - it('Should fail with a bad count pagination', async function () { - await checkBadCountPagination(server.url, path, server.accessToken) - }) - - it('Should fail with an incorrect sort', async function () { - await checkBadSortPagination(server.url, path, server.accessToken) - }) - - it('Should success with the correct parameters', async function () { - await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('When adding a video', function () { - let baseCorrectParams - const baseCorrectAttaches = { - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') - } - - before(function () { - // Put in before to have channelId - baseCorrectParams = { - name: 'my super name', - category: 5, - licence: 1, - language: 'pt', - nsfw: false, - commentsEnabled: true, - downloadEnabled: true, - waitTranscoding: true, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag1', 'tag2' ], - privacy: VideoPrivacy.PUBLIC, - channelId, - originallyPublishedAt: new Date().toISOString() - } - }) - - function runSuite (mode: 'legacy' | 'resumable') { - - const baseOptions = () => { - return { - server, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400, - mode - } - } - - it('Should fail with nothing', async function () { - const fields = {} - const attaches = {} - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail without name', async function () { - const fields = omit(baseCorrectParams, [ 'name' ]) - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad category', async function () { - const fields = { ...baseCorrectParams, category: 125 } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad licence', async function () { - const fields = { ...baseCorrectParams, licence: 125 } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad language', async function () { - const fields = { ...baseCorrectParams, language: 'a'.repeat(15) } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail without a channel', async function () { - const fields = omit(baseCorrectParams, [ 'channelId' ]) - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad channel', async function () { - const fields = { ...baseCorrectParams, channelId: 545454 } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with another user channel', async function () { - const user = { - username: 'fake' + randomInt(0, 1500), - password: 'fake_password' - } - await server.users.create({ username: user.username, password: user.password }) - - const accessTokenUser = await server.login.getAccessToken(user) - const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser }) - const customChannelId = videoChannels[0].id - - const fields = { ...baseCorrectParams, channelId: customChannelId } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ - ...baseOptions(), - token: userAccessToken, - attributes: { ...fields, ...attaches } - }) - }) - - it('Should fail with too many tags', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a tag length too low', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a tag length too big', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad schedule update (miss updateAt)', async function () { - const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad schedule update (wrong updateAt)', async function () { - const fields = { - ...baseCorrectParams, - - scheduleUpdate: { - privacy: VideoPrivacy.PUBLIC, - updateAt: 'toto' - } - } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a bad originally published at attribute', async function () { - const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' } - const attaches = baseCorrectAttaches - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail without an input file', async function () { - const fields = baseCorrectParams - const attaches = {} - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with an incorrect input file', async function () { - const fields = baseCorrectParams - let attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') } - - await checkUploadVideoParam({ - ...baseOptions(), - attributes: { ...fields, ...attaches }, - // 200 for the init request, 422 when the file has finished being uploaded - expectedStatus: undefined, - completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422 - }) - - attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') } - await checkUploadVideoParam({ - ...baseOptions(), - attributes: { ...fields, ...attaches }, - expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 - }) - }) - - it('Should fail with an incorrect thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a big thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'), - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with an incorrect preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should fail with a big preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'), - fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } }) - }) - - it('Should report the appropriate error', async function () { - const fields = { ...baseCorrectParams, language: 'a'.repeat(15) } - const attaches = baseCorrectAttaches - - const attributes = { ...fields, ...attaches } - const body = await checkUploadVideoParam({ ...baseOptions(), attributes }) - - const error = body as unknown as PeerTubeProblemDocument - - if (mode === 'legacy') { - expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy') - } else { - expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit') - } - - expect(error.type).to.equal('about:blank') - expect(error.title).to.equal('Bad Request') - - expect(error.detail).to.equal('Incorrect request parameters: language') - expect(error.error).to.equal('Incorrect request parameters: language') - - expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) - expect(error['invalid-params'].language).to.exist - }) - - it('Should succeed with the correct parameters', async function () { - this.timeout(30000) - - const fields = baseCorrectParams - - { - const attaches = baseCorrectAttaches - await checkUploadVideoParam({ - ...baseOptions(), - attributes: { ...fields, ...attaches }, - expectedStatus: HttpStatusCode.OK_200 - }) - } - - { - const attaches = { - ...baseCorrectAttaches, - - videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await checkUploadVideoParam({ - ...baseOptions(), - attributes: { ...fields, ...attaches }, - expectedStatus: HttpStatusCode.OK_200 - }) - } - - { - const attaches = { - ...baseCorrectAttaches, - - videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv') - } - - await checkUploadVideoParam({ - ...baseOptions(), - attributes: { ...fields, ...attaches }, - expectedStatus: HttpStatusCode.OK_200 - }) - } - }) - } - - describe('Resumable upload', function () { - runSuite('resumable') - }) - - describe('Legacy upload', function () { - runSuite('legacy') - }) - }) - - describe('When updating a video', function () { - const baseCorrectParams = { - name: 'my super name', - category: 5, - licence: 2, - language: 'pt', - nsfw: false, - commentsEnabled: false, - downloadEnabled: false, - description: 'my super description', - privacy: VideoPrivacy.PUBLIC, - tags: [ 'tag1', 'tag2' ] - } - - before(async function () { - const { data } = await server.videos.list() - video = data[0] - }) - - it('Should fail with nothing', async function () { - const fields = {} - await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) - }) - - it('Should fail without a valid uuid', async function () { - const fields = baseCorrectParams - await makePutBodyRequest({ url: server.url, path: path + 'blabla', token: server.accessToken, fields }) - }) - - it('Should fail with an unknown id', async function () { - const fields = baseCorrectParams - - await makePutBodyRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06', - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a long name', async function () { - const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad category', async function () { - const fields = { ...baseCorrectParams, category: 125 } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad licence', async function () { - const fields = { ...baseCorrectParams, licence: 125 } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad language', async function () { - const fields = { ...baseCorrectParams, language: 'a'.repeat(15) } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a long description', async function () { - const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a long support text', async function () { - const fields = { ...baseCorrectParams, support: 'super'.repeat(201) } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad channel', async function () { - const fields = { ...baseCorrectParams, channelId: 545454 } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with too many tags', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too low', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a tag length too big', async function () { - const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad schedule update (miss updateAt)', async function () { - const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad schedule update (wrong updateAt)', async function () { - const fields = { ...baseCorrectParams, scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with a bad originally published at param', async function () { - const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' } - - await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - }) - - it('Should fail with an incorrect thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await makeUploadRequest({ - url: server.url, - method: 'PUT', - path: path + video.shortUUID, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with a big thumbnail file', async function () { - const fields = baseCorrectParams - const attaches = { - thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png') - } - - await makeUploadRequest({ - url: server.url, - method: 'PUT', - path: path + video.shortUUID, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with an incorrect preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') - } - - await makeUploadRequest({ - url: server.url, - method: 'PUT', - path: path + video.shortUUID, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with a big preview file', async function () { - const fields = baseCorrectParams - const attaches = { - previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png') - } - - await makeUploadRequest({ - url: server.url, - method: 'PUT', - path: path + video.shortUUID, - token: server.accessToken, - fields, - attaches - }) - }) - - it('Should fail with a video of another user without the appropriate right', async function () { - const fields = baseCorrectParams - - await makePutBodyRequest({ - url: server.url, - path: path + video.shortUUID, - token: userAccessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with a video of another server') - - it('Shoud report the appropriate error', async function () { - const fields = { ...baseCorrectParams, licence: 125 } - - const res = await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields }) - const error = res.body as PeerTubeProblemDocument - - expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo') - - expect(error.type).to.equal('about:blank') - expect(error.title).to.equal('Bad Request') - - expect(error.detail).to.equal('Incorrect request parameters: licence') - expect(error.error).to.equal('Incorrect request parameters: licence') - - expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) - expect(error['invalid-params'].licence).to.exist - }) - - it('Should succeed with the correct parameters', async function () { - const fields = baseCorrectParams - - await makePutBodyRequest({ - url: server.url, - path: path + video.shortUUID, - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When getting a video', function () { - it('Should return the list of the videos with nothing', async function () { - const res = await makeGetRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.data).to.be.an('array') - expect(res.body.data.length).to.equal(6) - }) - - it('Should fail without a correct uuid', async function () { - await server.videos.get({ id: 'coucou', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should return 404 with an incorrect video', async function () { - await server.videos.get({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Shoud report the appropriate error', async function () { - const body = await server.videos.get({ id: 'hi', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - const error = body as unknown as PeerTubeProblemDocument - - expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo') - - expect(error.type).to.equal('about:blank') - expect(error.title).to.equal('Bad Request') - - expect(error.detail).to.equal('Incorrect request parameters: id') - expect(error.error).to.equal('Incorrect request parameters: id') - - expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) - expect(error['invalid-params'].id).to.exist - }) - - it('Should succeed with the correct parameters', async function () { - await server.videos.get({ id: video.shortUUID }) - }) - }) - - describe('When rating a video', function () { - let videoId: number - - before(async function () { - const { data } = await server.videos.list() - videoId = data[0].id - }) - - it('Should fail without a valid uuid', async function () { - const fields = { - rating: 'like' - } - await makePutBodyRequest({ url: server.url, path: path + 'blabla/rate', token: server.accessToken, fields }) - }) - - it('Should fail with an unknown id', async function () { - const fields = { - rating: 'like' - } - await makePutBodyRequest({ - url: server.url, - path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/rate', - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should fail with a wrong rating', async function () { - const fields = { - rating: 'likes' - } - await makePutBodyRequest({ url: server.url, path: path + videoId + '/rate', token: server.accessToken, fields }) - }) - - it('Should fail with a private video of another user', async function () { - const fields = { - rating: 'like' - } - await makePutBodyRequest({ - url: server.url, - path: path + privateVideo.uuid + '/rate', - token: userAccessToken, - fields, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should succeed with the correct parameters', async function () { - const fields = { - rating: 'like' - } - await makePutBodyRequest({ - url: server.url, - path: path + videoId + '/rate', - token: server.accessToken, - fields, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - }) - }) - - describe('When removing a video', function () { - it('Should have 404 with nothing', async function () { - await makeDeleteRequest({ - url: server.url, - path, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail without a correct uuid', async function () { - await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with a video which does not exist', async function () { - await server.videos.remove({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should fail with a video of another user without the appropriate right', async function () { - await server.videos.remove({ token: userAccessToken, id: video.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail with a video of another server') - - it('Shoud report the appropriate error', async function () { - const body = await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - const error = body as PeerTubeProblemDocument - - expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo') - - expect(error.type).to.equal('about:blank') - expect(error.title).to.equal('Bad Request') - - expect(error.detail).to.equal('Incorrect request parameters: id') - expect(error.error).to.equal('Incorrect request parameters: id') - - expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) - expect(error['invalid-params'].id).to.exist - }) - - it('Should succeed with the correct parameters', async function () { - await server.videos.remove({ id: video.uuid }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/check-params/views.ts b/server/tests/api/check-params/views.ts deleted file mode 100644 index 11416ccb8..000000000 --- a/server/tests/api/check-params/views.ts +++ /dev/null @@ -1,227 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test videos views', function () { - let servers: PeerTubeServer[] - let liveVideoId: string - let videoId: string - let remoteVideoId: string - let userAccessToken: string - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.enableLive({ allowReplay: false, transcoding: false }); - - ({ uuid: videoId } = await servers[0].videos.quickUpload({ name: 'video' })); - ({ uuid: remoteVideoId } = await servers[1].videos.quickUpload({ name: 'video' })); - ({ uuid: liveVideoId } = await servers[0].live.create({ - fields: { - name: 'live', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id - } - })) - - userAccessToken = await servers[0].users.generateUserAndToken('user') - - await doubleFollow(servers[0], servers[1]) - }) - - describe('When viewing a video', async function () { - - it('Should fail without current time', async function () { - await servers[0].views.view({ id: videoId, currentTime: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an invalid current time', async function () { - await servers[0].views.view({ id: videoId, currentTime: -1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].views.view({ id: videoId, currentTime: 10, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with correct parameters', async function () { - await servers[0].views.view({ id: videoId, currentTime: 1 }) - }) - }) - - describe('When getting overall stats', function () { - - it('Should fail with a remote video', async function () { - await servers[0].videoStats.getOverallStats({ videoId: remoteVideoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should fail without token', async function () { - await servers[0].videoStats.getOverallStats({ videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should fail with another token', async function () { - await servers[0].videoStats.getOverallStats({ - videoId, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid start date', async function () { - await servers[0].videoStats.getOverallStats({ - videoId, - startDate: 'fake' as any, - endDate: new Date().toISOString(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an invalid end date', async function () { - await servers[0].videoStats.getOverallStats({ - videoId, - startDate: new Date().toISOString(), - endDate: 'fake' as any, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await servers[0].videoStats.getOverallStats({ - videoId, - startDate: new Date().toISOString(), - endDate: new Date().toISOString() - }) - }) - }) - - describe('When getting timeserie stats', function () { - - it('Should fail with a remote video', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId: remoteVideoId, - metric: 'viewers', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail without token', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - token: null, - metric: 'viewers', - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another token', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - token: userAccessToken, - metric: 'viewers', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail with an invalid metric', async function () { - await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'hello' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should fail with an invalid start date', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - metric: 'viewers', - startDate: 'fake' as any, - endDate: new Date(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with an invalid end date', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - metric: 'viewers', - startDate: new Date(), - endDate: 'fake' as any, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if start date is specified but not end date', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - metric: 'viewers', - startDate: new Date(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail if end date is specified but not start date', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - metric: 'viewers', - endDate: new Date(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should fail with a too big interval', async function () { - await servers[0].videoStats.getTimeserieStats({ - videoId, - metric: 'viewers', - startDate: new Date('2000-04-07T08:31:57.126Z'), - endDate: new Date(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should succeed with the correct parameters', async function () { - await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'viewers' }) - }) - }) - - describe('When getting retention stats', function () { - - it('Should fail with a remote video', async function () { - await servers[0].videoStats.getRetentionStats({ - videoId: remoteVideoId, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail without token', async function () { - await servers[0].videoStats.getRetentionStats({ - videoId, - token: null, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - }) - - it('Should fail with another token', async function () { - await servers[0].videoStats.getRetentionStats({ - videoId, - token: userAccessToken, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should fail on live video', async function () { - await servers[0].videoStats.getRetentionStats({ videoId: liveVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should succeed with the correct parameters', async function () { - await servers[0].videoStats.getRetentionStats({ videoId }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/index.ts b/server/tests/api/index.ts deleted file mode 100644 index ef0c83294..000000000 --- a/server/tests/api/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Order of the tests we want to execute -import './activitypub' -import './check-params' -import './moderation' -import './object-storage' -import './notifications' -import './redundancy' -import './runners' -import './search' -import './server' -import './transcoding' -import './users' -import './videos' diff --git a/server/tests/api/live/index.ts b/server/tests/api/live/index.ts deleted file mode 100644 index c88943f65..000000000 --- a/server/tests/api/live/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import './live-constraints' -import './live-fast-restream' -import './live-socket-messages' -import './live-permanent' -import './live-rtmps' -import './live-save-replay' -import './live' diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts deleted file mode 100644 index 697d808d5..000000000 --- a/server/tests/api/live/live-constraints.ts +++ /dev/null @@ -1,237 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { LiveVideoError, UserVideoQuota, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs, - waitUntilLiveReplacedByReplayOnAllServers, - waitUntilLiveWaitingOnAllServers -} from '@shared/server-commands' -import { checkLiveCleanup } from '../../shared' - -describe('Test live constraints', function () { - let servers: PeerTubeServer[] = [] - let userId: number - let userAccessToken: string - let userChannelId: number - - async function createLiveWrapper (options: { replay: boolean, permanent: boolean }) { - const { replay, permanent } = options - - const liveAttributes = { - name: 'user live', - channelId: userChannelId, - privacy: VideoPrivacy.PUBLIC, - saveReplay: replay, - replaySettings: options.replay ? { privacy: VideoPrivacy.PUBLIC } : undefined, - permanentLive: permanent - } - - const { uuid } = await servers[0].live.create({ token: userAccessToken, fields: liveAttributes }) - return uuid - } - - async function checkSaveReplay (videoId: string, resolutions = [ 720 ]) { - for (const server of servers) { - const video = await server.videos.get({ id: videoId }) - expect(video.isLive).to.be.false - expect(video.duration).to.be.greaterThan(0) - } - - await checkLiveCleanup({ server: servers[0], permanent: false, videoUUID: videoId, savedResolutions: resolutions }) - } - - function updateQuota (options: { total: number, daily: number }) { - return servers[0].users.update({ - userId, - videoQuota: options.total, - videoQuotaDaily: options.daily - }) - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - transcoding: { - enabled: false - } - } - } - }) - - { - const res = await servers[0].users.generate('user1') - userId = res.userId - userChannelId = res.userChannelId - userAccessToken = res.token - - await updateQuota({ total: 1, daily: -1 }) - } - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - it('Should not have size limit if save replay is disabled', async function () { - this.timeout(60000) - - const userVideoLiveoId = await createLiveWrapper({ replay: false, permanent: false }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: false }) - }) - - it('Should have size limit depending on user global quota if save replay is enabled on non permanent live', async function () { - this.timeout(60000) - - // Wait for user quota memoize cache invalidation - await wait(5000) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, userVideoLiveoId) - await waitJobs(servers) - - await checkSaveReplay(userVideoLiveoId) - - const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) - expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) - }) - - it('Should have size limit depending on user global quota if save replay is enabled on a permanent live', async function () { - this.timeout(60000) - - // Wait for user quota memoize cache invalidation - await wait(5000) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: true }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) - - await waitJobs(servers) - await waitUntilLiveWaitingOnAllServers(servers, userVideoLiveoId) - - const session = await servers[0].live.findLatestSession({ videoId: userVideoLiveoId }) - expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) - }) - - it('Should have size limit depending on user daily quota if save replay is enabled', async function () { - this.timeout(60000) - - // Wait for user quota memoize cache invalidation - await wait(5000) - - await updateQuota({ total: -1, daily: 1 }) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, userVideoLiveoId) - await waitJobs(servers) - - await checkSaveReplay(userVideoLiveoId) - - const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) - expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) - }) - - it('Should succeed without quota limit', async function () { - this.timeout(60000) - - // Wait for user quota memoize cache invalidation - await wait(5000) - - await updateQuota({ total: 10 * 1000 * 1000, daily: -1 }) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: false }) - }) - - it('Should have the same quota in admin and as a user', async function () { - this.timeout(120000) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ token: userAccessToken, videoId: userVideoLiveoId }) - - await servers[0].live.waitUntilPublished({ videoId: userVideoLiveoId }) - // Wait previous live cleanups - await wait(3000) - - const baseQuota = await servers[0].users.getMyQuotaUsed({ token: userAccessToken }) - - let quotaUser: UserVideoQuota - - do { - await wait(500) - - quotaUser = await servers[0].users.getMyQuotaUsed({ token: userAccessToken }) - } while (quotaUser.videoQuotaUsed <= baseQuota.videoQuotaUsed) - - const { data } = await servers[0].users.list() - const quotaAdmin = data.find(u => u.username === 'user1') - - expect(quotaUser.videoQuotaUsed).to.be.above(baseQuota.videoQuotaUsed) - expect(quotaUser.videoQuotaUsedDaily).to.be.above(baseQuota.videoQuotaUsedDaily) - - expect(quotaAdmin.videoQuotaUsed).to.be.above(baseQuota.videoQuotaUsed) - expect(quotaAdmin.videoQuotaUsedDaily).to.be.above(baseQuota.videoQuotaUsedDaily) - - expect(quotaUser.videoQuotaUsed).to.be.above(10) - expect(quotaUser.videoQuotaUsedDaily).to.be.above(10) - expect(quotaAdmin.videoQuotaUsed).to.be.above(10) - expect(quotaAdmin.videoQuotaUsedDaily).to.be.above(10) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have max duration limit', async function () { - this.timeout(240000) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - maxDuration: 15, - transcoding: { - enabled: true, - resolutions: ConfigCommand.getCustomConfigResolutions(true) - } - } - } - }) - - const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) - await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, userVideoLiveoId) - await waitJobs(servers) - - await checkSaveReplay(userVideoLiveoId, [ 720, 480, 360, 240, 144 ]) - - const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) - expect(session.error).to.equal(LiveVideoError.DURATION_EXCEEDED) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/live/live-fast-restream.ts b/server/tests/api/live/live-fast-restream.ts deleted file mode 100644 index 1b7fddd8b..000000000 --- a/server/tests/api/live/live-fast-restream.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { LiveVideoCreate, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -describe('Fast restream in live', function () { - let server: PeerTubeServer - - async function createLiveWrapper (options: { permanent: boolean, replay: boolean }) { - const attributes: LiveVideoCreate = { - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC, - name: 'my super live', - saveReplay: options.replay, - replaySettings: options.replay ? { privacy: VideoPrivacy.PUBLIC } : undefined, - permanentLive: options.permanent - } - - const { uuid } = await server.live.create({ fields: attributes }) - return uuid - } - - async function fastRestreamWrapper ({ replay }: { replay: boolean }) { - const liveVideoUUID = await createLiveWrapper({ permanent: true, replay }) - await waitJobs([ server ]) - - const rtmpOptions = { - videoId: liveVideoUUID, - copyCodecs: true, - fixtureName: 'video_short.mp4' - } - - // Streaming session #1 - let ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) - await server.live.waitUntilPublished({ videoId: liveVideoUUID }) - - const video = await server.videos.get({ id: liveVideoUUID }) - const session1PlaylistId = video.streamingPlaylists[0].id - - await stopFfmpeg(ffmpegCommand) - await server.live.waitUntilWaiting({ videoId: liveVideoUUID }) - - // Streaming session #2 - ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) - - let hasNewPlaylist = false - do { - const video = await server.videos.get({ id: liveVideoUUID }) - hasNewPlaylist = video.streamingPlaylists.length === 1 && video.streamingPlaylists[0].id !== session1PlaylistId - - await wait(100) - } while (!hasNewPlaylist) - - await server.live.waitUntilSegmentGeneration({ - server, - videoUUID: liveVideoUUID, - segment: 1, - playlistNumber: 0 - }) - - return { ffmpegCommand, liveVideoUUID } - } - - async function ensureLastLiveWorks (liveId: string) { - // Equivalent to PEERTUBE_TEST_CONSTANTS_VIDEO_LIVE_CLEANUP_DELAY - for (let i = 0; i < 100; i++) { - const video = await server.videos.get({ id: liveId }) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - try { - await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) - await server.streamingPlaylists.get({ url: video.streamingPlaylists[0].playlistUrl }) - await server.streamingPlaylists.getSegmentSha256({ url: video.streamingPlaylists[0].segmentsSha256Url }) - } catch (err) { - // FIXME: try to debug error in CI "Unexpected end of JSON input" - console.error(err) - throw err - } - - await wait(100) - } - } - - async function runTest (replay: boolean) { - const { ffmpegCommand, liveVideoUUID } = await fastRestreamWrapper({ replay }) - - // TODO: remove, we try to debug a test timeout failure here - console.log('Ensuring last live works') - - await ensureLastLiveWorks(liveVideoUUID) - - await stopFfmpeg(ffmpegCommand) - await server.live.waitUntilWaiting({ videoId: liveVideoUUID }) - - // Wait for replays - await waitJobs([ server ]) - - const { total, data: sessions } = await server.live.listSessions({ videoId: liveVideoUUID }) - - expect(total).to.equal(2) - expect(sessions).to.have.lengthOf(2) - - for (const session of sessions) { - expect(session.error).to.be.null - - if (replay) { - expect(session.replayVideo).to.exist - - await server.videos.get({ id: session.replayVideo.uuid }) - } else { - expect(session.replayVideo).to.not.exist - } - } - } - - before(async function () { - this.timeout(120000) - - const env = { PEERTUBE_TEST_CONSTANTS_VIDEO_LIVE_CLEANUP_DELAY: '10000' } - server = await createSingleServer(1, {}, { env }) - - // Get the access tokens - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableMinimumTranscoding({ webVideo: false, hls: true }) - await server.config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' }) - }) - - it('Should correctly fast restream in a permanent live with and without save replay', async function () { - this.timeout(480000) - - // A test can take a long time, so prefer to run them in parallel - await Promise.all([ - runTest(true), - runTest(false) - ]) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts deleted file mode 100644 index 4203b1bfc..000000000 --- a/server/tests/api/live/live-permanent.ts +++ /dev/null @@ -1,204 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkLiveCleanup } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -describe('Permanent live', function () { - let servers: PeerTubeServer[] = [] - let videoUUID: string - - async function createLiveWrapper (permanentLive: boolean) { - const attributes: LiveVideoCreate = { - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - name: 'my super live', - saveReplay: false, - permanentLive - } - - const { uuid } = await servers[0].live.create({ fields: attributes }) - return uuid - } - - async function checkVideoState (videoId: string, state: VideoState) { - for (const server of servers) { - const video = await server.videos.get({ id: videoId }) - expect(video.state.id).to.equal(state) - } - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - maxDuration: -1, - transcoding: { - enabled: true, - resolutions: ConfigCommand.getCustomConfigResolutions(true) - } - } - } - }) - }) - - it('Should create a non permanent live and update it to be a permanent live', async function () { - this.timeout(20000) - - const videoUUID = await createLiveWrapper(false) - - { - const live = await servers[0].live.get({ videoId: videoUUID }) - expect(live.permanentLive).to.be.false - } - - await servers[0].live.update({ videoId: videoUUID, fields: { permanentLive: true } }) - - { - const live = await servers[0].live.get({ videoId: videoUUID }) - expect(live.permanentLive).to.be.true - } - }) - - it('Should create a permanent live', async function () { - this.timeout(20000) - - videoUUID = await createLiveWrapper(true) - - const live = await servers[0].live.get({ videoId: videoUUID }) - expect(live.permanentLive).to.be.true - - await waitJobs(servers) - }) - - it('Should stream into this permanent live', async function () { - this.timeout(240_000) - - const beforePublication = new Date() - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID }) - - for (const server of servers) { - await server.live.waitUntilPublished({ videoId: videoUUID }) - } - - await checkVideoState(videoUUID, VideoState.PUBLISHED) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(new Date(video.publishedAt)).greaterThan(beforePublication) - } - - await stopFfmpeg(ffmpegCommand) - await servers[0].live.waitUntilWaiting({ videoId: videoUUID }) - - await waitJobs(servers) - }) - - it('Should have cleaned up this live', async function () { - this.timeout(40000) - - await wait(5000) - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - expect(videoDetails.streamingPlaylists).to.have.lengthOf(0) - } - - await checkLiveCleanup({ server: servers[0], permanent: true, videoUUID }) - }) - - it('Should have set this live to waiting for live state', async function () { - this.timeout(20000) - - await checkVideoState(videoUUID, VideoState.WAITING_FOR_LIVE) - }) - - it('Should be able to stream again in the permanent live', async function () { - this.timeout(60000) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - maxDuration: -1, - transcoding: { - enabled: true, - resolutions: ConfigCommand.getCustomConfigResolutions(false) - } - } - } - }) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID }) - - for (const server of servers) { - await server.live.waitUntilPublished({ videoId: videoUUID }) - } - - await checkVideoState(videoUUID, VideoState.PUBLISHED) - - const count = await servers[0].live.countPlaylists({ videoUUID }) - // master playlist and 720p playlist - expect(count).to.equal(2) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have appropriate sessions', async function () { - this.timeout(60000) - - await servers[0].live.waitUntilWaiting({ videoId: videoUUID }) - - const { data, total } = await servers[0].live.listSessions({ videoId: videoUUID }) - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const session of data) { - expect(session.startDate).to.exist - expect(session.endDate).to.exist - - expect(session.error).to.not.exist - } - }) - - it('Should remove the live and have cleaned up the directory', async function () { - this.timeout(60000) - - await servers[0].videos.remove({ id: videoUUID }) - await waitJobs(servers) - - await checkLiveCleanup({ server: servers[0], permanent: true, videoUUID }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/live/live-rtmps.ts b/server/tests/api/live/live-rtmps.ts deleted file mode 100644 index dcaee90cf..000000000 --- a/server/tests/api/live/live-rtmps.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - testFfmpegStreamError, - waitUntilLivePublishedOnAllServers -} from '@shared/server-commands' - -describe('Test live RTMPS', function () { - let server: PeerTubeServer - let rtmpUrl: string - let rtmpsUrl: string - - async function createLiveWrapper () { - const liveAttributes = { - name: 'live', - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC, - saveReplay: false - } - - const { uuid } = await server.live.create({ fields: liveAttributes }) - - const live = await server.live.get({ videoId: uuid }) - const video = await server.videos.get({ id: uuid }) - - return Object.assign(video, live) - } - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - // Get the access tokens - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - transcoding: { - enabled: false - } - } - } - }) - - rtmpUrl = 'rtmp://' + server.hostname + ':' + server.rtmpPort + '/live' - rtmpsUrl = 'rtmps://' + server.hostname + ':' + server.rtmpsPort + '/live' - }) - - it('Should enable RTMPS endpoint only', async function () { - this.timeout(240000) - - await server.kill() - await server.run({ - live: { - rtmp: { - enabled: false - }, - rtmps: { - enabled: true, - port: server.rtmpsPort, - key_file: buildAbsoluteFixturePath('rtmps.key'), - cert_file: buildAbsoluteFixturePath('rtmps.cert') - } - } - }) - - { - const liveVideo = await createLiveWrapper() - - expect(liveVideo.rtmpUrl).to.not.exist - expect(liveVideo.rtmpsUrl).to.equal(rtmpsUrl) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl, streamKey: liveVideo.streamKey }) - await testFfmpegStreamError(command, true) - } - - { - const liveVideo = await createLiveWrapper() - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpsUrl, streamKey: liveVideo.streamKey }) - await waitUntilLivePublishedOnAllServers([ server ], liveVideo.uuid) - await stopFfmpeg(command) - } - }) - - it('Should enable both RTMP and RTMPS', async function () { - this.timeout(240000) - - await server.kill() - await server.run({ - live: { - rtmp: { - enabled: true, - port: server.rtmpPort - }, - rtmps: { - enabled: true, - port: server.rtmpsPort, - key_file: buildAbsoluteFixturePath('rtmps.key'), - cert_file: buildAbsoluteFixturePath('rtmps.cert') - } - } - }) - - { - const liveVideo = await createLiveWrapper() - - expect(liveVideo.rtmpUrl).to.equal(rtmpUrl) - expect(liveVideo.rtmpsUrl).to.equal(rtmpsUrl) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl, streamKey: liveVideo.streamKey }) - await waitUntilLivePublishedOnAllServers([ server ], liveVideo.uuid) - await stopFfmpeg(command) - } - - { - const liveVideo = await createLiveWrapper() - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpsUrl, streamKey: liveVideo.streamKey }) - await waitUntilLivePublishedOnAllServers([ server ], liveVideo.uuid) - await stopFfmpeg(command) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts deleted file mode 100644 index d554cf208..000000000 --- a/server/tests/api/live/live-save-replay.ts +++ /dev/null @@ -1,570 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FfmpegCommand } from 'fluent-ffmpeg' -import { checkLiveCleanup } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, LiveVideoCreate, LiveVideoError, VideoPrivacy, VideoState } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createMultipleServers, - doubleFollow, - findExternalSavedVideo, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - testFfmpegStreamError, - waitJobs, - waitUntilLivePublishedOnAllServers, - waitUntilLiveReplacedByReplayOnAllServers, - waitUntilLiveWaitingOnAllServers -} from '@shared/server-commands' - -describe('Save replay setting', function () { - let servers: PeerTubeServer[] = [] - let liveVideoUUID: string - let ffmpegCommand: FfmpegCommand - - async function createLiveWrapper (options: { permanent: boolean, replay: boolean, replaySettings?: { privacy: VideoPrivacy } }) { - if (liveVideoUUID) { - try { - await servers[0].videos.remove({ id: liveVideoUUID }) - await waitJobs(servers) - } catch {} - } - - const attributes: LiveVideoCreate = { - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - name: 'live'.repeat(30), - saveReplay: options.replay, - replaySettings: options.replaySettings, - permanentLive: options.permanent - } - - const { uuid } = await servers[0].live.create({ fields: attributes }) - return uuid - } - - async function publishLive (options: { permanent: boolean, replay: boolean, replaySettings?: { privacy: VideoPrivacy } }) { - liveVideoUUID = await createLiveWrapper(options) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - - const liveDetails = await servers[0].videos.get({ id: liveVideoUUID }) - - await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) - - return { ffmpegCommand, liveDetails } - } - - async function publishLiveAndDelete (options: { permanent: boolean, replay: boolean, replaySettings?: { privacy: VideoPrivacy } }) { - const { ffmpegCommand, liveDetails } = await publishLive(options) - - await Promise.all([ - servers[0].videos.remove({ id: liveVideoUUID }), - testFfmpegStreamError(ffmpegCommand, true) - ]) - - await waitJobs(servers) - await wait(5000) - await waitJobs(servers) - - return { liveDetails } - } - - async function publishLiveAndBlacklist (options: { permanent: boolean, replay: boolean, replaySettings?: { privacy: VideoPrivacy } }) { - const { ffmpegCommand, liveDetails } = await publishLive(options) - - await Promise.all([ - servers[0].blacklist.add({ videoId: liveVideoUUID, reason: 'bad live', unfederate: true }), - testFfmpegStreamError(ffmpegCommand, true) - ]) - - await waitJobs(servers) - await wait(5000) - await waitJobs(servers) - - return { liveDetails } - } - - async function checkVideosExist (videoId: string, existsInList: boolean, expectedStatus?: number) { - for (const server of servers) { - const length = existsInList ? 1 : 0 - - const { data, total } = await server.videos.list() - expect(data).to.have.lengthOf(length) - expect(total).to.equal(length) - - if (expectedStatus) { - await server.videos.get({ id: videoId, expectedStatus }) - } - } - } - - async function checkVideoState (videoId: string, state: VideoState) { - for (const server of servers) { - const video = await server.videos.get({ id: videoId }) - expect(video.state.id).to.equal(state) - } - } - - async function checkVideoPrivacy (videoId: string, privacy: VideoPrivacy) { - for (const server of servers) { - const video = await server.videos.get({ id: videoId }) - expect(video.privacy.id).to.equal(privacy) - } - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - maxDuration: -1, - transcoding: { - enabled: false, - resolutions: ConfigCommand.getCustomConfigResolutions(true) - } - } - } - }) - }) - - describe('With save replay disabled', function () { - let sessionStartDateMin: Date - let sessionStartDateMax: Date - let sessionEndDateMin: Date - - it('Should correctly create and federate the "waiting for stream" live', async function () { - this.timeout(40000) - - liveVideoUUID = await createLiveWrapper({ permanent: false, replay: false }) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) - }) - - it('Should correctly have updated the live and federated it when streaming in the live', async function () { - this.timeout(120000) - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - - sessionStartDateMin = new Date() - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - sessionStartDateMax = new Date() - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) - }) - - it('Should correctly delete the video files after the stream ended', async function () { - this.timeout(120000) - - sessionEndDateMin = new Date() - await stopFfmpeg(ffmpegCommand) - - for (const server of servers) { - await server.live.waitUntilEnded({ videoId: liveVideoUUID }) - } - await waitJobs(servers) - - // Live still exist, but cannot be played anymore - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED) - - // No resolutions saved since we did not save replay - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - - it('Should have appropriate ended session', async function () { - const { data, total } = await servers[0].live.listSessions({ videoId: liveVideoUUID }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const session = data[0] - - const startDate = new Date(session.startDate) - expect(startDate).to.be.above(sessionStartDateMin) - expect(startDate).to.be.below(sessionStartDateMax) - - expect(session.endDate).to.exist - expect(new Date(session.endDate)).to.be.above(sessionEndDateMin) - - expect(session.saveReplay).to.be.false - expect(session.error).to.not.exist - expect(session.replayVideo).to.not.exist - }) - - it('Should correctly terminate the stream on blacklist and delete the live', async function () { - this.timeout(120000) - - await publishLiveAndBlacklist({ permanent: false, replay: false }) - - await checkVideosExist(liveVideoUUID, false) - - await servers[0].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await servers[1].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - - await wait(5000) - await waitJobs(servers) - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - - it('Should have blacklisted session error', async function () { - const session = await servers[0].live.findLatestSession({ videoId: liveVideoUUID }) - expect(session.startDate).to.exist - expect(session.endDate).to.exist - - expect(session.error).to.equal(LiveVideoError.BLACKLISTED) - expect(session.replayVideo).to.not.exist - }) - - it('Should correctly terminate the stream on delete and delete the video', async function () { - this.timeout(120000) - - await publishLiveAndDelete({ permanent: false, replay: false }) - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - }) - - describe('With save replay enabled on non permanent live', function () { - - it('Should correctly create and federate the "waiting for stream" live', async function () { - this.timeout(120000) - - liveVideoUUID = await createLiveWrapper({ permanent: false, replay: true, replaySettings: { privacy: VideoPrivacy.UNLISTED } }) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC) - }) - - it('Should correctly have updated the live and federated it when streaming in the live', async function () { - this.timeout(120000) - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC) - }) - - it('Should correctly have saved the live and federated it after the streaming', async function () { - this.timeout(120000) - - const session = await servers[0].live.findLatestSession({ videoId: liveVideoUUID }) - expect(session.endDate).to.not.exist - expect(session.endingProcessed).to.be.false - expect(session.saveReplay).to.be.true - expect(session.replaySettings).to.exist - expect(session.replaySettings.privacy).to.equal(VideoPrivacy.UNLISTED) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - // Live has been transcoded - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.UNLISTED) - }) - - it('Should find the replay live session', async function () { - const session = await servers[0].live.getReplaySession({ videoId: liveVideoUUID }) - - expect(session).to.exist - - expect(session.startDate).to.exist - expect(session.endDate).to.exist - - expect(session.error).to.not.exist - expect(session.saveReplay).to.be.true - expect(session.endingProcessed).to.be.true - expect(session.replaySettings).to.exist - expect(session.replaySettings.privacy).to.equal(VideoPrivacy.UNLISTED) - - expect(session.replayVideo).to.exist - expect(session.replayVideo.id).to.exist - expect(session.replayVideo.shortUUID).to.exist - expect(session.replayVideo.uuid).to.equal(liveVideoUUID) - }) - - it('Should update the saved live and correctly federate the updated attributes', async function () { - this.timeout(120000) - - await servers[0].videos.update({ id: liveVideoUUID, attributes: { name: 'video updated', privacy: VideoPrivacy.PUBLIC } }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: liveVideoUUID }) - expect(video.name).to.equal('video updated') - expect(video.isLive).to.be.false - expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC) - } - }) - - it('Should have cleaned up the live files', async function () { - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false, savedResolutions: [ 720 ] }) - }) - - it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { - this.timeout(120000) - - await publishLiveAndBlacklist({ permanent: false, replay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }) - - await checkVideosExist(liveVideoUUID, false) - - await servers[0].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await servers[1].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - - await wait(5000) - await waitJobs(servers) - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false, savedResolutions: [ 720 ] }) - }) - - it('Should correctly terminate the stream on delete and delete the video', async function () { - this.timeout(120000) - - await publishLiveAndDelete({ permanent: false, replay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }) - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - }) - - describe('With save replay enabled on permanent live', function () { - let lastReplayUUID: string - - describe('With a first live and its replay', function () { - - it('Should correctly create and federate the "waiting for stream" live', async function () { - this.timeout(120000) - - liveVideoUUID = await createLiveWrapper({ permanent: true, replay: true, replaySettings: { privacy: VideoPrivacy.UNLISTED } }) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC) - }) - - it('Should correctly have updated the live and federated it when streaming in the live', async function () { - this.timeout(120000) - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC) - }) - - it('Should correctly have saved the live and federated it after the streaming', async function () { - this.timeout(120000) - - const liveDetails = await servers[0].videos.get({ id: liveVideoUUID }) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveWaitingOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - const video = await findExternalSavedVideo(servers[0], liveDetails) - expect(video).to.exist - - for (const server of servers) { - await server.videos.get({ id: video.uuid }) - } - - lastReplayUUID = video.uuid - }) - - it('Should have appropriate ended session and replay live session', async function () { - const { data, total } = await servers[0].live.listSessions({ videoId: liveVideoUUID }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const sessionFromLive = data[0] - const sessionFromReplay = await servers[0].live.getReplaySession({ videoId: lastReplayUUID }) - - for (const session of [ sessionFromLive, sessionFromReplay ]) { - expect(session.startDate).to.exist - expect(session.endDate).to.exist - - expect(session.replaySettings).to.exist - expect(session.replaySettings.privacy).to.equal(VideoPrivacy.UNLISTED) - - expect(session.error).to.not.exist - - expect(session.replayVideo).to.exist - expect(session.replayVideo.id).to.exist - expect(session.replayVideo.shortUUID).to.exist - expect(session.replayVideo.uuid).to.equal(lastReplayUUID) - } - }) - - it('Should have the first live replay with correct settings', async function () { - await checkVideosExist(lastReplayUUID, false, HttpStatusCode.OK_200) - await checkVideoState(lastReplayUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(lastReplayUUID, VideoPrivacy.UNLISTED) - }) - }) - - describe('With a second live and its replay', function () { - - it('Should update the replay settings', async function () { - await servers[0].live.update({ videoId: liveVideoUUID, fields: { replaySettings: { privacy: VideoPrivacy.PUBLIC } } }) - await waitJobs(servers) - - const live = await servers[0].live.get({ videoId: liveVideoUUID }) - - expect(live.saveReplay).to.be.true - expect(live.replaySettings).to.exist - expect(live.replaySettings.privacy).to.equal(VideoPrivacy.PUBLIC) - - }) - - it('Should correctly have updated the live and federated it when streaming in the live', async function () { - this.timeout(120000) - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - - await waitJobs(servers) - - await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) - await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC) - }) - - it('Should correctly have saved the live and federated it after the streaming', async function () { - this.timeout(120000) - - const liveDetails = await servers[0].videos.get({ id: liveVideoUUID }) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveWaitingOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - const video = await findExternalSavedVideo(servers[0], liveDetails) - expect(video).to.exist - - for (const server of servers) { - await server.videos.get({ id: video.uuid }) - } - - lastReplayUUID = video.uuid - }) - - it('Should have appropriate ended session and replay live session', async function () { - const { data, total } = await servers[0].live.listSessions({ videoId: liveVideoUUID }) - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - const sessionFromLive = data[1] - const sessionFromReplay = await servers[0].live.getReplaySession({ videoId: lastReplayUUID }) - - for (const session of [ sessionFromLive, sessionFromReplay ]) { - expect(session.startDate).to.exist - expect(session.endDate).to.exist - - expect(session.replaySettings).to.exist - expect(session.replaySettings.privacy).to.equal(VideoPrivacy.PUBLIC) - - expect(session.error).to.not.exist - - expect(session.replayVideo).to.exist - expect(session.replayVideo.id).to.exist - expect(session.replayVideo.shortUUID).to.exist - expect(session.replayVideo.uuid).to.equal(lastReplayUUID) - } - }) - - it('Should have the first live replay with correct settings', async function () { - await checkVideosExist(lastReplayUUID, true, HttpStatusCode.OK_200) - await checkVideoState(lastReplayUUID, VideoState.PUBLISHED) - await checkVideoPrivacy(lastReplayUUID, VideoPrivacy.PUBLIC) - }) - - it('Should have cleaned up the live files', async function () { - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - - it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { - this.timeout(120000) - - await servers[0].videos.remove({ id: lastReplayUUID }) - const { liveDetails } = await publishLiveAndBlacklist({ - permanent: true, - replay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC } - }) - - const replay = await findExternalSavedVideo(servers[0], liveDetails) - expect(replay).to.exist - - for (const videoId of [ liveVideoUUID, replay.uuid ]) { - await checkVideosExist(videoId, false) - - await servers[0].videos.get({ id: videoId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await servers[1].videos.get({ id: videoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - - it('Should correctly terminate the stream on delete and not save the video', async function () { - this.timeout(120000) - - const { liveDetails } = await publishLiveAndDelete({ - permanent: true, - replay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC } - }) - - const replay = await findExternalSavedVideo(servers[0], liveDetails) - expect(replay).to.not.exist - - await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) - await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/live/live-socket-messages.ts b/server/tests/api/live/live-socket-messages.ts deleted file mode 100644 index 0cccd1594..000000000 --- a/server/tests/api/live/live-socket-messages.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { LiveVideoEventPayload, VideoPrivacy, VideoState } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs, - waitUntilLivePublishedOnAllServers -} from '@shared/server-commands' - -describe('Test live socket messages', function () { - let servers: PeerTubeServer[] = [] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - transcoding: { - enabled: false - } - } - } - }) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - describe('Live socket messages', function () { - - async function createLiveWrapper () { - const liveAttributes = { - name: 'live video', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - - const { uuid } = await servers[0].live.create({ fields: liveAttributes }) - return uuid - } - - it('Should correctly send a message when the live starts and ends', async function () { - this.timeout(60000) - - const localStateChanges: VideoState[] = [] - const remoteStateChanges: VideoState[] = [] - - const liveVideoUUID = await createLiveWrapper() - await waitJobs(servers) - - { - const videoId = await servers[0].videos.getId({ uuid: liveVideoUUID }) - - const localSocket = servers[0].socketIO.getLiveNotificationSocket() - localSocket.on('state-change', data => localStateChanges.push(data.state)) - localSocket.emit('subscribe', { videoId }) - } - - { - const videoId = await servers[1].videos.getId({ uuid: liveVideoUUID }) - - const remoteSocket = servers[1].socketIO.getLiveNotificationSocket() - remoteSocket.on('state-change', data => remoteStateChanges.push(data.state)) - remoteSocket.emit('subscribe', { videoId }) - } - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - for (const stateChanges of [ localStateChanges, remoteStateChanges ]) { - expect(stateChanges).to.have.length.at.least(1) - expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED) - } - - await stopFfmpeg(ffmpegCommand) - - for (const server of servers) { - await server.live.waitUntilEnded({ videoId: liveVideoUUID }) - } - await waitJobs(servers) - - for (const stateChanges of [ localStateChanges, remoteStateChanges ]) { - expect(stateChanges).to.have.length.at.least(2) - expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.LIVE_ENDED) - } - }) - - it('Should correctly send views change notification', async function () { - this.timeout(60000) - - let localLastVideoViews = 0 - let remoteLastVideoViews = 0 - - const liveVideoUUID = await createLiveWrapper() - await waitJobs(servers) - - { - const videoId = await servers[0].videos.getId({ uuid: liveVideoUUID }) - - const localSocket = servers[0].socketIO.getLiveNotificationSocket() - localSocket.on('views-change', (data: LiveVideoEventPayload) => { localLastVideoViews = data.viewers }) - localSocket.emit('subscribe', { videoId }) - } - - { - const videoId = await servers[1].videos.getId({ uuid: liveVideoUUID }) - - const remoteSocket = servers[1].socketIO.getLiveNotificationSocket() - remoteSocket.on('views-change', (data: LiveVideoEventPayload) => { remoteLastVideoViews = data.viewers }) - remoteSocket.emit('subscribe', { videoId }) - } - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - expect(localLastVideoViews).to.equal(0) - expect(remoteLastVideoViews).to.equal(0) - - await servers[0].views.simulateView({ id: liveVideoUUID }) - await servers[1].views.simulateView({ id: liveVideoUUID }) - - await waitJobs(servers) - - expect(localLastVideoViews).to.equal(2) - expect(remoteLastVideoViews).to.equal(2) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should not receive a notification after unsubscribe', async function () { - this.timeout(120000) - - const stateChanges: VideoState[] = [] - - const liveVideoUUID = await createLiveWrapper() - await waitJobs(servers) - - const videoId = await servers[0].videos.getId({ uuid: liveVideoUUID }) - - const socket = servers[0].socketIO.getLiveNotificationSocket() - socket.on('state-change', data => stateChanges.push(data.state)) - socket.emit('subscribe', { videoId }) - - const command = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) - await waitJobs(servers) - - // Notifier waits before sending a notification - await wait(10000) - - expect(stateChanges).to.have.lengthOf(1) - socket.emit('unsubscribe', { videoId }) - - await stopFfmpeg(command) - await waitJobs(servers) - - expect(stateChanges).to.have.lengthOf(1) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts deleted file mode 100644 index 2b302a8a2..000000000 --- a/server/tests/api/live/live.ts +++ /dev/null @@ -1,764 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { basename, join } from 'path' -import { SQLCommand, testImageGeneratedByFFmpeg, testLiveVideoResolutions } from '@server/tests/shared' -import { getAllFiles, wait } from '@shared/core-utils' -import { ffprobePromise, getVideoStream } from '@shared/ffmpeg' -import { - HttpStatusCode, - LiveVideo, - LiveVideoCreate, - LiveVideoLatencyMode, - VideoDetails, - VideoPrivacy, - VideoState, - VideoStreamingPlaylistType -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - LiveCommand, - makeGetRequest, - makeRawRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - testFfmpegStreamError, - waitJobs, - waitUntilLivePublishedOnAllServers -} from '@shared/server-commands' - -describe('Test live', function () { - let servers: PeerTubeServer[] = [] - let commands: LiveCommand[] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - latencySetting: { - enabled: true - }, - transcoding: { - enabled: false - } - } - } - }) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - commands = servers.map(s => s.live) - }) - - describe('Live creation, update and delete', function () { - let liveVideoUUID: string - - it('Should create a live with the appropriate parameters', async function () { - this.timeout(20000) - - const attributes: LiveVideoCreate = { - category: 1, - licence: 2, - language: 'fr', - description: 'super live description', - support: 'support field', - channelId: servers[0].store.channel.id, - nsfw: false, - waitTranscoding: false, - name: 'my super live', - tags: [ 'tag1', 'tag2' ], - commentsEnabled: false, - downloadEnabled: false, - saveReplay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC }, - latencyMode: LiveVideoLatencyMode.SMALL_LATENCY, - privacy: VideoPrivacy.PUBLIC, - previewfile: 'video_short1-preview.webm.jpg', - thumbnailfile: 'video_short1.webm.jpg' - } - - const live = await commands[0].create({ fields: attributes }) - liveVideoUUID = live.uuid - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: liveVideoUUID }) - - expect(video.category.id).to.equal(1) - expect(video.licence.id).to.equal(2) - expect(video.language.id).to.equal('fr') - expect(video.description).to.equal('super live description') - expect(video.support).to.equal('support field') - - expect(video.channel.name).to.equal(servers[0].store.channel.name) - expect(video.channel.host).to.equal(servers[0].store.channel.host) - - expect(video.isLive).to.be.true - - expect(video.nsfw).to.be.false - expect(video.waitTranscoding).to.be.false - expect(video.name).to.equal('my super live') - expect(video.tags).to.deep.equal([ 'tag1', 'tag2' ]) - expect(video.commentsEnabled).to.be.false - expect(video.downloadEnabled).to.be.false - expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC) - - await testImageGeneratedByFFmpeg(server.url, 'video_short1-preview.webm', video.previewPath) - await testImageGeneratedByFFmpeg(server.url, 'video_short1.webm', video.thumbnailPath) - - const live = await server.live.get({ videoId: liveVideoUUID }) - - if (server.url === servers[0].url) { - expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live') - expect(live.streamKey).to.not.be.empty - - expect(live.replaySettings).to.exist - expect(live.replaySettings.privacy).to.equal(VideoPrivacy.PUBLIC) - } else { - expect(live.rtmpUrl).to.not.exist - expect(live.streamKey).to.not.exist - } - - expect(live.saveReplay).to.be.true - expect(live.latencyMode).to.equal(LiveVideoLatencyMode.SMALL_LATENCY) - } - }) - - it('Should have a default preview and thumbnail', async function () { - this.timeout(20000) - - const attributes: LiveVideoCreate = { - name: 'default live thumbnail', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.UNLISTED, - nsfw: true - } - - const live = await commands[0].create({ fields: attributes }) - const videoId = live.uuid - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoId }) - expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) - expect(video.nsfw).to.be.true - - await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should not have the live listed since nobody streams into', async function () { - for (const server of servers) { - const { total, data } = await server.videos.list() - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - }) - - it('Should not be able to update a live of another server', async function () { - await commands[1].update({ videoId: liveVideoUUID, fields: { saveReplay: false }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should update the live', async function () { - await commands[0].update({ videoId: liveVideoUUID, fields: { saveReplay: false, latencyMode: LiveVideoLatencyMode.DEFAULT } }) - await waitJobs(servers) - }) - - it('Have the live updated', async function () { - for (const server of servers) { - const live = await server.live.get({ videoId: liveVideoUUID }) - - if (server.url === servers[0].url) { - expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live') - expect(live.streamKey).to.not.be.empty - } else { - expect(live.rtmpUrl).to.not.exist - expect(live.streamKey).to.not.exist - } - - expect(live.saveReplay).to.be.false - expect(live.replaySettings).to.not.exist - expect(live.latencyMode).to.equal(LiveVideoLatencyMode.DEFAULT) - } - }) - - it('Delete the live', async function () { - await servers[0].videos.remove({ id: liveVideoUUID }) - await waitJobs(servers) - }) - - it('Should have the live deleted', async function () { - for (const server of servers) { - await server.videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await server.live.get({ videoId: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - }) - - describe('Live filters', function () { - let ffmpegCommand: any - let liveVideoId: string - let vodVideoId: string - - before(async function () { - this.timeout(240000) - - vodVideoId = (await servers[0].videos.quickUpload({ name: 'vod video' })).uuid - - const liveOptions = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: servers[0].store.channel.id } - const live = await commands[0].create({ fields: liveOptions }) - liveVideoId = live.uuid - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoId }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - }) - - it('Should only display lives', async function () { - const { data, total } = await servers[0].videos.list({ isLive: true }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('live') - }) - - it('Should not display lives', async function () { - const { data, total } = await servers[0].videos.list({ isLive: false }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('vod video') - }) - - it('Should display my lives', async function () { - this.timeout(60000) - - await stopFfmpeg(ffmpegCommand) - await waitJobs(servers) - - const { data } = await servers[0].videos.listMyVideos({ isLive: true }) - - const result = data.every(v => v.isLive) - expect(result).to.be.true - }) - - it('Should not display my lives', async function () { - const { data } = await servers[0].videos.listMyVideos({ isLive: false }) - - const result = data.every(v => !v.isLive) - expect(result).to.be.true - }) - - after(async function () { - await servers[0].videos.remove({ id: vodVideoId }) - await servers[0].videos.remove({ id: liveVideoId }) - }) - }) - - describe('Stream checks', function () { - let liveVideo: LiveVideo & VideoDetails - let rtmpUrl: string - - before(function () { - rtmpUrl = 'rtmp://' + servers[0].hostname + ':' + servers[0].rtmpPort + '' - }) - - async function createLiveWrapper () { - const liveAttributes = { - name: 'user live', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - saveReplay: false - } - - const { uuid } = await commands[0].create({ fields: liveAttributes }) - - const live = await commands[0].get({ videoId: uuid }) - const video = await servers[0].videos.get({ id: uuid }) - - return Object.assign(video, live) - } - - it('Should not allow a stream without the appropriate path', async function () { - this.timeout(60000) - - liveVideo = await createLiveWrapper() - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl + '/bad-live', streamKey: liveVideo.streamKey }) - await testFfmpegStreamError(command, true) - }) - - it('Should not allow a stream without the appropriate stream key', async function () { - this.timeout(60000) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl + '/live', streamKey: 'bad-stream-key' }) - await testFfmpegStreamError(command, true) - }) - - it('Should succeed with the correct params', async function () { - this.timeout(60000) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl + '/live', streamKey: liveVideo.streamKey }) - await testFfmpegStreamError(command, false) - }) - - it('Should list this live now someone stream into it', async function () { - for (const server of servers) { - const { total, data } = await server.videos.list() - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const video = data[0] - expect(video.name).to.equal('user live') - expect(video.isLive).to.be.true - } - }) - - it('Should not allow a stream on a live that was blacklisted', async function () { - this.timeout(60000) - - liveVideo = await createLiveWrapper() - - await servers[0].blacklist.add({ videoId: liveVideo.uuid }) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl + '/live', streamKey: liveVideo.streamKey }) - await testFfmpegStreamError(command, true) - }) - - it('Should not allow a stream on a live that was deleted', async function () { - this.timeout(60000) - - liveVideo = await createLiveWrapper() - - await servers[0].videos.remove({ id: liveVideo.uuid }) - - const command = sendRTMPStream({ rtmpBaseUrl: rtmpUrl + '/live', streamKey: liveVideo.streamKey }) - await testFfmpegStreamError(command, true) - }) - }) - - describe('Live transcoding', function () { - let liveVideoId: string - let sqlCommandServer1: SQLCommand - - async function createLiveWrapper (saveReplay: boolean) { - const liveAttributes = { - name: 'live video', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - saveReplay, - replaySettings: saveReplay - ? { privacy: VideoPrivacy.PUBLIC } - : undefined - } - - const { uuid } = await commands[0].create({ fields: liveAttributes }) - return uuid - } - - function updateConf (resolutions: number[]) { - return servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - maxDuration: -1, - transcoding: { - enabled: true, - resolutions: { - '144p': resolutions.includes(144), - '240p': resolutions.includes(240), - '360p': resolutions.includes(360), - '480p': resolutions.includes(480), - '720p': resolutions.includes(720), - '1080p': resolutions.includes(1080), - '2160p': resolutions.includes(2160) - } - } - } - } - }) - } - - before(async function () { - await updateConf([]) - - sqlCommandServer1 = new SQLCommand(servers[0]) - }) - - it('Should enable transcoding without additional resolutions', async function () { - this.timeout(120000) - - liveVideoId = await createLiveWrapper(false) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId, - resolutions: [ 720 ], - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should transcode audio only RTMP stream', async function () { - this.timeout(120000) - - liveVideoId = await createLiveWrapper(false) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short_no_audio.mp4' }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should enable transcoding with some resolutions', async function () { - this.timeout(240000) - - const resolutions = [ 240, 480 ] - await updateConf(resolutions) - liveVideoId = await createLiveWrapper(false) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId, - resolutions: resolutions.concat([ 720 ]), - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should correctly set the appropriate bitrate depending on the input', async function () { - this.timeout(120000) - - liveVideoId = await createLiveWrapper(false) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ - videoId: liveVideoId, - fixtureName: 'video_short.mp4', - copyCodecs: true - }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: liveVideoId }) - - const masterPlaylist = video.streamingPlaylists[0].playlistUrl - const probe = await ffprobePromise(masterPlaylist) - - const bitrates = probe.streams.map(s => parseInt(s.tags.variant_bitrate)) - for (const bitrate of bitrates) { - expect(bitrate).to.exist - expect(isNaN(bitrate)).to.be.false - expect(bitrate).to.be.below(61_000_000) // video_short.mp4 bitrate - } - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should enable transcoding with some resolutions and correctly save them', async function () { - this.timeout(500_000) - - const resolutions = [ 240, 360, 720 ] - - await updateConf(resolutions) - liveVideoId = await createLiveWrapper(true) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId, - resolutions, - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - await commands[0].waitUntilEnded({ videoId: liveVideoId }) - - await waitJobs(servers) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - - const maxBitrateLimits = { - 720: 6500 * 1000, // 60FPS - 360: 1250 * 1000, - 240: 700 * 1000 - } - - const minBitrateLimits = { - 720: 4800 * 1000, - 360: 1000 * 1000, - 240: 550 * 1000 - } - - for (const server of servers) { - const video = await server.videos.get({ id: liveVideoId }) - - expect(video.state.id).to.equal(VideoState.PUBLISHED) - expect(video.duration).to.be.greaterThan(1) - expect(video.files).to.have.lengthOf(0) - - const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) - await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) - - // We should have generated random filenames - expect(basename(hlsPlaylist.playlistUrl)).to.not.equal('master.m3u8') - expect(basename(hlsPlaylist.segmentsSha256Url)).to.not.equal('segments-sha256.json') - - expect(hlsPlaylist.files).to.have.lengthOf(resolutions.length) - - for (const resolution of resolutions) { - const file = hlsPlaylist.files.find(f => f.resolution.id === resolution) - - expect(file).to.exist - expect(file.size).to.be.greaterThan(1) - - if (resolution >= 720) { - expect(file.fps).to.be.approximately(60, 10) - } else { - expect(file.fps).to.be.approximately(30, 3) - } - - const filename = basename(file.fileUrl) - expect(filename).to.not.contain(video.uuid) - - const segmentPath = servers[0].servers.buildDirectory(join('streaming-playlists', 'hls', video.uuid, filename)) - - const probe = await ffprobePromise(segmentPath) - const videoStream = await getVideoStream(segmentPath, probe) - - expect(probe.format.bit_rate).to.be.below(maxBitrateLimits[videoStream.height]) - expect(probe.format.bit_rate).to.be.at.least(minBitrateLimits[videoStream.height]) - - await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - - it('Should not generate an upper resolution than original file', async function () { - this.timeout(500_000) - - const resolutions = [ 240, 480 ] - await updateConf(resolutions) - - await servers[0].config.updateExistingSubConfig({ - newConfig: { - live: { - transcoding: { - alwaysTranscodeOriginalResolution: false - } - } - } - }) - - liveVideoId = await createLiveWrapper(true) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId, - resolutions, - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - await commands[0].waitUntilEnded({ videoId: liveVideoId }) - - await waitJobs(servers) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - - const video = await servers[0].videos.get({ id: liveVideoId }) - const hlsFiles = video.streamingPlaylists[0].files - - expect(video.files).to.have.lengthOf(0) - expect(hlsFiles).to.have.lengthOf(resolutions.length) - - // eslint-disable-next-line @typescript-eslint/require-array-sort-compare - expect(getAllFiles(video).map(f => f.resolution.id).sort()).to.deep.equal(resolutions) - }) - - it('Should only keep the original resolution if all resolutions are disabled', async function () { - this.timeout(600_000) - - await updateConf([]) - liveVideoId = await createLiveWrapper(true) - - const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' }) - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId, - resolutions: [ 720 ], - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - await commands[0].waitUntilEnded({ videoId: liveVideoId }) - - await waitJobs(servers) - - await waitUntilLivePublishedOnAllServers(servers, liveVideoId) - - const video = await servers[0].videos.get({ id: liveVideoId }) - const hlsFiles = video.streamingPlaylists[0].files - - expect(video.files).to.have.lengthOf(0) - expect(hlsFiles).to.have.lengthOf(1) - - expect(hlsFiles[0].resolution.id).to.equal(720) - }) - - after(async function () { - await sqlCommandServer1.cleanup() - }) - }) - - describe('After a server restart', function () { - let liveVideoId: string - let liveVideoReplayId: string - let permanentLiveVideoReplayId: string - - let permanentLiveReplayName: string - - let beforeServerRestart: Date - - async function createLiveWrapper (options: { saveReplay: boolean, permanent: boolean }) { - const liveAttributes: LiveVideoCreate = { - name: 'live video', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - saveReplay: options.saveReplay, - replaySettings: options.saveReplay - ? { privacy: VideoPrivacy.PUBLIC } - : undefined, - permanentLive: options.permanent - } - - const { uuid } = await commands[0].create({ fields: liveAttributes }) - return uuid - } - - before(async function () { - this.timeout(600_000) - - liveVideoId = await createLiveWrapper({ saveReplay: false, permanent: false }) - liveVideoReplayId = await createLiveWrapper({ saveReplay: true, permanent: false }) - permanentLiveVideoReplayId = await createLiveWrapper({ saveReplay: true, permanent: true }) - - await Promise.all([ - commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId }), - commands[0].sendRTMPStreamInVideo({ videoId: permanentLiveVideoReplayId }), - commands[0].sendRTMPStreamInVideo({ videoId: liveVideoReplayId }) - ]) - - await Promise.all([ - commands[0].waitUntilPublished({ videoId: liveVideoId }), - commands[0].waitUntilPublished({ videoId: permanentLiveVideoReplayId }), - commands[0].waitUntilPublished({ videoId: liveVideoReplayId }) - ]) - - for (const videoUUID of [ liveVideoId, liveVideoReplayId, permanentLiveVideoReplayId ]) { - await commands[0].waitUntilSegmentGeneration({ - server: servers[0], - videoUUID, - playlistNumber: 0, - segment: 2 - }) - } - - { - const video = await servers[0].videos.get({ id: permanentLiveVideoReplayId }) - permanentLiveReplayName = video.name + ' - ' + new Date(video.publishedAt).toLocaleString() - } - - await killallServers([ servers[0] ]) - - beforeServerRestart = new Date() - await servers[0].run() - - await wait(5000) - await waitJobs(servers) - }) - - it('Should cleanup lives', async function () { - this.timeout(60000) - - await commands[0].waitUntilEnded({ videoId: liveVideoId }) - await commands[0].waitUntilWaiting({ videoId: permanentLiveVideoReplayId }) - }) - - it('Should save a non permanent live replay', async function () { - this.timeout(240000) - - await commands[0].waitUntilPublished({ videoId: liveVideoReplayId }) - - const session = await commands[0].getReplaySession({ videoId: liveVideoReplayId }) - expect(session.endDate).to.exist - expect(new Date(session.endDate)).to.be.above(beforeServerRestart) - }) - - it('Should have saved a permanent live replay', async function () { - this.timeout(120000) - - const { data } = await servers[0].videos.listMyVideos({ sort: '-publishedAt' }) - expect(data.find(v => v.name === permanentLiveReplayName)).to.exist - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/moderation/abuses.ts b/server/tests/api/moderation/abuses.ts deleted file mode 100644 index 9fc296ea8..000000000 --- a/server/tests/api/moderation/abuses.ts +++ /dev/null @@ -1,887 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { AbuseMessage, AbusePredefinedReasonsString, AbuseState, AdminAbuse, UserAbuse } from '@shared/models' -import { - AbusesCommand, - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test abuses', function () { - let servers: PeerTubeServer[] = [] - let abuseServer1: AdminAbuse - let abuseServer2: AdminAbuse - let commands: AbusesCommand[] - - before(async function () { - this.timeout(50000) - - // Run servers - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultChannelAvatar(servers) - await setDefaultAccountAvatar(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - commands = servers.map(s => s.abuses) - }) - - describe('Video abuses', function () { - - before(async function () { - this.timeout(50000) - - // Upload some videos on each servers - { - const attributes = { - name: 'my super name for server 1', - description: 'my super description for server 1' - } - await servers[0].videos.upload({ attributes }) - } - - { - const attributes = { - name: 'my super name for server 2', - description: 'my super description for server 2' - } - await servers[1].videos.upload({ attributes }) - } - - // Wait videos propagation, server 2 has transcoding enabled - await waitJobs(servers) - - const { data } = await servers[0].videos.list() - expect(data.length).to.equal(2) - - servers[0].store.videoCreated = data.find(video => video.name === 'my super name for server 1') - servers[1].store.videoCreated = data.find(video => video.name === 'my super name for server 2') - }) - - it('Should not have abuses', async function () { - const body = await commands[0].getAdminList() - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - }) - - it('Should report abuse on a local video', async function () { - this.timeout(15000) - - const reason = 'my super bad reason' - await commands[0].report({ videoId: servers[0].store.videoCreated.id, reason }) - - // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2 - await waitJobs(servers) - }) - - it('Should have 1 video abuses on server 1 and 0 on server 2', async function () { - { - const body = await commands[0].getAdminList() - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(1) - - const abuse = body.data[0] - expect(abuse.reason).to.equal('my super bad reason') - - expect(abuse.reporterAccount.name).to.equal('root') - expect(abuse.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse.video.id).to.equal(servers[0].store.videoCreated.id) - expect(abuse.video.channel).to.exist - - expect(abuse.comment).to.be.null - - expect(abuse.flaggedAccount.name).to.equal('root') - expect(abuse.flaggedAccount.host).to.equal(servers[0].host) - - expect(abuse.video.countReports).to.equal(1) - expect(abuse.video.nthReport).to.equal(1) - - expect(abuse.countReportsForReporter).to.equal(1) - expect(abuse.countReportsForReportee).to.equal(1) - } - - { - const body = await commands[1].getAdminList() - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - }) - - it('Should report abuse on a remote video', async function () { - const reason = 'my super bad reason 2' - const videoId = await servers[0].videos.getId({ uuid: servers[1].store.videoCreated.uuid }) - await commands[0].report({ videoId, reason }) - - // We wait requests propagation - await waitJobs(servers) - }) - - it('Should have 2 video abuses on server 1 and 1 on server 2', async function () { - { - const body = await commands[0].getAdminList() - - expect(body.total).to.equal(2) - expect(body.data.length).to.equal(2) - - const abuse1 = body.data[0] - expect(abuse1.reason).to.equal('my super bad reason') - expect(abuse1.reporterAccount.name).to.equal('root') - expect(abuse1.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse1.video.id).to.equal(servers[0].store.videoCreated.id) - expect(abuse1.video.countReports).to.equal(1) - expect(abuse1.video.nthReport).to.equal(1) - - expect(abuse1.comment).to.be.null - - expect(abuse1.flaggedAccount.name).to.equal('root') - expect(abuse1.flaggedAccount.host).to.equal(servers[0].host) - - expect(abuse1.state.id).to.equal(AbuseState.PENDING) - expect(abuse1.state.label).to.equal('Pending') - expect(abuse1.moderationComment).to.be.null - - const abuse2 = body.data[1] - expect(abuse2.reason).to.equal('my super bad reason 2') - - expect(abuse2.reporterAccount.name).to.equal('root') - expect(abuse2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse2.video.uuid).to.equal(servers[1].store.videoCreated.uuid) - - expect(abuse2.comment).to.be.null - - expect(abuse2.flaggedAccount.name).to.equal('root') - expect(abuse2.flaggedAccount.host).to.equal(servers[1].host) - - expect(abuse2.state.id).to.equal(AbuseState.PENDING) - expect(abuse2.state.label).to.equal('Pending') - expect(abuse2.moderationComment).to.be.null - } - - { - const body = await commands[1].getAdminList() - expect(body.total).to.equal(1) - expect(body.data.length).to.equal(1) - - abuseServer2 = body.data[0] - expect(abuseServer2.reason).to.equal('my super bad reason 2') - expect(abuseServer2.reporterAccount.name).to.equal('root') - expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuseServer2.flaggedAccount.name).to.equal('root') - expect(abuseServer2.flaggedAccount.host).to.equal(servers[1].host) - - expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) - expect(abuseServer2.state.label).to.equal('Pending') - expect(abuseServer2.moderationComment).to.be.null - } - }) - - it('Should hide video abuses from blocked accounts', async function () { - { - const videoId = await servers[1].videos.getId({ uuid: servers[0].store.videoCreated.uuid }) - await commands[1].report({ videoId, reason: 'will mute this' }) - await waitJobs(servers) - - const body = await commands[0].getAdminList() - expect(body.total).to.equal(3) - } - - const accountToBlock = 'root@' + servers[1].host - - { - await servers[0].blocklist.addToServerBlocklist({ account: accountToBlock }) - - const body = await commands[0].getAdminList() - expect(body.total).to.equal(2) - - const abuse = body.data.find(a => a.reason === 'will mute this') - expect(abuse).to.be.undefined - } - - { - await servers[0].blocklist.removeFromServerBlocklist({ account: accountToBlock }) - - const body = await commands[0].getAdminList() - expect(body.total).to.equal(3) - } - }) - - it('Should hide video abuses from blocked servers', async function () { - const serverToBlock = servers[1].host - - { - await servers[0].blocklist.addToServerBlocklist({ server: serverToBlock }) - - const body = await commands[0].getAdminList() - expect(body.total).to.equal(2) - - const abuse = body.data.find(a => a.reason === 'will mute this') - expect(abuse).to.be.undefined - } - - { - await servers[0].blocklist.removeFromServerBlocklist({ server: serverToBlock }) - - const body = await commands[0].getAdminList() - expect(body.total).to.equal(3) - } - }) - - it('Should keep the video abuse when deleting the video', async function () { - await servers[1].videos.remove({ id: abuseServer2.video.uuid }) - - await waitJobs(servers) - - const body = await commands[1].getAdminList() - expect(body.total).to.equal(2, 'wrong number of videos returned') - expect(body.data).to.have.lengthOf(2, 'wrong number of videos returned') - - const abuse = body.data[0] - expect(abuse.id).to.equal(abuseServer2.id, 'wrong origin server id for first video') - expect(abuse.video.id).to.equal(abuseServer2.video.id, 'wrong video id') - expect(abuse.video.channel).to.exist - expect(abuse.video.deleted).to.be.true - }) - - it('Should include counts of reports from reporter and reportee', async function () { - // register a second user to have two reporters/reportees - const user = { username: 'user2', password: 'password' } - await servers[0].users.create({ ...user }) - const userAccessToken = await servers[0].login.getAccessToken(user) - - // upload a third video via this user - const attributes = { - name: 'my second super name for server 1', - description: 'my second super description for server 1' - } - const { id } = await servers[0].videos.upload({ token: userAccessToken, attributes }) - const video3Id = id - - // resume with the test - const reason3 = 'my super bad reason 3' - await commands[0].report({ videoId: video3Id, reason: reason3 }) - - const reason4 = 'my super bad reason 4' - await commands[0].report({ token: userAccessToken, videoId: servers[0].store.videoCreated.id, reason: reason4 }) - - { - const body = await commands[0].getAdminList() - const abuses = body.data - - const abuseVideo3 = body.data.find(a => a.video.id === video3Id) - expect(abuseVideo3).to.not.be.undefined - expect(abuseVideo3.video.countReports).to.equal(1, 'wrong reports count for video 3') - expect(abuseVideo3.video.nthReport).to.equal(1, 'wrong report position in report list for video 3') - expect(abuseVideo3.countReportsForReportee).to.equal(1, 'wrong reports count for reporter on video 3 abuse') - expect(abuseVideo3.countReportsForReporter).to.equal(3, 'wrong reports count for reportee on video 3 abuse') - - const abuseServer1 = abuses.find(a => a.video.id === servers[0].store.videoCreated.id) - expect(abuseServer1.countReportsForReportee).to.equal(3, 'wrong reports count for reporter on video 1 abuse') - } - }) - - it('Should list predefined reasons as well as timestamps for the reported video', async function () { - const reason5 = 'my super bad reason 5' - const predefinedReasons5: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ] - const createRes = await commands[0].report({ - videoId: servers[0].store.videoCreated.id, - reason: reason5, - predefinedReasons: predefinedReasons5, - startAt: 1, - endAt: 5 - }) - - const body = await commands[0].getAdminList() - - { - const abuse = body.data.find(a => a.id === createRes.abuse.id) - expect(abuse.reason).to.equals(reason5) - expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, 'predefined reasons do not match the one reported') - expect(abuse.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported") - expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported") - } - }) - - it('Should delete the video abuse', async function () { - await commands[1].delete({ abuseId: abuseServer2.id }) - - await waitJobs(servers) - - { - const body = await commands[1].getAdminList() - expect(body.total).to.equal(1) - expect(body.data.length).to.equal(1) - expect(body.data[0].id).to.not.equal(abuseServer2.id) - } - - { - const body = await commands[0].getAdminList() - expect(body.total).to.equal(6) - } - }) - - it('Should list and filter video abuses', async function () { - async function list (query: Parameters[0]) { - const body = await commands[0].getAdminList(query) - - return body.data - } - - expect(await list({ id: 56 })).to.have.lengthOf(0) - expect(await list({ id: 1 })).to.have.lengthOf(1) - - expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4) - expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0) - - expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1) - - expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4) - expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0) - - expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1) - expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5) - - expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5) - expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0) - - expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1) - expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0) - - expect(await list({ state: AbuseState.ACCEPTED })).to.have.lengthOf(0) - expect(await list({ state: AbuseState.PENDING })).to.have.lengthOf(6) - - expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1) - expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0) - }) - }) - - describe('Comment abuses', function () { - - async function getComment (server: PeerTubeServer, videoIdArg: number | string) { - const videoId = typeof videoIdArg === 'string' - ? await server.videos.getId({ uuid: videoIdArg }) - : videoIdArg - - const { data } = await server.comments.listThreads({ videoId }) - - return data[0] - } - - before(async function () { - this.timeout(50000) - - servers[0].store.videoCreated = await servers[0].videos.quickUpload({ name: 'server 1' }) - servers[1].store.videoCreated = await servers[1].videos.quickUpload({ name: 'server 2' }) - - await servers[0].comments.createThread({ videoId: servers[0].store.videoCreated.id, text: 'comment server 1' }) - await servers[1].comments.createThread({ videoId: servers[1].store.videoCreated.id, text: 'comment server 2' }) - - await waitJobs(servers) - }) - - it('Should report abuse on a comment', async function () { - this.timeout(15000) - - const comment = await getComment(servers[0], servers[0].store.videoCreated.id) - - const reason = 'it is a bad comment' - await commands[0].report({ commentId: comment.id, reason }) - - await waitJobs(servers) - }) - - it('Should have 1 comment abuse on server 1 and 0 on server 2', async function () { - { - const comment = await getComment(servers[0], servers[0].store.videoCreated.id) - const body = await commands[0].getAdminList({ filter: 'comment' }) - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const abuse = body.data[0] - expect(abuse.reason).to.equal('it is a bad comment') - - expect(abuse.reporterAccount.name).to.equal('root') - expect(abuse.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse.video).to.be.null - - expect(abuse.comment.deleted).to.be.false - expect(abuse.comment.id).to.equal(comment.id) - expect(abuse.comment.text).to.equal(comment.text) - expect(abuse.comment.video.name).to.equal('server 1') - expect(abuse.comment.video.id).to.equal(servers[0].store.videoCreated.id) - expect(abuse.comment.video.uuid).to.equal(servers[0].store.videoCreated.uuid) - - expect(abuse.countReportsForReporter).to.equal(5) - expect(abuse.countReportsForReportee).to.equal(5) - } - - { - const body = await commands[1].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(0) - expect(body.data.length).to.equal(0) - } - }) - - it('Should report abuse on a remote comment', async function () { - const comment = await getComment(servers[0], servers[1].store.videoCreated.uuid) - - const reason = 'it is a really bad comment' - await commands[0].report({ commentId: comment.id, reason }) - - await waitJobs(servers) - }) - - it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { - const commentServer2 = await getComment(servers[0], servers[1].store.videoCreated.shortUUID) - - { - const body = await commands[0].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(2) - expect(body.data.length).to.equal(2) - - const abuse = body.data[0] - expect(abuse.reason).to.equal('it is a bad comment') - expect(abuse.countReportsForReporter).to.equal(6) - expect(abuse.countReportsForReportee).to.equal(5) - - const abuse2 = body.data[1] - - expect(abuse2.reason).to.equal('it is a really bad comment') - - expect(abuse2.reporterAccount.name).to.equal('root') - expect(abuse2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse2.video).to.be.null - - expect(abuse2.comment.deleted).to.be.false - expect(abuse2.comment.id).to.equal(commentServer2.id) - expect(abuse2.comment.text).to.equal(commentServer2.text) - expect(abuse2.comment.video.name).to.equal('server 2') - expect(abuse2.comment.video.uuid).to.equal(servers[1].store.videoCreated.uuid) - - expect(abuse2.state.id).to.equal(AbuseState.PENDING) - expect(abuse2.state.label).to.equal('Pending') - - expect(abuse2.moderationComment).to.be.null - - expect(abuse2.countReportsForReporter).to.equal(6) - expect(abuse2.countReportsForReportee).to.equal(2) - } - - { - const body = await commands[1].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(1) - expect(body.data.length).to.equal(1) - - abuseServer2 = body.data[0] - expect(abuseServer2.reason).to.equal('it is a really bad comment') - expect(abuseServer2.reporterAccount.name).to.equal('root') - expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) - expect(abuseServer2.state.label).to.equal('Pending') - - expect(abuseServer2.moderationComment).to.be.null - - expect(abuseServer2.countReportsForReporter).to.equal(1) - expect(abuseServer2.countReportsForReportee).to.equal(1) - } - }) - - it('Should keep the comment abuse when deleting the comment', async function () { - const commentServer2 = await getComment(servers[0], servers[1].store.videoCreated.uuid) - - await servers[0].comments.delete({ videoId: servers[1].store.videoCreated.uuid, commentId: commentServer2.id }) - - await waitJobs(servers) - - const body = await commands[0].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - const abuse = body.data.find(a => a.comment?.id === commentServer2.id) - expect(abuse).to.not.be.undefined - - expect(abuse.comment.text).to.be.empty - expect(abuse.comment.video.name).to.equal('server 2') - expect(abuse.comment.deleted).to.be.true - }) - - it('Should delete the comment abuse', async function () { - await commands[1].delete({ abuseId: abuseServer2.id }) - - await waitJobs(servers) - - { - const body = await commands[1].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(0) - expect(body.data.length).to.equal(0) - } - - { - const body = await commands[0].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(2) - } - }) - - it('Should list and filter video abuses', async function () { - { - const body = await commands[0].getAdminList({ filter: 'comment', searchReportee: 'foo' }) - expect(body.total).to.equal(0) - } - - { - const body = await commands[0].getAdminList({ filter: 'comment', searchReportee: 'ot' }) - expect(body.total).to.equal(2) - } - - { - const body = await commands[0].getAdminList({ filter: 'comment', start: 1, count: 1, sort: 'createdAt' }) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].comment.text).to.be.empty - } - - { - const body = await commands[0].getAdminList({ filter: 'comment', start: 1, count: 1, sort: '-createdAt' }) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].comment.text).to.equal('comment server 1') - } - }) - }) - - describe('Account abuses', function () { - - function getAccountFromServer (server: PeerTubeServer, targetName: string, targetServer: PeerTubeServer) { - return server.accounts.get({ accountName: targetName + '@' + targetServer.host }) - } - - before(async function () { - this.timeout(50000) - - await servers[0].users.create({ username: 'user_1', password: 'donald' }) - - const token = await servers[1].users.generateUserAndToken('user_2') - await servers[1].videos.upload({ token, attributes: { name: 'super video' } }) - - await waitJobs(servers) - }) - - it('Should report abuse on an account', async function () { - this.timeout(15000) - - const account = await getAccountFromServer(servers[0], 'user_1', servers[0]) - - const reason = 'it is a bad account' - await commands[0].report({ accountId: account.id, reason }) - - await waitJobs(servers) - }) - - it('Should have 1 account abuse on server 1 and 0 on server 2', async function () { - { - const body = await commands[0].getAdminList({ filter: 'account' }) - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const abuse = body.data[0] - expect(abuse.reason).to.equal('it is a bad account') - - expect(abuse.reporterAccount.name).to.equal('root') - expect(abuse.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse.video).to.be.null - expect(abuse.comment).to.be.null - - expect(abuse.flaggedAccount.name).to.equal('user_1') - expect(abuse.flaggedAccount.host).to.equal(servers[0].host) - } - - { - const body = await commands[1].getAdminList({ filter: 'comment' }) - expect(body.total).to.equal(0) - expect(body.data.length).to.equal(0) - } - }) - - it('Should report abuse on a remote account', async function () { - const account = await getAccountFromServer(servers[0], 'user_2', servers[1]) - - const reason = 'it is a really bad account' - await commands[0].report({ accountId: account.id, reason }) - - await waitJobs(servers) - }) - - it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { - { - const body = await commands[0].getAdminList({ filter: 'account' }) - expect(body.total).to.equal(2) - expect(body.data.length).to.equal(2) - - const abuse: AdminAbuse = body.data[0] - expect(abuse.reason).to.equal('it is a bad account') - - const abuse2: AdminAbuse = body.data[1] - expect(abuse2.reason).to.equal('it is a really bad account') - - expect(abuse2.reporterAccount.name).to.equal('root') - expect(abuse2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuse2.video).to.be.null - expect(abuse2.comment).to.be.null - - expect(abuse2.state.id).to.equal(AbuseState.PENDING) - expect(abuse2.state.label).to.equal('Pending') - - expect(abuse2.moderationComment).to.be.null - } - - { - const body = await commands[1].getAdminList({ filter: 'account' }) - expect(body.total).to.equal(1) - expect(body.data.length).to.equal(1) - - abuseServer2 = body.data[0] - - expect(abuseServer2.reason).to.equal('it is a really bad account') - - expect(abuseServer2.reporterAccount.name).to.equal('root') - expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) - - expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) - expect(abuseServer2.state.label).to.equal('Pending') - - expect(abuseServer2.moderationComment).to.be.null - } - }) - - it('Should keep the account abuse when deleting the account', async function () { - const account = await getAccountFromServer(servers[1], 'user_2', servers[1]) - await servers[1].users.remove({ userId: account.userId }) - - await waitJobs(servers) - - const body = await commands[0].getAdminList({ filter: 'account' }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - const abuse = body.data.find(a => a.reason === 'it is a really bad account') - expect(abuse).to.not.be.undefined - }) - - it('Should delete the account abuse', async function () { - await commands[1].delete({ abuseId: abuseServer2.id }) - - await waitJobs(servers) - - { - const body = await commands[1].getAdminList({ filter: 'account' }) - expect(body.total).to.equal(0) - expect(body.data.length).to.equal(0) - } - - { - const body = await commands[0].getAdminList({ filter: 'account' }) - expect(body.total).to.equal(2) - - abuseServer1 = body.data[0] - } - }) - }) - - describe('Common actions on abuses', function () { - - it('Should update the state of an abuse', async function () { - await commands[0].update({ abuseId: abuseServer1.id, body: { state: AbuseState.REJECTED } }) - - const body = await commands[0].getAdminList({ id: abuseServer1.id }) - expect(body.data[0].state.id).to.equal(AbuseState.REJECTED) - }) - - it('Should add a moderation comment', async function () { - await commands[0].update({ abuseId: abuseServer1.id, body: { state: AbuseState.ACCEPTED, moderationComment: 'Valid' } }) - - const body = await commands[0].getAdminList({ id: abuseServer1.id }) - expect(body.data[0].state.id).to.equal(AbuseState.ACCEPTED) - expect(body.data[0].moderationComment).to.equal('Valid') - }) - }) - - describe('My abuses', async function () { - let abuseId1: number - let userAccessToken: string - - before(async function () { - userAccessToken = await servers[0].users.generateUserAndToken('user_42') - - await commands[0].report({ token: userAccessToken, videoId: servers[0].store.videoCreated.id, reason: 'user reason 1' }) - - const videoId = await servers[0].videos.getId({ uuid: servers[1].store.videoCreated.uuid }) - await commands[0].report({ token: userAccessToken, videoId, reason: 'user reason 2' }) - }) - - it('Should correctly list my abuses', async function () { - { - const body = await commands[0].getUserList({ token: userAccessToken, start: 0, count: 5, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const abuses = body.data - expect(abuses[0].reason).to.equal('user reason 1') - expect(abuses[1].reason).to.equal('user reason 2') - - abuseId1 = abuses[0].id - } - - { - const body = await commands[0].getUserList({ token: userAccessToken, start: 1, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const abuses: UserAbuse[] = body.data - expect(abuses[0].reason).to.equal('user reason 2') - } - - { - const body = await commands[0].getUserList({ token: userAccessToken, start: 1, count: 1, sort: '-createdAt' }) - expect(body.total).to.equal(2) - - const abuses: UserAbuse[] = body.data - expect(abuses[0].reason).to.equal('user reason 1') - } - }) - - it('Should correctly filter my abuses by id', async function () { - const body = await commands[0].getUserList({ token: userAccessToken, id: abuseId1 }) - expect(body.total).to.equal(1) - - const abuses: UserAbuse[] = body.data - expect(abuses[0].reason).to.equal('user reason 1') - }) - - it('Should correctly filter my abuses by search', async function () { - const body = await commands[0].getUserList({ token: userAccessToken, search: 'server 2' }) - expect(body.total).to.equal(1) - - const abuses: UserAbuse[] = body.data - expect(abuses[0].reason).to.equal('user reason 2') - }) - - it('Should correctly filter my abuses by state', async function () { - await commands[0].update({ abuseId: abuseId1, body: { state: AbuseState.REJECTED } }) - - const body = await commands[0].getUserList({ token: userAccessToken, state: AbuseState.REJECTED }) - expect(body.total).to.equal(1) - - const abuses: UserAbuse[] = body.data - expect(abuses[0].reason).to.equal('user reason 1') - }) - }) - - describe('Abuse messages', async function () { - let abuseId: number - let userToken: string - let abuseMessageUserId: number - let abuseMessageModerationId: number - - before(async function () { - userToken = await servers[0].users.generateUserAndToken('user_43') - - const body = await commands[0].report({ token: userToken, videoId: servers[0].store.videoCreated.id, reason: 'user 43 reason 1' }) - abuseId = body.abuse.id - }) - - it('Should create some messages on the abuse', async function () { - await commands[0].addMessage({ token: userToken, abuseId, message: 'message 1' }) - await commands[0].addMessage({ abuseId, message: 'message 2' }) - await commands[0].addMessage({ abuseId, message: 'message 3' }) - await commands[0].addMessage({ token: userToken, abuseId, message: 'message 4' }) - }) - - it('Should have the correct messages count when listing abuses', async function () { - const results = await Promise.all([ - commands[0].getAdminList({ start: 0, count: 50 }), - commands[0].getUserList({ token: userToken, start: 0, count: 50 }) - ]) - - for (const body of results) { - const abuses = body.data - const abuse = abuses.find(a => a.id === abuseId) - expect(abuse.countMessages).to.equal(4) - } - }) - - it('Should correctly list messages of this abuse', async function () { - const results = await Promise.all([ - commands[0].listMessages({ abuseId }), - commands[0].listMessages({ token: userToken, abuseId }) - ]) - - for (const body of results) { - expect(body.total).to.equal(4) - - const abuseMessages: AbuseMessage[] = body.data - - expect(abuseMessages[0].message).to.equal('message 1') - expect(abuseMessages[0].byModerator).to.be.false - expect(abuseMessages[0].account.name).to.equal('user_43') - - abuseMessageUserId = abuseMessages[0].id - - expect(abuseMessages[1].message).to.equal('message 2') - expect(abuseMessages[1].byModerator).to.be.true - expect(abuseMessages[1].account.name).to.equal('root') - - expect(abuseMessages[2].message).to.equal('message 3') - expect(abuseMessages[2].byModerator).to.be.true - expect(abuseMessages[2].account.name).to.equal('root') - abuseMessageModerationId = abuseMessages[2].id - - expect(abuseMessages[3].message).to.equal('message 4') - expect(abuseMessages[3].byModerator).to.be.false - expect(abuseMessages[3].account.name).to.equal('user_43') - } - }) - - it('Should delete messages', async function () { - await commands[0].deleteMessage({ abuseId, messageId: abuseMessageModerationId }) - await commands[0].deleteMessage({ token: userToken, abuseId, messageId: abuseMessageUserId }) - - const results = await Promise.all([ - commands[0].listMessages({ abuseId }), - commands[0].listMessages({ token: userToken, abuseId }) - ]) - - for (const body of results) { - expect(body.total).to.equal(2) - - const abuseMessages: AbuseMessage[] = body.data - expect(abuseMessages[0].message).to.equal('message 2') - expect(abuseMessages[1].message).to.equal('message 4') - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/moderation/blocklist-notification.ts b/server/tests/api/moderation/blocklist-notification.ts deleted file mode 100644 index 9c2863a58..000000000 --- a/server/tests/api/moderation/blocklist-notification.ts +++ /dev/null @@ -1,231 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { UserNotificationType } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -async function checkNotifications (server: PeerTubeServer, token: string, expected: UserNotificationType[]) { - const { data } = await server.notifications.list({ token, start: 0, count: 10, unread: true }) - expect(data).to.have.lengthOf(expected.length) - - for (const type of expected) { - expect(data.find(n => n.type === type)).to.exist - } -} - -describe('Test blocklist notifications', function () { - let servers: PeerTubeServer[] - let videoUUID: string - - let userToken1: string - let userToken2: string - let remoteUserToken: string - - async function resetState () { - try { - await servers[1].subscriptions.remove({ token: remoteUserToken, uri: 'user1_channel@' + servers[0].host }) - await servers[1].subscriptions.remove({ token: remoteUserToken, uri: 'user2_channel@' + servers[0].host }) - } catch {} - - await waitJobs(servers) - - await servers[0].notifications.markAsReadAll({ token: userToken1 }) - await servers[0].notifications.markAsReadAll({ token: userToken2 }) - - { - const { uuid } = await servers[0].videos.upload({ token: userToken1, attributes: { name: 'video' } }) - videoUUID = uuid - - await waitJobs(servers) - } - - { - await servers[1].comments.createThread({ - token: remoteUserToken, - videoId: videoUUID, - text: '@user2@' + servers[0].host + ' hello' - }) - } - - { - - await servers[1].subscriptions.add({ token: remoteUserToken, targetUri: 'user1_channel@' + servers[0].host }) - await servers[1].subscriptions.add({ token: remoteUserToken, targetUri: 'user2_channel@' + servers[0].host }) - } - - await waitJobs(servers) - } - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - { - const user = { username: 'user1', password: 'password' } - await servers[0].users.create({ - username: user.username, - password: user.password, - videoQuota: -1, - videoQuotaDaily: -1 - }) - - userToken1 = await servers[0].login.getAccessToken(user) - await servers[0].videos.upload({ token: userToken1, attributes: { name: 'video user 1' } }) - } - - { - const user = { username: 'user2', password: 'password' } - await servers[0].users.create({ username: user.username, password: user.password }) - - userToken2 = await servers[0].login.getAccessToken(user) - } - - { - const user = { username: 'user3', password: 'password' } - await servers[1].users.create({ username: user.username, password: user.password }) - - remoteUserToken = await servers[1].login.getAccessToken(user) - } - - await doubleFollow(servers[0], servers[1]) - }) - - describe('User blocks another user', function () { - - before(async function () { - this.timeout(30000) - - await resetState() - }) - - it('Should have appropriate notifications', async function () { - const notifs = [ UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken1, notifs) - }) - - it('Should block an account', async function () { - await servers[0].blocklist.addToMyBlocklist({ token: userToken1, account: 'user3@' + servers[1].host }) - await waitJobs(servers) - }) - - it('Should not have notifications from this account', async function () { - await checkNotifications(servers[0], userToken1, []) - }) - - it('Should have notifications of this account on user 2', async function () { - const notifs = [ UserNotificationType.COMMENT_MENTION, UserNotificationType.NEW_FOLLOW ] - - await checkNotifications(servers[0], userToken2, notifs) - - await servers[0].blocklist.removeFromMyBlocklist({ token: userToken1, account: 'user3@' + servers[1].host }) - }) - }) - - describe('User blocks another server', function () { - - before(async function () { - this.timeout(30000) - - await resetState() - }) - - it('Should have appropriate notifications', async function () { - const notifs = [ UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken1, notifs) - }) - - it('Should block an account', async function () { - await servers[0].blocklist.addToMyBlocklist({ token: userToken1, server: servers[1].host }) - await waitJobs(servers) - }) - - it('Should not have notifications from this account', async function () { - await checkNotifications(servers[0], userToken1, []) - }) - - it('Should have notifications of this account on user 2', async function () { - const notifs = [ UserNotificationType.COMMENT_MENTION, UserNotificationType.NEW_FOLLOW ] - - await checkNotifications(servers[0], userToken2, notifs) - - await servers[0].blocklist.removeFromMyBlocklist({ token: userToken1, server: servers[1].host }) - }) - }) - - describe('Server blocks a user', function () { - - before(async function () { - this.timeout(30000) - - await resetState() - }) - - it('Should have appropriate notifications', async function () { - { - const notifs = [ UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken1, notifs) - } - - { - const notifs = [ UserNotificationType.COMMENT_MENTION, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken2, notifs) - } - }) - - it('Should block an account', async function () { - await servers[0].blocklist.addToServerBlocklist({ account: 'user3@' + servers[1].host }) - await waitJobs(servers) - }) - - it('Should not have notifications from this account', async function () { - await checkNotifications(servers[0], userToken1, []) - await checkNotifications(servers[0], userToken2, []) - - await servers[0].blocklist.removeFromServerBlocklist({ account: 'user3@' + servers[1].host }) - }) - }) - - describe('Server blocks a server', function () { - - before(async function () { - this.timeout(30000) - - await resetState() - }) - - it('Should have appropriate notifications', async function () { - { - const notifs = [ UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken1, notifs) - } - - { - const notifs = [ UserNotificationType.COMMENT_MENTION, UserNotificationType.NEW_FOLLOW ] - await checkNotifications(servers[0], userToken2, notifs) - } - }) - - it('Should block an account', async function () { - await servers[0].blocklist.addToServerBlocklist({ server: servers[1].host }) - await waitJobs(servers) - }) - - it('Should not have notifications from this account', async function () { - await checkNotifications(servers[0], userToken1, []) - await checkNotifications(servers[0], userToken2, []) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/moderation/blocklist.ts b/server/tests/api/moderation/blocklist.ts deleted file mode 100644 index b90d8c16c..000000000 --- a/server/tests/api/moderation/blocklist.ts +++ /dev/null @@ -1,902 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { UserNotificationType } from '@shared/models' -import { - BlocklistCommand, - cleanupTests, - CommentsCommand, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - waitJobs -} from '@shared/server-commands' - -async function checkAllVideos (server: PeerTubeServer, token: string) { - { - const { data } = await server.videos.listWithToken({ token }) - expect(data).to.have.lengthOf(5) - } - - { - const { data } = await server.videos.list() - expect(data).to.have.lengthOf(5) - } -} - -async function checkAllComments (server: PeerTubeServer, token: string, videoUUID: string) { - const { data } = await server.comments.listThreads({ videoId: videoUUID, start: 0, count: 25, sort: '-createdAt', token }) - - const threads = data.filter(t => t.isDeleted === false) - expect(threads).to.have.lengthOf(2) - - for (const thread of threads) { - const tree = await server.comments.getThread({ videoId: videoUUID, threadId: thread.id, token }) - expect(tree.children).to.have.lengthOf(1) - } -} - -async function checkCommentNotification ( - mainServer: PeerTubeServer, - comment: { server: PeerTubeServer, token: string, videoUUID: string, text: string }, - check: 'presence' | 'absence' -) { - const command = comment.server.comments - - const { threadId, createdAt } = await command.createThread({ token: comment.token, videoId: comment.videoUUID, text: comment.text }) - - await waitJobs([ mainServer, comment.server ]) - - const { data } = await mainServer.notifications.list({ start: 0, count: 30 }) - const commentNotifications = data.filter(n => n.comment && n.comment.video.uuid === comment.videoUUID && n.createdAt >= createdAt) - - if (check === 'presence') expect(commentNotifications).to.have.lengthOf(1) - else expect(commentNotifications).to.have.lengthOf(0) - - await command.delete({ token: comment.token, videoId: comment.videoUUID, commentId: threadId }) - - await waitJobs([ mainServer, comment.server ]) -} - -describe('Test blocklist', function () { - let servers: PeerTubeServer[] - let videoUUID1: string - let videoUUID2: string - let videoUUID3: string - let userToken1: string - let userModeratorToken: string - let userToken2: string - - let command: BlocklistCommand - let commentsCommand: CommentsCommand[] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - await setAccessTokensToServers(servers) - await setDefaultAccountAvatar(servers) - - command = servers[0].blocklist - commentsCommand = servers.map(s => s.comments) - - { - const user = { username: 'user1', password: 'password' } - await servers[0].users.create({ username: user.username, password: user.password }) - - userToken1 = await servers[0].login.getAccessToken(user) - await servers[0].videos.upload({ token: userToken1, attributes: { name: 'video user 1' } }) - } - - { - const user = { username: 'moderator', password: 'password' } - await servers[0].users.create({ username: user.username, password: user.password }) - - userModeratorToken = await servers[0].login.getAccessToken(user) - } - - { - const user = { username: 'user2', password: 'password' } - await servers[1].users.create({ username: user.username, password: user.password }) - - userToken2 = await servers[1].login.getAccessToken(user) - await servers[1].videos.upload({ token: userToken2, attributes: { name: 'video user 2' } }) - } - - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video server 1' } }) - videoUUID1 = uuid - } - - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video server 2' } }) - videoUUID2 = uuid - } - - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 2 server 1' } }) - videoUUID3 = uuid - } - - await doubleFollow(servers[0], servers[1]) - await doubleFollow(servers[0], servers[2]) - - { - const created = await commentsCommand[0].createThread({ videoId: videoUUID1, text: 'comment root 1' }) - const reply = await commentsCommand[0].addReply({ - token: userToken1, - videoId: videoUUID1, - toCommentId: created.id, - text: 'comment user 1' - }) - await commentsCommand[0].addReply({ videoId: videoUUID1, toCommentId: reply.id, text: 'comment root 1' }) - } - - { - const created = await commentsCommand[0].createThread({ token: userToken1, videoId: videoUUID1, text: 'comment user 1' }) - await commentsCommand[0].addReply({ videoId: videoUUID1, toCommentId: created.id, text: 'comment root 1' }) - } - - await waitJobs(servers) - }) - - describe('User blocklist', function () { - - describe('When managing account blocklist', function () { - it('Should list all videos', function () { - return checkAllVideos(servers[0], servers[0].accessToken) - }) - - it('Should list the comments', function () { - return checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - }) - - it('Should block a remote account', async function () { - await command.addToMyBlocklist({ account: 'user2@' + servers[1].host }) - }) - - it('Should hide its videos', async function () { - const { data } = await servers[0].videos.listWithToken() - - expect(data).to.have.lengthOf(4) - - const v = data.find(v => v.name === 'video user 2') - expect(v).to.be.undefined - }) - - it('Should block a local account', async function () { - await command.addToMyBlocklist({ account: 'user1' }) - }) - - it('Should hide its videos', async function () { - const { data } = await servers[0].videos.listWithToken() - - expect(data).to.have.lengthOf(3) - - const v = data.find(v => v.name === 'video user 1') - expect(v).to.be.undefined - }) - - it('Should hide its comments', async function () { - const { data } = await commentsCommand[0].listThreads({ - token: servers[0].accessToken, - videoId: videoUUID1, - start: 0, - count: 25, - sort: '-createdAt' - }) - - expect(data).to.have.lengthOf(1) - expect(data[0].totalReplies).to.equal(1) - - const t = data.find(t => t.text === 'comment user 1') - expect(t).to.be.undefined - - for (const thread of data) { - const tree = await commentsCommand[0].getThread({ - videoId: videoUUID1, - threadId: thread.id, - token: servers[0].accessToken - }) - expect(tree.children).to.have.lengthOf(0) - } - }) - - it('Should not have notifications from blocked accounts', async function () { - this.timeout(20000) - - { - const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } - await checkCommentNotification(servers[0], comment, 'absence') - } - - { - const comment = { - server: servers[0], - token: userToken1, - videoUUID: videoUUID2, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'absence') - } - }) - - it('Should list all the videos with another user', async function () { - return checkAllVideos(servers[0], userToken1) - }) - - it('Should list blocked accounts', async function () { - { - const body = await command.listMyAccountBlocklist({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('root') - expect(block.byAccount.name).to.equal('root') - expect(block.blockedAccount.displayName).to.equal('user2') - expect(block.blockedAccount.name).to.equal('user2') - expect(block.blockedAccount.host).to.equal('' + servers[1].host) - } - - { - const body = await command.listMyAccountBlocklist({ start: 1, count: 2, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('root') - expect(block.byAccount.name).to.equal('root') - expect(block.blockedAccount.displayName).to.equal('user1') - expect(block.blockedAccount.name).to.equal('user1') - expect(block.blockedAccount.host).to.equal('' + servers[0].host) - } - }) - - it('Should search blocked accounts', async function () { - const body = await command.listMyAccountBlocklist({ start: 0, count: 10, search: 'user2' }) - expect(body.total).to.equal(1) - - expect(body.data[0].blockedAccount.name).to.equal('user2') - }) - - it('Should get blocked status', async function () { - const remoteHandle = 'user2@' + servers[1].host - const localHandle = 'user1@' + servers[0].host - const unknownHandle = 'user5@' + servers[0].host - - { - const status = await command.getStatus({ accounts: [ remoteHandle ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(1) - expect(status.accounts[remoteHandle].blockedByUser).to.be.false - expect(status.accounts[remoteHandle].blockedByServer).to.be.false - - expect(Object.keys(status.hosts)).to.have.lengthOf(0) - } - - { - const status = await command.getStatus({ token: servers[0].accessToken, accounts: [ remoteHandle ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(1) - expect(status.accounts[remoteHandle].blockedByUser).to.be.true - expect(status.accounts[remoteHandle].blockedByServer).to.be.false - - expect(Object.keys(status.hosts)).to.have.lengthOf(0) - } - - { - const status = await command.getStatus({ token: servers[0].accessToken, accounts: [ localHandle, remoteHandle, unknownHandle ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(3) - - for (const handle of [ localHandle, remoteHandle ]) { - expect(status.accounts[handle].blockedByUser).to.be.true - expect(status.accounts[handle].blockedByServer).to.be.false - } - - expect(status.accounts[unknownHandle].blockedByUser).to.be.false - expect(status.accounts[unknownHandle].blockedByServer).to.be.false - - expect(Object.keys(status.hosts)).to.have.lengthOf(0) - } - }) - - it('Should not allow a remote blocked user to comment my videos', async function () { - this.timeout(60000) - - { - await commentsCommand[1].createThread({ token: userToken2, videoId: videoUUID3, text: 'comment user 2' }) - await waitJobs(servers) - - await commentsCommand[0].createThread({ token: servers[0].accessToken, videoId: videoUUID3, text: 'uploader' }) - await waitJobs(servers) - - const commentId = await commentsCommand[1].findCommentId({ videoId: videoUUID3, text: 'uploader' }) - const message = 'reply by user 2' - const reply = await commentsCommand[1].addReply({ token: userToken2, videoId: videoUUID3, toCommentId: commentId, text: message }) - await commentsCommand[1].addReply({ videoId: videoUUID3, toCommentId: reply.id, text: 'another reply' }) - - await waitJobs(servers) - } - - // Server 2 has all the comments - { - const { data } = await commentsCommand[1].listThreads({ videoId: videoUUID3, count: 25, sort: '-createdAt' }) - - expect(data).to.have.lengthOf(2) - expect(data[0].text).to.equal('uploader') - expect(data[1].text).to.equal('comment user 2') - - const tree = await commentsCommand[1].getThread({ videoId: videoUUID3, threadId: data[0].id }) - expect(tree.children).to.have.lengthOf(1) - expect(tree.children[0].comment.text).to.equal('reply by user 2') - expect(tree.children[0].children).to.have.lengthOf(1) - expect(tree.children[0].children[0].comment.text).to.equal('another reply') - } - - // Server 1 and 3 should only have uploader comments - for (const server of [ servers[0], servers[2] ]) { - const { data } = await server.comments.listThreads({ videoId: videoUUID3, count: 25, sort: '-createdAt' }) - - expect(data).to.have.lengthOf(1) - expect(data[0].text).to.equal('uploader') - - const tree = await server.comments.getThread({ videoId: videoUUID3, threadId: data[0].id }) - - if (server.serverNumber === 1) expect(tree.children).to.have.lengthOf(0) - else expect(tree.children).to.have.lengthOf(1) - } - }) - - it('Should unblock the remote account', async function () { - await command.removeFromMyBlocklist({ account: 'user2@' + servers[1].host }) - }) - - it('Should display its videos', async function () { - const { data } = await servers[0].videos.listWithToken() - expect(data).to.have.lengthOf(4) - - const v = data.find(v => v.name === 'video user 2') - expect(v).not.to.be.undefined - }) - - it('Should display its comments on my video', async function () { - for (const server of servers) { - const { data } = await server.comments.listThreads({ videoId: videoUUID3, count: 25, sort: '-createdAt' }) - - // Server 3 should not have 2 comment threads, because server 1 did not forward the server 2 comment - if (server.serverNumber === 3) { - expect(data).to.have.lengthOf(1) - continue - } - - expect(data).to.have.lengthOf(2) - expect(data[0].text).to.equal('uploader') - expect(data[1].text).to.equal('comment user 2') - - const tree = await server.comments.getThread({ videoId: videoUUID3, threadId: data[0].id }) - expect(tree.children).to.have.lengthOf(1) - expect(tree.children[0].comment.text).to.equal('reply by user 2') - expect(tree.children[0].children).to.have.lengthOf(1) - expect(tree.children[0].children[0].comment.text).to.equal('another reply') - } - }) - - it('Should unblock the local account', async function () { - await command.removeFromMyBlocklist({ account: 'user1' }) - }) - - it('Should display its comments', function () { - return checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - }) - - it('Should have a notification from a non blocked account', async function () { - this.timeout(20000) - - { - const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } - await checkCommentNotification(servers[0], comment, 'presence') - } - - { - const comment = { - server: servers[0], - token: userToken1, - videoUUID: videoUUID2, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'presence') - } - }) - }) - - describe('When managing server blocklist', function () { - - it('Should list all videos', function () { - return checkAllVideos(servers[0], servers[0].accessToken) - }) - - it('Should list the comments', function () { - return checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - }) - - it('Should block a remote server', async function () { - await command.addToMyBlocklist({ server: '' + servers[1].host }) - }) - - it('Should hide its videos', async function () { - const { data } = await servers[0].videos.listWithToken() - - expect(data).to.have.lengthOf(3) - - const v1 = data.find(v => v.name === 'video user 2') - const v2 = data.find(v => v.name === 'video server 2') - - expect(v1).to.be.undefined - expect(v2).to.be.undefined - }) - - it('Should list all the videos with another user', async function () { - return checkAllVideos(servers[0], userToken1) - }) - - it('Should hide its comments', async function () { - const { id } = await commentsCommand[1].createThread({ token: userToken2, videoId: videoUUID1, text: 'hidden comment 2' }) - - await waitJobs(servers) - - await checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - - await commentsCommand[1].delete({ token: userToken2, videoId: videoUUID1, commentId: id }) - }) - - it('Should not have notifications from blocked server', async function () { - this.timeout(20000) - - { - const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } - await checkCommentNotification(servers[0], comment, 'absence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'absence') - } - }) - - it('Should list blocked servers', async function () { - const body = await command.listMyServerBlocklist({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('root') - expect(block.byAccount.name).to.equal('root') - expect(block.blockedServer.host).to.equal('' + servers[1].host) - }) - - it('Should search blocked servers', async function () { - const body = await command.listMyServerBlocklist({ start: 0, count: 10, search: servers[1].host }) - expect(body.total).to.equal(1) - - expect(body.data[0].blockedServer.host).to.equal(servers[1].host) - }) - - it('Should get blocklist status', async function () { - const blockedServer = servers[1].host - const notBlockedServer = 'example.com' - - { - const status = await command.getStatus({ hosts: [ blockedServer, notBlockedServer ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(0) - - expect(Object.keys(status.hosts)).to.have.lengthOf(2) - expect(status.hosts[blockedServer].blockedByUser).to.be.false - expect(status.hosts[blockedServer].blockedByServer).to.be.false - - expect(status.hosts[notBlockedServer].blockedByUser).to.be.false - expect(status.hosts[notBlockedServer].blockedByServer).to.be.false - } - - { - const status = await command.getStatus({ token: servers[0].accessToken, hosts: [ blockedServer, notBlockedServer ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(0) - - expect(Object.keys(status.hosts)).to.have.lengthOf(2) - expect(status.hosts[blockedServer].blockedByUser).to.be.true - expect(status.hosts[blockedServer].blockedByServer).to.be.false - - expect(status.hosts[notBlockedServer].blockedByUser).to.be.false - expect(status.hosts[notBlockedServer].blockedByServer).to.be.false - } - }) - - it('Should unblock the remote server', async function () { - await command.removeFromMyBlocklist({ server: '' + servers[1].host }) - }) - - it('Should display its videos', function () { - return checkAllVideos(servers[0], servers[0].accessToken) - }) - - it('Should display its comments', function () { - return checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - }) - - it('Should have notification from unblocked server', async function () { - this.timeout(20000) - - { - const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } - await checkCommentNotification(servers[0], comment, 'presence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'presence') - } - }) - }) - }) - - describe('Server blocklist', function () { - - describe('When managing account blocklist', function () { - it('Should list all videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllVideos(servers[0], token) - } - }) - - it('Should list the comments', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllComments(servers[0], token, videoUUID1) - } - }) - - it('Should block a remote account', async function () { - await command.addToServerBlocklist({ account: 'user2@' + servers[1].host }) - }) - - it('Should hide its videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - const { data } = await servers[0].videos.listWithToken({ token }) - - expect(data).to.have.lengthOf(4) - - const v = data.find(v => v.name === 'video user 2') - expect(v).to.be.undefined - } - }) - - it('Should block a local account', async function () { - await command.addToServerBlocklist({ account: 'user1' }) - }) - - it('Should hide its videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - const { data } = await servers[0].videos.listWithToken({ token }) - - expect(data).to.have.lengthOf(3) - - const v = data.find(v => v.name === 'video user 1') - expect(v).to.be.undefined - } - }) - - it('Should hide its comments', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - const { data } = await commentsCommand[0].listThreads({ videoId: videoUUID1, count: 20, sort: '-createdAt', token }) - const threads = data.filter(t => t.isDeleted === false) - - expect(threads).to.have.lengthOf(1) - expect(threads[0].totalReplies).to.equal(1) - - const t = threads.find(t => t.text === 'comment user 1') - expect(t).to.be.undefined - - for (const thread of threads) { - const tree = await commentsCommand[0].getThread({ videoId: videoUUID1, threadId: thread.id, token }) - expect(tree.children).to.have.lengthOf(0) - } - } - }) - - it('Should not have notification from blocked accounts by instance', async function () { - this.timeout(20000) - - { - const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } - await checkCommentNotification(servers[0], comment, 'absence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'absence') - } - }) - - it('Should list blocked accounts', async function () { - { - const body = await command.listServerAccountBlocklist({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('peertube') - expect(block.byAccount.name).to.equal('peertube') - expect(block.blockedAccount.displayName).to.equal('user2') - expect(block.blockedAccount.name).to.equal('user2') - expect(block.blockedAccount.host).to.equal('' + servers[1].host) - } - - { - const body = await command.listServerAccountBlocklist({ start: 1, count: 2, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('peertube') - expect(block.byAccount.name).to.equal('peertube') - expect(block.blockedAccount.displayName).to.equal('user1') - expect(block.blockedAccount.name).to.equal('user1') - expect(block.blockedAccount.host).to.equal('' + servers[0].host) - } - }) - - it('Should search blocked accounts', async function () { - const body = await command.listServerAccountBlocklist({ start: 0, count: 10, search: 'user2' }) - expect(body.total).to.equal(1) - - expect(body.data[0].blockedAccount.name).to.equal('user2') - }) - - it('Should get blocked status', async function () { - const remoteHandle = 'user2@' + servers[1].host - const localHandle = 'user1@' + servers[0].host - const unknownHandle = 'user5@' + servers[0].host - - for (const token of [ undefined, servers[0].accessToken ]) { - const status = await command.getStatus({ token, accounts: [ localHandle, remoteHandle, unknownHandle ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(3) - - for (const handle of [ localHandle, remoteHandle ]) { - expect(status.accounts[handle].blockedByUser).to.be.false - expect(status.accounts[handle].blockedByServer).to.be.true - } - - expect(status.accounts[unknownHandle].blockedByUser).to.be.false - expect(status.accounts[unknownHandle].blockedByServer).to.be.false - - expect(Object.keys(status.hosts)).to.have.lengthOf(0) - } - }) - - it('Should unblock the remote account', async function () { - await command.removeFromServerBlocklist({ account: 'user2@' + servers[1].host }) - }) - - it('Should display its videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - const { data } = await servers[0].videos.listWithToken({ token }) - expect(data).to.have.lengthOf(4) - - const v = data.find(v => v.name === 'video user 2') - expect(v).not.to.be.undefined - } - }) - - it('Should unblock the local account', async function () { - await command.removeFromServerBlocklist({ account: 'user1' }) - }) - - it('Should display its comments', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllComments(servers[0], token, videoUUID1) - } - }) - - it('Should have notifications from unblocked accounts', async function () { - this.timeout(20000) - - { - const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } - await checkCommentNotification(servers[0], comment, 'presence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'presence') - } - }) - }) - - describe('When managing server blocklist', function () { - - it('Should list all videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllVideos(servers[0], token) - } - }) - - it('Should list the comments', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllComments(servers[0], token, videoUUID1) - } - }) - - it('Should block a remote server', async function () { - await command.addToServerBlocklist({ server: '' + servers[1].host }) - }) - - it('Should hide its videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - const requests = [ - servers[0].videos.list(), - servers[0].videos.listWithToken({ token }) - ] - - for (const req of requests) { - const { data } = await req - expect(data).to.have.lengthOf(3) - - const v1 = data.find(v => v.name === 'video user 2') - const v2 = data.find(v => v.name === 'video server 2') - - expect(v1).to.be.undefined - expect(v2).to.be.undefined - } - } - }) - - it('Should hide its comments', async function () { - const { id } = await commentsCommand[1].createThread({ token: userToken2, videoId: videoUUID1, text: 'hidden comment 2' }) - - await waitJobs(servers) - - await checkAllComments(servers[0], servers[0].accessToken, videoUUID1) - - await commentsCommand[1].delete({ token: userToken2, videoId: videoUUID1, commentId: id }) - }) - - it('Should not have notification from blocked instances by instance', async function () { - this.timeout(50000) - - { - const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } - await checkCommentNotification(servers[0], comment, 'absence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'absence') - } - - { - const now = new Date() - await servers[1].follows.unfollow({ target: servers[0] }) - await waitJobs(servers) - await servers[1].follows.follow({ hosts: [ servers[0].host ] }) - - await waitJobs(servers) - - const { data } = await servers[0].notifications.list({ start: 0, count: 30 }) - const commentNotifications = data.filter(n => { - return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER && n.createdAt >= now.toISOString() - }) - - expect(commentNotifications).to.have.lengthOf(0) - } - }) - - it('Should list blocked servers', async function () { - const body = await command.listServerServerBlocklist({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const block = body.data[0] - expect(block.byAccount.displayName).to.equal('peertube') - expect(block.byAccount.name).to.equal('peertube') - expect(block.blockedServer.host).to.equal('' + servers[1].host) - }) - - it('Should search blocked servers', async function () { - const body = await command.listServerServerBlocklist({ start: 0, count: 10, search: servers[1].host }) - expect(body.total).to.equal(1) - - expect(body.data[0].blockedServer.host).to.equal(servers[1].host) - }) - - it('Should get blocklist status', async function () { - const blockedServer = servers[1].host - const notBlockedServer = 'example.com' - - for (const token of [ undefined, servers[0].accessToken ]) { - const status = await command.getStatus({ token, hosts: [ blockedServer, notBlockedServer ] }) - expect(Object.keys(status.accounts)).to.have.lengthOf(0) - - expect(Object.keys(status.hosts)).to.have.lengthOf(2) - expect(status.hosts[blockedServer].blockedByUser).to.be.false - expect(status.hosts[blockedServer].blockedByServer).to.be.true - - expect(status.hosts[notBlockedServer].blockedByUser).to.be.false - expect(status.hosts[notBlockedServer].blockedByServer).to.be.false - } - }) - - it('Should unblock the remote server', async function () { - await command.removeFromServerBlocklist({ server: '' + servers[1].host }) - }) - - it('Should list all videos', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllVideos(servers[0], token) - } - }) - - it('Should list the comments', async function () { - for (const token of [ userModeratorToken, servers[0].accessToken ]) { - await checkAllComments(servers[0], token, videoUUID1) - } - }) - - it('Should have notification from unblocked instances', async function () { - this.timeout(50000) - - { - const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } - await checkCommentNotification(servers[0], comment, 'presence') - } - - { - const comment = { - server: servers[1], - token: userToken2, - videoUUID: videoUUID1, - text: 'hello @root@' + servers[0].host - } - await checkCommentNotification(servers[0], comment, 'presence') - } - - { - const now = new Date() - await servers[1].follows.unfollow({ target: servers[0] }) - await waitJobs(servers) - await servers[1].follows.follow({ hosts: [ servers[0].host ] }) - - await waitJobs(servers) - - const { data } = await servers[0].notifications.list({ start: 0, count: 30 }) - const commentNotifications = data.filter(n => { - return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER && n.createdAt >= now.toISOString() - }) - - expect(commentNotifications).to.have.lengthOf(1) - } - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/moderation/index.ts b/server/tests/api/moderation/index.ts deleted file mode 100644 index 874be03d5..000000000 --- a/server/tests/api/moderation/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './abuses' -export * from './blocklist-notification' -export * from './blocklist' -export * from './video-blacklist' diff --git a/server/tests/api/moderation/video-blacklist.ts b/server/tests/api/moderation/video-blacklist.ts deleted file mode 100644 index ef087a93b..000000000 --- a/server/tests/api/moderation/video-blacklist.ts +++ /dev/null @@ -1,414 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FIXTURE_URLS } from '@server/tests/shared' -import { sortObjectComparator } from '@shared/core-utils' -import { UserAdminFlag, UserRole, VideoBlacklist, VideoBlacklistType } from '@shared/models' -import { - BlacklistCommand, - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test video blacklist', function () { - let servers: PeerTubeServer[] = [] - let videoId: number - let command: BlacklistCommand - - async function blacklistVideosOnServer (server: PeerTubeServer) { - const { data } = await server.videos.list() - - for (const video of data) { - await server.blacklist.add({ videoId: video.id, reason: 'super reason' }) - } - } - - before(async function () { - this.timeout(120000) - - // Run servers - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - await setDefaultChannelAvatar(servers[0]) - - // Upload 2 videos on server 2 - await servers[1].videos.upload({ attributes: { name: 'My 1st video', description: 'A video on server 2' } }) - await servers[1].videos.upload({ attributes: { name: 'My 2nd video', description: 'A video on server 2' } }) - - // Wait videos propagation, server 2 has transcoding enabled - await waitJobs(servers) - - command = servers[0].blacklist - - // Blacklist the two videos on server 1 - await blacklistVideosOnServer(servers[0]) - }) - - describe('When listing/searching videos', function () { - - it('Should not have the video blacklisted in videos list/search on server 1', async function () { - { - const { total, data } = await servers[0].videos.list() - - expect(total).to.equal(0) - expect(data).to.be.an('array') - expect(data.length).to.equal(0) - } - - { - const body = await servers[0].search.searchVideos({ search: 'video' }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - }) - - it('Should have the blacklisted video in videos list/search on server 2', async function () { - { - const { total, data } = await servers[1].videos.list() - - expect(total).to.equal(2) - expect(data).to.be.an('array') - expect(data.length).to.equal(2) - } - - { - const body = await servers[1].search.searchVideos({ search: 'video' }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(2) - } - }) - }) - - describe('When listing manually blacklisted videos', function () { - it('Should display all the blacklisted videos', async function () { - const body = await command.list() - expect(body.total).to.equal(2) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(2) - - for (const blacklistedVideo of blacklistedVideos) { - expect(blacklistedVideo.reason).to.equal('super reason') - videoId = blacklistedVideo.video.id - } - }) - - it('Should display all the blacklisted videos when applying manual type filter', async function () { - const body = await command.list({ type: VideoBlacklistType.MANUAL }) - expect(body.total).to.equal(2) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(2) - }) - - it('Should display nothing when applying automatic type filter', async function () { - const body = await command.list({ type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED }) - expect(body.total).to.equal(0) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(0) - }) - - it('Should get the correct sort when sorting by descending id', async function () { - const body = await command.list({ sort: '-id' }) - expect(body.total).to.equal(2) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(2) - - const result = [ ...body.data ].sort(sortObjectComparator('id', 'desc')) - expect(blacklistedVideos).to.deep.equal(result) - }) - - it('Should get the correct sort when sorting by descending video name', async function () { - const body = await command.list({ sort: '-name' }) - expect(body.total).to.equal(2) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(2) - - const result = [ ...body.data ].sort(sortObjectComparator('name', 'desc')) - expect(blacklistedVideos).to.deep.equal(result) - }) - - it('Should get the correct sort when sorting by ascending creation date', async function () { - const body = await command.list({ sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const blacklistedVideos = body.data - expect(blacklistedVideos).to.be.an('array') - expect(blacklistedVideos.length).to.equal(2) - - const result = [ ...body.data ].sort(sortObjectComparator('createdAt', 'asc')) - expect(blacklistedVideos).to.deep.equal(result) - }) - }) - - describe('When updating blacklisted videos', function () { - it('Should change the reason', async function () { - await command.update({ videoId, reason: 'my super reason updated' }) - - const body = await command.list({ sort: '-name' }) - const video = body.data.find(b => b.video.id === videoId) - - expect(video.reason).to.equal('my super reason updated') - }) - }) - - describe('When listing my videos', function () { - it('Should display blacklisted videos', async function () { - await blacklistVideosOnServer(servers[1]) - - const { total, data } = await servers[1].videos.listMyVideos() - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const video of data) { - expect(video.blacklisted).to.be.true - expect(video.blacklistedReason).to.equal('super reason') - } - }) - }) - - describe('When removing a blacklisted video', function () { - let videoToRemove: VideoBlacklist - let blacklist = [] - - it('Should not have any video in videos list on server 1', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(0) - expect(data).to.be.an('array') - expect(data.length).to.equal(0) - }) - - it('Should remove a video from the blacklist on server 1', async function () { - // Get one video in the blacklist - const body = await command.list({ sort: '-name' }) - videoToRemove = body.data[0] - blacklist = body.data.slice(1) - - // Remove it - await command.remove({ videoId: videoToRemove.video.id }) - }) - - it('Should have the ex-blacklisted video in videos list on server 1', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(1) - - expect(data).to.be.an('array') - expect(data.length).to.equal(1) - - expect(data[0].name).to.equal(videoToRemove.video.name) - expect(data[0].id).to.equal(videoToRemove.video.id) - }) - - it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { - const body = await command.list({ sort: '-name' }) - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos.length).to.equal(1) - expect(videos).to.deep.equal(blacklist) - }) - }) - - describe('When blacklisting local videos', function () { - let video3UUID: string - let video4UUID: string - - before(async function () { - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'Video 3' } }) - video3UUID = uuid - } - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'Video 4' } }) - video4UUID = uuid - } - - await waitJobs(servers) - }) - - it('Should blacklist video 3 and keep it federated', async function () { - await command.add({ videoId: video3UUID, reason: 'super reason', unfederate: false }) - - await waitJobs(servers) - - { - const { data } = await servers[0].videos.list() - expect(data.find(v => v.uuid === video3UUID)).to.be.undefined - } - - { - const { data } = await servers[1].videos.list() - expect(data.find(v => v.uuid === video3UUID)).to.not.be.undefined - } - }) - - it('Should unfederate the video', async function () { - await command.add({ videoId: video4UUID, reason: 'super reason', unfederate: true }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - expect(data.find(v => v.uuid === video4UUID)).to.be.undefined - } - }) - - it('Should have the video unfederated even after an Update AP message', async function () { - await servers[0].videos.update({ id: video4UUID, attributes: { description: 'super description' } }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - expect(data.find(v => v.uuid === video4UUID)).to.be.undefined - } - }) - - it('Should have the correct video blacklist unfederate attribute', async function () { - const body = await command.list({ sort: 'createdAt' }) - - const blacklistedVideos = body.data - const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) - const video4Blacklisted = blacklistedVideos.find(b => b.video.uuid === video4UUID) - - expect(video3Blacklisted.unfederated).to.be.false - expect(video4Blacklisted.unfederated).to.be.true - }) - - it('Should remove the video from blacklist and refederate the video', async function () { - await command.remove({ videoId: video4UUID }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - expect(data.find(v => v.uuid === video4UUID)).to.not.be.undefined - } - }) - - }) - - describe('When auto blacklist videos', function () { - let userWithoutFlag: string - let userWithFlag: string - let channelOfUserWithoutFlag: number - - before(async function () { - this.timeout(20000) - - await killallServers([ servers[0] ]) - - const config = { - auto_blacklist: { - videos: { - of_users: { - enabled: true - } - } - } - } - await servers[0].run(config) - - { - const user = { username: 'user_without_flag', password: 'password' } - await servers[0].users.create({ - username: user.username, - adminFlags: UserAdminFlag.NONE, - password: user.password, - role: UserRole.USER - }) - - userWithoutFlag = await servers[0].login.getAccessToken(user) - - const { videoChannels } = await servers[0].users.getMyInfo({ token: userWithoutFlag }) - channelOfUserWithoutFlag = videoChannels[0].id - } - - { - const user = { username: 'user_with_flag', password: 'password' } - await servers[0].users.create({ - username: user.username, - adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST, - password: user.password, - role: UserRole.USER - }) - - userWithFlag = await servers[0].login.getAccessToken(user) - } - - await waitJobs(servers) - }) - - it('Should auto blacklist a video on upload', async function () { - await servers[0].videos.upload({ token: userWithoutFlag, attributes: { name: 'blacklisted' } }) - - const body = await command.list({ type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED }) - expect(body.total).to.equal(1) - expect(body.data[0].video.name).to.equal('blacklisted') - }) - - it('Should auto blacklist a video on URL import', async function () { - this.timeout(15000) - - const attributes = { - targetUrl: FIXTURE_URLS.goodVideo, - name: 'URL import', - channelId: channelOfUserWithoutFlag - } - await servers[0].imports.importVideo({ token: userWithoutFlag, attributes }) - - const body = await command.list({ sort: 'createdAt', type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED }) - expect(body.total).to.equal(2) - expect(body.data[1].video.name).to.equal('URL import') - }) - - it('Should auto blacklist a video on torrent import', async function () { - const attributes = { - magnetUri: FIXTURE_URLS.magnet, - name: 'Torrent import', - channelId: channelOfUserWithoutFlag - } - await servers[0].imports.importVideo({ token: userWithoutFlag, attributes }) - - const body = await command.list({ sort: 'createdAt', type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED }) - expect(body.total).to.equal(3) - expect(body.data[2].video.name).to.equal('Torrent import') - }) - - it('Should not auto blacklist a video on upload if the user has the bypass blacklist flag', async function () { - await servers[0].videos.upload({ token: userWithFlag, attributes: { name: 'not blacklisted' } }) - - const body = await command.list({ type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED }) - expect(body.total).to.equal(3) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/notifications/admin-notifications.ts b/server/tests/api/notifications/admin-notifications.ts deleted file mode 100644 index 4824542c9..000000000 --- a/server/tests/api/notifications/admin-notifications.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - CheckerBaseParams, - checkNewPeerTubeVersion, - checkNewPluginVersion, - MockJoinPeerTubeVersions, - MockSmtpServer, - prepareNotificationsTest, - SQLCommand -} from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { PluginType, UserNotification, UserNotificationType } from '@shared/models' -import { cleanupTests, PeerTubeServer } from '@shared/server-commands' - -describe('Test admin notifications', function () { - let server: PeerTubeServer - let sqlCommand: SQLCommand - let userNotifications: UserNotification[] = [] - let adminNotifications: UserNotification[] = [] - let emails: object[] = [] - let baseParams: CheckerBaseParams - let joinPeerTubeServer: MockJoinPeerTubeVersions - - before(async function () { - this.timeout(120000) - - joinPeerTubeServer = new MockJoinPeerTubeVersions() - const port = await joinPeerTubeServer.initialize() - - const config = { - peertube: { - check_latest_version: { - enabled: true, - url: `http://127.0.0.1:${port}/versions.json` - } - }, - plugins: { - index: { - enabled: true, - check_latest_versions_interval: '3 seconds' - } - } - } - - const res = await prepareNotificationsTest(1, config) - emails = res.emails - server = res.servers[0] - - userNotifications = res.userNotifications - adminNotifications = res.adminNotifications - - baseParams = { - server, - emails, - socketNotifications: adminNotifications, - token: server.accessToken - } - - await server.plugins.install({ npmName: 'peertube-plugin-hello-world' }) - await server.plugins.install({ npmName: 'peertube-theme-background-red' }) - - sqlCommand = new SQLCommand(server) - }) - - describe('Latest PeerTube version notification', function () { - - it('Should not send a notification to admins if there is no new version', async function () { - this.timeout(30000) - - joinPeerTubeServer.setLatestVersion('1.4.2') - - await wait(3000) - await checkNewPeerTubeVersion({ ...baseParams, latestVersion: '1.4.2', checkType: 'absence' }) - }) - - it('Should send a notification to admins on new version', async function () { - this.timeout(30000) - - joinPeerTubeServer.setLatestVersion('15.4.2') - - await wait(3000) - await checkNewPeerTubeVersion({ ...baseParams, latestVersion: '15.4.2', checkType: 'presence' }) - }) - - it('Should not send the same notification to admins', async function () { - this.timeout(30000) - - await wait(3000) - expect(adminNotifications.filter(n => n.type === UserNotificationType.NEW_PEERTUBE_VERSION)).to.have.lengthOf(1) - }) - - it('Should not have sent a notification to users', async function () { - this.timeout(30000) - - expect(userNotifications.filter(n => n.type === UserNotificationType.NEW_PEERTUBE_VERSION)).to.have.lengthOf(0) - }) - - it('Should send a new notification after a new release', async function () { - this.timeout(30000) - - joinPeerTubeServer.setLatestVersion('15.4.3') - - await wait(3000) - await checkNewPeerTubeVersion({ ...baseParams, latestVersion: '15.4.3', checkType: 'presence' }) - expect(adminNotifications.filter(n => n.type === UserNotificationType.NEW_PEERTUBE_VERSION)).to.have.lengthOf(2) - }) - }) - - describe('Latest plugin version notification', function () { - - it('Should not send a notification to admins if there is no new plugin version', async function () { - this.timeout(30000) - - await wait(6000) - await checkNewPluginVersion({ ...baseParams, pluginType: PluginType.PLUGIN, pluginName: 'hello-world', checkType: 'absence' }) - }) - - it('Should send a notification to admins on new plugin version', async function () { - this.timeout(30000) - - await sqlCommand.setPluginVersion('hello-world', '0.0.1') - await sqlCommand.setPluginLatestVersion('hello-world', '0.0.1') - await wait(6000) - - await checkNewPluginVersion({ ...baseParams, pluginType: PluginType.PLUGIN, pluginName: 'hello-world', checkType: 'presence' }) - }) - - it('Should not send the same notification to admins', async function () { - this.timeout(30000) - - await wait(6000) - - expect(adminNotifications.filter(n => n.type === UserNotificationType.NEW_PLUGIN_VERSION)).to.have.lengthOf(1) - }) - - it('Should not have sent a notification to users', async function () { - expect(userNotifications.filter(n => n.type === UserNotificationType.NEW_PLUGIN_VERSION)).to.have.lengthOf(0) - }) - - it('Should send a new notification after a new plugin release', async function () { - this.timeout(30000) - - await sqlCommand.setPluginVersion('hello-world', '0.0.1') - await sqlCommand.setPluginLatestVersion('hello-world', '0.0.1') - await wait(6000) - - expect(adminNotifications.filter(n => n.type === UserNotificationType.NEW_PEERTUBE_VERSION)).to.have.lengthOf(2) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await sqlCommand.cleanup() - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/notifications/comments-notifications.ts b/server/tests/api/notifications/comments-notifications.ts deleted file mode 100644 index 0a4bfc5e4..000000000 --- a/server/tests/api/notifications/comments-notifications.ts +++ /dev/null @@ -1,305 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - checkCommentMention, - CheckerBaseParams, - checkNewCommentOnMyVideo, - MockSmtpServer, - prepareNotificationsTest -} from '@server/tests/shared' -import { UserNotification } from '@shared/models' -import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' - -describe('Test comments notifications', function () { - let servers: PeerTubeServer[] = [] - let userToken: string - let userNotifications: UserNotification[] = [] - let emails: object[] = [] - - const commentText = '**hello** world,

what do you think about peertube?

' - const expectedHtml = 'hello world' + - ',

what do you think about peertube?' - - before(async function () { - this.timeout(120000) - - const res = await prepareNotificationsTest(2) - emails = res.emails - userToken = res.userAccessToken - servers = res.servers - userNotifications = res.userNotifications - }) - - describe('Comment on my video notifications', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken - } - }) - - it('Should not send a new comment notification after a comment on another video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - const created = await servers[0].comments.createThread({ videoId: uuid, text: 'comment' }) - const commentId = created.id - - await waitJobs(servers) - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId: commentId, commentId, checkType: 'absence' }) - }) - - it('Should not send a new comment notification if I comment my own video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - const created = await servers[0].comments.createThread({ token: userToken, videoId: uuid, text: 'comment' }) - const commentId = created.id - - await waitJobs(servers) - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId: commentId, commentId, checkType: 'absence' }) - }) - - it('Should not send a new comment notification if the account is muted', async function () { - this.timeout(30000) - - await servers[0].blocklist.addToMyBlocklist({ token: userToken, account: 'root' }) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - const created = await servers[0].comments.createThread({ videoId: uuid, text: 'comment' }) - const commentId = created.id - - await waitJobs(servers) - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId: commentId, commentId, checkType: 'absence' }) - - await servers[0].blocklist.removeFromMyBlocklist({ token: userToken, account: 'root' }) - }) - - it('Should send a new comment notification after a local comment on my video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - const created = await servers[0].comments.createThread({ videoId: uuid, text: 'comment' }) - const commentId = created.id - - await waitJobs(servers) - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId: commentId, commentId, checkType: 'presence' }) - }) - - it('Should send a new comment notification after a remote comment on my video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - await waitJobs(servers) - - await servers[1].comments.createThread({ videoId: uuid, text: 'comment' }) - - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: uuid }) - expect(data).to.have.lengthOf(1) - - const commentId = data[0].id - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId: commentId, commentId, checkType: 'presence' }) - }) - - it('Should send a new comment notification after a local reply on my video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - const { id: threadId } = await servers[0].comments.createThread({ videoId: uuid, text: 'comment' }) - - const { id: commentId } = await servers[0].comments.addReply({ videoId: uuid, toCommentId: threadId, text: 'reply' }) - - await waitJobs(servers) - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId, commentId, checkType: 'presence' }) - }) - - it('Should send a new comment notification after a remote reply on my video', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - await waitJobs(servers) - - { - const created = await servers[1].comments.createThread({ videoId: uuid, text: 'comment' }) - const threadId = created.id - await servers[1].comments.addReply({ videoId: uuid, toCommentId: threadId, text: 'reply' }) - } - - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: uuid }) - expect(data).to.have.lengthOf(1) - - const threadId = data[0].id - const tree = await servers[0].comments.getThread({ videoId: uuid, threadId }) - - expect(tree.children).to.have.lengthOf(1) - const commentId = tree.children[0].comment.id - - await checkNewCommentOnMyVideo({ ...baseParams, shortUUID, threadId, commentId, checkType: 'presence' }) - }) - - it('Should convert markdown in comment to html', async function () { - this.timeout(30000) - - const { uuid } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'cool video' } }) - - await servers[0].comments.createThread({ videoId: uuid, text: commentText }) - - await waitJobs(servers) - - const latestEmail = emails[emails.length - 1] - expect(latestEmail['html']).to.contain(expectedHtml) - }) - }) - - describe('Mention notifications', function () { - let baseParams: CheckerBaseParams - const byAccountDisplayName = 'super root name' - - before(async function () { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken - } - - await servers[0].users.updateMe({ displayName: 'super root name' }) - await servers[1].users.updateMe({ displayName: 'super root 2 name' }) - }) - - it('Should not send a new mention comment notification if I mention the video owner', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken, attributes: { name: 'super video' } }) - - const { id: commentId } = await servers[0].comments.createThread({ videoId: uuid, text: '@user_1 hello' }) - - await waitJobs(servers) - await checkCommentMention({ ...baseParams, shortUUID, threadId: commentId, commentId, byAccountDisplayName, checkType: 'absence' }) - }) - - it('Should not send a new mention comment notification if I mention myself', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - const { id: commentId } = await servers[0].comments.createThread({ token: userToken, videoId: uuid, text: '@user_1 hello' }) - - await waitJobs(servers) - await checkCommentMention({ ...baseParams, shortUUID, threadId: commentId, commentId, byAccountDisplayName, checkType: 'absence' }) - }) - - it('Should not send a new mention notification if the account is muted', async function () { - this.timeout(30000) - - await servers[0].blocklist.addToMyBlocklist({ token: userToken, account: 'root' }) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - const { id: commentId } = await servers[0].comments.createThread({ videoId: uuid, text: '@user_1 hello' }) - - await waitJobs(servers) - await checkCommentMention({ ...baseParams, shortUUID, threadId: commentId, commentId, byAccountDisplayName, checkType: 'absence' }) - - await servers[0].blocklist.removeFromMyBlocklist({ token: userToken, account: 'root' }) - }) - - it('Should not send a new mention notification if the remote account mention a local account', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - await waitJobs(servers) - const { id: threadId } = await servers[1].comments.createThread({ videoId: uuid, text: '@user_1 hello' }) - - await waitJobs(servers) - - const byAccountDisplayName = 'super root 2 name' - await checkCommentMention({ ...baseParams, shortUUID, threadId, commentId: threadId, byAccountDisplayName, checkType: 'absence' }) - }) - - it('Should send a new mention notification after local comments', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - const { id: threadId } = await servers[0].comments.createThread({ videoId: uuid, text: '@user_1 hellotext: 1' }) - - await waitJobs(servers) - await checkCommentMention({ ...baseParams, shortUUID, threadId, commentId: threadId, byAccountDisplayName, checkType: 'presence' }) - - const { id: commentId } = await servers[0].comments.addReply({ videoId: uuid, toCommentId: threadId, text: 'hello 2 @user_1' }) - - await waitJobs(servers) - await checkCommentMention({ ...baseParams, shortUUID, commentId, threadId, byAccountDisplayName, checkType: 'presence' }) - }) - - it('Should send a new mention notification after remote comments', async function () { - this.timeout(30000) - - const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - await waitJobs(servers) - - const text1 = `hello @user_1@${servers[0].host} 1` - const { id: server2ThreadId } = await servers[1].comments.createThread({ videoId: uuid, text: text1 }) - - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: uuid }) - expect(data).to.have.lengthOf(1) - - const byAccountDisplayName = 'super root 2 name' - const threadId = data[0].id - await checkCommentMention({ ...baseParams, shortUUID, commentId: threadId, threadId, byAccountDisplayName, checkType: 'presence' }) - - const text2 = `@user_1@${servers[0].host} hello 2 @root@${servers[0].host}` - await servers[1].comments.addReply({ videoId: uuid, toCommentId: server2ThreadId, text: text2 }) - - await waitJobs(servers) - - const tree = await servers[0].comments.getThread({ videoId: uuid, threadId }) - - expect(tree.children).to.have.lengthOf(1) - const commentId = tree.children[0].comment.id - - await checkCommentMention({ ...baseParams, shortUUID, commentId, threadId, byAccountDisplayName, checkType: 'presence' }) - }) - - it('Should convert markdown in comment to html', async function () { - this.timeout(30000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'super video' } }) - - const { id: threadId } = await servers[0].comments.createThread({ videoId: uuid, text: '@user_1 hello 1' }) - - await servers[0].comments.addReply({ videoId: uuid, toCommentId: threadId, text: '@user_1 ' + commentText }) - - await waitJobs(servers) - - const latestEmail = emails[emails.length - 1] - expect(latestEmail['html']).to.contain(expectedHtml) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/notifications/index.ts b/server/tests/api/notifications/index.ts deleted file mode 100644 index c0216b74f..000000000 --- a/server/tests/api/notifications/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import './admin-notifications' -import './comments-notifications' -import './moderation-notifications' -import './notifications-api' -import './registrations-notifications' -import './user-notifications' diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts deleted file mode 100644 index e7a5c47e9..000000000 --- a/server/tests/api/notifications/moderation-notifications.ts +++ /dev/null @@ -1,609 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { - checkAbuseStateChange, - checkAutoInstanceFollowing, - CheckerBaseParams, - checkNewAbuseMessage, - checkNewAccountAbuseForModerators, - checkNewBlacklistOnMyVideo, - checkNewCommentAbuseForModerators, - checkNewInstanceFollower, - checkNewVideoAbuseForModerators, - checkNewVideoFromSubscription, - checkVideoAutoBlacklistForModerators, - checkVideoIsPublished, - MockInstancesIndex, - MockSmtpServer, - prepareNotificationsTest -} from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { buildUUID } from '@shared/extra-utils' -import { AbuseState, CustomConfig, UserNotification, UserRole, VideoPrivacy } from '@shared/models' -import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' - -describe('Test moderation notifications', function () { - let servers: PeerTubeServer[] = [] - let userToken1: string - let userToken2: string - - let userNotifications: UserNotification[] = [] - let adminNotifications: UserNotification[] = [] - let adminNotificationsServer2: UserNotification[] = [] - let emails: object[] = [] - - before(async function () { - this.timeout(120000) - - const res = await prepareNotificationsTest(3) - emails = res.emails - userToken1 = res.userAccessToken - servers = res.servers - userNotifications = res.userNotifications - adminNotifications = res.adminNotifications - adminNotificationsServer2 = res.adminNotificationsServer2 - - userToken2 = await servers[1].users.generateUserAndToken('user2', UserRole.USER) - }) - - describe('Abuse for moderators notification', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[0], - emails, - socketNotifications: adminNotifications, - token: servers[0].accessToken - } - }) - - it('Should not send a notification to moderators on local abuse reported by an admin', async function () { - this.timeout(50000) - - const name = 'video for abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await servers[0].abuses.report({ videoId: video.id, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'absence' }) - }) - - it('Should send a notification to moderators on local video abuse', async function () { - this.timeout(50000) - - const name = 'video for abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) - }) - - it('Should send a notification to moderators on remote video abuse', async function () { - this.timeout(50000) - - const name = 'video for abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await waitJobs(servers) - - const videoId = await servers[1].videos.getId({ uuid: video.uuid }) - await servers[1].abuses.report({ token: userToken2, videoId, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) - }) - - it('Should send a notification to moderators on local comment abuse', async function () { - this.timeout(50000) - - const name = 'video for abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - const comment = await servers[0].comments.createThread({ - token: userToken1, - videoId: video.id, - text: 'comment abuse ' + buildUUID() - }) - - await waitJobs(servers) - - await servers[0].abuses.report({ token: userToken1, commentId: comment.id, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) - }) - - it('Should send a notification to moderators on remote comment abuse', async function () { - this.timeout(50000) - - const name = 'video for abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await servers[0].comments.createThread({ - token: userToken1, - videoId: video.id, - text: 'comment abuse ' + buildUUID() - }) - - await waitJobs(servers) - - const { data } = await servers[1].comments.listThreads({ videoId: video.uuid }) - const commentId = data[0].id - await servers[1].abuses.report({ token: userToken2, commentId, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) - }) - - it('Should send a notification to moderators on local account abuse', async function () { - this.timeout(50000) - - const username = 'user' + new Date().getTime() - const { account } = await servers[0].users.create({ username, password: 'donald' }) - const accountId = account.id - - await servers[0].abuses.report({ token: userToken1, accountId, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) - }) - - it('Should send a notification to moderators on remote account abuse', async function () { - this.timeout(50000) - - const username = 'user' + new Date().getTime() - const tmpToken = await servers[0].users.generateUserAndToken(username) - await servers[0].videos.upload({ token: tmpToken, attributes: { name: 'super video' } }) - - await waitJobs(servers) - - const account = await servers[1].accounts.get({ accountName: username + '@' + servers[0].host }) - await servers[1].abuses.report({ token: userToken2, accountId: account.id, reason: 'super reason' }) - - await waitJobs(servers) - await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) - }) - }) - - describe('Abuse state change notification', function () { - let baseParams: CheckerBaseParams - let abuseId: number - - before(async function () { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken1 - } - - const name = 'abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) - abuseId = body.abuse.id - }) - - it('Should send a notification to reporter if the abuse has been accepted', async function () { - this.timeout(30000) - - await servers[0].abuses.update({ abuseId, body: { state: AbuseState.ACCEPTED } }) - await waitJobs(servers) - - await checkAbuseStateChange({ ...baseParams, abuseId, state: AbuseState.ACCEPTED, checkType: 'presence' }) - }) - - it('Should send a notification to reporter if the abuse has been rejected', async function () { - this.timeout(30000) - - await servers[0].abuses.update({ abuseId, body: { state: AbuseState.REJECTED } }) - await waitJobs(servers) - - await checkAbuseStateChange({ ...baseParams, abuseId, state: AbuseState.REJECTED, checkType: 'presence' }) - }) - }) - - describe('New abuse message notification', function () { - let baseParamsUser: CheckerBaseParams - let baseParamsAdmin: CheckerBaseParams - let abuseId: number - let abuseId2: number - - before(async function () { - baseParamsUser = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken1 - } - - baseParamsAdmin = { - server: servers[0], - emails, - socketNotifications: adminNotifications, - token: servers[0].accessToken - } - - const name = 'abuse ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - { - const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) - abuseId = body.abuse.id - } - - { - const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason 2' }) - abuseId2 = body.abuse.id - } - }) - - it('Should send a notification to reporter on new message', async function () { - this.timeout(30000) - - const message = 'my super message to users' - await servers[0].abuses.addMessage({ abuseId, message }) - await waitJobs(servers) - - await checkNewAbuseMessage({ ...baseParamsUser, abuseId, message, toEmail: 'user_1@example.com', checkType: 'presence' }) - }) - - it('Should not send a notification to the admin if sent by the admin', async function () { - this.timeout(30000) - - const message = 'my super message that should not be sent to the admin' - await servers[0].abuses.addMessage({ abuseId, message }) - await waitJobs(servers) - - const toEmail = 'admin' + servers[0].internalServerNumber + '@example.com' - await checkNewAbuseMessage({ ...baseParamsAdmin, abuseId, message, toEmail, checkType: 'absence' }) - }) - - it('Should send a notification to moderators', async function () { - this.timeout(30000) - - const message = 'my super message to moderators' - await servers[0].abuses.addMessage({ token: userToken1, abuseId: abuseId2, message }) - await waitJobs(servers) - - const toEmail = 'admin' + servers[0].internalServerNumber + '@example.com' - await checkNewAbuseMessage({ ...baseParamsAdmin, abuseId: abuseId2, message, toEmail, checkType: 'presence' }) - }) - - it('Should not send a notification to reporter if sent by the reporter', async function () { - this.timeout(30000) - - const message = 'my super message that should not be sent to reporter' - await servers[0].abuses.addMessage({ token: userToken1, abuseId: abuseId2, message }) - await waitJobs(servers) - - const toEmail = 'user_1@example.com' - await checkNewAbuseMessage({ ...baseParamsUser, abuseId: abuseId2, message, toEmail, checkType: 'absence' }) - }) - }) - - describe('Video blacklist on my video', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken1 - } - }) - - it('Should send a notification to video owner on blacklist', async function () { - this.timeout(30000) - - const name = 'video for abuse ' + buildUUID() - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await servers[0].blacklist.add({ videoId: uuid }) - - await waitJobs(servers) - await checkNewBlacklistOnMyVideo({ ...baseParams, shortUUID, videoName: name, blacklistType: 'blacklist' }) - }) - - it('Should send a notification to video owner on unblacklist', async function () { - this.timeout(30000) - - const name = 'video for abuse ' + buildUUID() - const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) - - await servers[0].blacklist.add({ videoId: uuid }) - - await waitJobs(servers) - await servers[0].blacklist.remove({ videoId: uuid }) - await waitJobs(servers) - - await wait(500) - await checkNewBlacklistOnMyVideo({ ...baseParams, shortUUID, videoName: name, blacklistType: 'unblacklist' }) - }) - }) - - describe('New instance follows', function () { - const instanceIndexServer = new MockInstancesIndex() - let config: any - let baseParams: CheckerBaseParams - - before(async function () { - baseParams = { - server: servers[0], - emails, - socketNotifications: adminNotifications, - token: servers[0].accessToken - } - - const port = await instanceIndexServer.initialize() - instanceIndexServer.addInstance(servers[1].host) - - config = { - followings: { - instance: { - autoFollowIndex: { - indexUrl: `http://127.0.0.1:${port}/api/v1/instances/hosts`, - enabled: true - } - } - } - } - }) - - it('Should send a notification only to admin when there is a new instance follower', async function () { - this.timeout(60000) - - await servers[2].follows.follow({ hosts: [ servers[0].url ] }) - - await waitJobs(servers) - - await checkNewInstanceFollower({ ...baseParams, followerHost: servers[2].host, checkType: 'presence' }) - - const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } - await checkNewInstanceFollower({ ...baseParams, ...userOverride, followerHost: servers[2].host, checkType: 'absence' }) - }) - - it('Should send a notification on auto follow back', async function () { - this.timeout(40000) - - await servers[2].follows.unfollow({ target: servers[0] }) - await waitJobs(servers) - - const config = { - followings: { - instance: { - autoFollowBack: { enabled: true } - } - } - } - await servers[0].config.updateCustomSubConfig({ newConfig: config }) - - await servers[2].follows.follow({ hosts: [ servers[0].url ] }) - - await waitJobs(servers) - - const followerHost = servers[0].host - const followingHost = servers[2].host - await checkAutoInstanceFollowing({ ...baseParams, followerHost, followingHost, checkType: 'presence' }) - - const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } - await checkAutoInstanceFollowing({ ...baseParams, ...userOverride, followerHost, followingHost, checkType: 'absence' }) - - config.followings.instance.autoFollowBack.enabled = false - await servers[0].config.updateCustomSubConfig({ newConfig: config }) - await servers[0].follows.unfollow({ target: servers[2] }) - await servers[2].follows.unfollow({ target: servers[0] }) - }) - - it('Should send a notification on auto instances index follow', async function () { - this.timeout(30000) - await servers[0].follows.unfollow({ target: servers[1] }) - - await servers[0].config.updateCustomSubConfig({ newConfig: config }) - - await wait(5000) - await waitJobs(servers) - - const followerHost = servers[0].host - const followingHost = servers[1].host - await checkAutoInstanceFollowing({ ...baseParams, followerHost, followingHost, checkType: 'presence' }) - - config.followings.instance.autoFollowIndex.enabled = false - await servers[0].config.updateCustomSubConfig({ newConfig: config }) - await servers[0].follows.unfollow({ target: servers[1] }) - }) - }) - - describe('Video-related notifications when video auto-blacklist is enabled', function () { - let userBaseParams: CheckerBaseParams - let adminBaseParamsServer1: CheckerBaseParams - let adminBaseParamsServer2: CheckerBaseParams - let uuid: string - let shortUUID: string - let videoName: string - let currentCustomConfig: CustomConfig - - before(async function () { - - adminBaseParamsServer1 = { - server: servers[0], - emails, - socketNotifications: adminNotifications, - token: servers[0].accessToken - } - - adminBaseParamsServer2 = { - server: servers[1], - emails, - socketNotifications: adminNotificationsServer2, - token: servers[1].accessToken - } - - userBaseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userToken1 - } - - currentCustomConfig = await servers[0].config.getCustomConfig() - - const autoBlacklistTestsCustomConfig = { - ...currentCustomConfig, - - autoBlacklist: { - videos: { - ofUsers: { - enabled: true - } - } - } - } - - // enable transcoding otherwise own publish notification after transcoding not expected - autoBlacklistTestsCustomConfig.transcoding.enabled = true - await servers[0].config.updateCustomConfig({ newCustomConfig: autoBlacklistTestsCustomConfig }) - - await servers[0].subscriptions.add({ targetUri: 'user_1_channel@' + servers[0].host }) - await servers[1].subscriptions.add({ targetUri: 'user_1_channel@' + servers[0].host }) - }) - - it('Should send notification to moderators on new video with auto-blacklist', async function () { - this.timeout(120000) - - videoName = 'video with auto-blacklist ' + buildUUID() - const video = await servers[0].videos.upload({ token: userToken1, attributes: { name: videoName } }) - shortUUID = video.shortUUID - uuid = video.uuid - - await waitJobs(servers) - await checkVideoAutoBlacklistForModerators({ ...adminBaseParamsServer1, shortUUID, videoName, checkType: 'presence' }) - }) - - it('Should not send video publish notification if auto-blacklisted', async function () { - this.timeout(120000) - - await checkVideoIsPublished({ ...userBaseParams, videoName, shortUUID, checkType: 'absence' }) - }) - - it('Should not send a local user subscription notification if auto-blacklisted', async function () { - this.timeout(120000) - - await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'absence' }) - }) - - it('Should not send a remote user subscription notification if auto-blacklisted', async function () { - await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName, shortUUID, checkType: 'absence' }) - }) - - it('Should send video published and unblacklist after video unblacklisted', async function () { - this.timeout(120000) - - await servers[0].blacklist.remove({ videoId: uuid }) - - await waitJobs(servers) - - // FIXME: Can't test as two notifications sent to same user and util only checks last one - // One notification might be better anyways - // await checkNewBlacklistOnMyVideo(userBaseParams, videoUUID, videoName, 'unblacklist') - // await checkVideoIsPublished(userBaseParams, videoName, videoUUID, 'presence') - }) - - it('Should send a local user subscription notification after removed from blacklist', async function () { - this.timeout(120000) - - await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'presence' }) - }) - - it('Should send a remote user subscription notification after removed from blacklist', async function () { - this.timeout(120000) - - await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName, shortUUID, checkType: 'presence' }) - }) - - it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { - this.timeout(120000) - - const updateAt = new Date(new Date().getTime() + 1000000) - - const name = 'video with auto-blacklist and future schedule ' + buildUUID() - - const attributes = { - name, - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - - const { shortUUID, uuid } = await servers[0].videos.upload({ token: userToken1, attributes }) - - await servers[0].blacklist.remove({ videoId: uuid }) - - await waitJobs(servers) - await checkNewBlacklistOnMyVideo({ ...userBaseParams, shortUUID, videoName: name, blacklistType: 'unblacklist' }) - - // FIXME: Can't test absence as two notifications sent to same user and util only checks last one - // One notification might be better anyways - // await checkVideoIsPublished(userBaseParams, name, uuid, 'absence') - - await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName: name, shortUUID, checkType: 'absence' }) - await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should not send publish/subscription notifications after scheduled update if video still auto-blacklisted', async function () { - this.timeout(120000) - - // In 2 seconds - const updateAt = new Date(new Date().getTime() + 2000) - - const name = 'video with schedule done and still auto-blacklisted ' + buildUUID() - - const attributes = { - name, - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - - const { shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes }) - - await wait(6000) - await checkVideoIsPublished({ ...userBaseParams, videoName: name, shortUUID, checkType: 'absence' }) - await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName: name, shortUUID, checkType: 'absence' }) - await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should not send a notification to moderators on new video without auto-blacklist', async function () { - this.timeout(120000) - - const name = 'video without auto-blacklist ' + buildUUID() - - // admin with blacklist right will not be auto-blacklisted - const { shortUUID } = await servers[0].videos.upload({ attributes: { name } }) - - await waitJobs(servers) - await checkVideoAutoBlacklistForModerators({ ...adminBaseParamsServer1, shortUUID, videoName: name, checkType: 'absence' }) - }) - - after(async () => { - await servers[0].config.updateCustomConfig({ newCustomConfig: currentCustomConfig }) - - await servers[0].subscriptions.remove({ uri: 'user_1_channel@' + servers[0].host }) - await servers[1].subscriptions.remove({ uri: 'user_1_channel@' + servers[0].host }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/notifications/notifications-api.ts b/server/tests/api/notifications/notifications-api.ts deleted file mode 100644 index 1fc861160..000000000 --- a/server/tests/api/notifications/notifications-api.ts +++ /dev/null @@ -1,206 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - CheckerBaseParams, - checkNewVideoFromSubscription, - getAllNotificationsSettings, - MockSmtpServer, - prepareNotificationsTest -} from '@server/tests/shared' -import { UserNotification, UserNotificationSettingValue } from '@shared/models' -import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' - -describe('Test notifications API', function () { - let server: PeerTubeServer - let userNotifications: UserNotification[] = [] - let userToken: string - let emails: object[] = [] - - before(async function () { - this.timeout(120000) - - const res = await prepareNotificationsTest(1) - emails = res.emails - userToken = res.userAccessToken - userNotifications = res.userNotifications - server = res.servers[0] - - await server.subscriptions.add({ token: userToken, targetUri: 'root_channel@' + server.host }) - - for (let i = 0; i < 10; i++) { - await server.videos.randomUpload({ wait: false }) - } - - await waitJobs([ server ]) - }) - - describe('Notification list & count', function () { - - it('Should correctly list notifications', async function () { - const { data, total } = await server.notifications.list({ token: userToken, start: 0, count: 2 }) - - expect(data).to.have.lengthOf(2) - expect(total).to.equal(10) - }) - }) - - describe('Mark as read', function () { - - it('Should mark as read some notifications', async function () { - const { data } = await server.notifications.list({ token: userToken, start: 2, count: 3 }) - const ids = data.map(n => n.id) - - await server.notifications.markAsRead({ token: userToken, ids }) - }) - - it('Should have the notifications marked as read', async function () { - const { data } = await server.notifications.list({ token: userToken, start: 0, count: 10 }) - - expect(data[0].read).to.be.false - expect(data[1].read).to.be.false - expect(data[2].read).to.be.true - expect(data[3].read).to.be.true - expect(data[4].read).to.be.true - expect(data[5].read).to.be.false - }) - - it('Should only list read notifications', async function () { - const { data } = await server.notifications.list({ token: userToken, start: 0, count: 10, unread: false }) - - for (const notification of data) { - expect(notification.read).to.be.true - } - }) - - it('Should only list unread notifications', async function () { - const { data } = await server.notifications.list({ token: userToken, start: 0, count: 10, unread: true }) - - for (const notification of data) { - expect(notification.read).to.be.false - } - }) - - it('Should mark as read all notifications', async function () { - await server.notifications.markAsReadAll({ token: userToken }) - - const body = await server.notifications.list({ token: userToken, start: 0, count: 10, unread: true }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - }) - - describe('Notification settings', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server, - emails, - socketNotifications: userNotifications, - token: userToken - } - }) - - it('Should not have notifications', async function () { - this.timeout(20000) - - await server.notifications.updateMySettings({ - token: userToken, - settings: { ...getAllNotificationsSettings(), newVideoFromSubscription: UserNotificationSettingValue.NONE } - }) - - { - const info = await server.users.getMyInfo({ token: userToken }) - expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.NONE) - } - - const { name, shortUUID } = await server.videos.randomUpload() - - const check = { web: true, mail: true } - await checkNewVideoFromSubscription({ ...baseParams, check, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should only have web notifications', async function () { - this.timeout(20000) - - await server.notifications.updateMySettings({ - token: userToken, - settings: { ...getAllNotificationsSettings(), newVideoFromSubscription: UserNotificationSettingValue.WEB } - }) - - { - const info = await server.users.getMyInfo({ token: userToken }) - expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.WEB) - } - - const { name, shortUUID } = await server.videos.randomUpload() - - { - const check = { mail: true, web: false } - await checkNewVideoFromSubscription({ ...baseParams, check, videoName: name, shortUUID, checkType: 'absence' }) - } - - { - const check = { mail: false, web: true } - await checkNewVideoFromSubscription({ ...baseParams, check, videoName: name, shortUUID, checkType: 'presence' }) - } - }) - - it('Should only have mail notifications', async function () { - this.timeout(20000) - - await server.notifications.updateMySettings({ - token: userToken, - settings: { ...getAllNotificationsSettings(), newVideoFromSubscription: UserNotificationSettingValue.EMAIL } - }) - - { - const info = await server.users.getMyInfo({ token: userToken }) - expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.EMAIL) - } - - const { name, shortUUID } = await server.videos.randomUpload() - - { - const check = { mail: false, web: true } - await checkNewVideoFromSubscription({ ...baseParams, check, videoName: name, shortUUID, checkType: 'absence' }) - } - - { - const check = { mail: true, web: false } - await checkNewVideoFromSubscription({ ...baseParams, check, videoName: name, shortUUID, checkType: 'presence' }) - } - }) - - it('Should have email and web notifications', async function () { - this.timeout(20000) - - await server.notifications.updateMySettings({ - token: userToken, - settings: { - ...getAllNotificationsSettings(), - newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL - } - }) - - { - const info = await server.users.getMyInfo({ token: userToken }) - expect(info.notificationSettings.newVideoFromSubscription).to.equal( - UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL - ) - } - - const { name, shortUUID } = await server.videos.randomUpload() - - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/notifications/registrations-notifications.ts b/server/tests/api/notifications/registrations-notifications.ts deleted file mode 100644 index d20fc8df3..000000000 --- a/server/tests/api/notifications/registrations-notifications.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { - CheckerBaseParams, - checkRegistrationRequest, - checkUserRegistered, - MockSmtpServer, - prepareNotificationsTest -} from '@server/tests/shared' -import { UserNotification } from '@shared/models' -import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' - -describe('Test registrations notifications', function () { - let server: PeerTubeServer - let userToken1: string - - let userNotifications: UserNotification[] = [] - let adminNotifications: UserNotification[] = [] - let emails: object[] = [] - - let baseParams: CheckerBaseParams - - before(async function () { - this.timeout(120000) - - const res = await prepareNotificationsTest(1) - - server = res.servers[0] - emails = res.emails - userToken1 = res.userAccessToken - adminNotifications = res.adminNotifications - userNotifications = res.userNotifications - - baseParams = { - server, - emails, - socketNotifications: adminNotifications, - token: server.accessToken - } - }) - - describe('New direct registration for moderators', function () { - - before(async function () { - await server.config.enableSignup(false) - }) - - it('Should send a notification only to moderators when a user registers on the instance', async function () { - this.timeout(50000) - - await server.registrations.register({ username: 'user_10' }) - - await waitJobs([ server ]) - - await checkUserRegistered({ ...baseParams, username: 'user_10', checkType: 'presence' }) - - const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } - await checkUserRegistered({ ...baseParams, ...userOverride, username: 'user_10', checkType: 'absence' }) - }) - }) - - describe('New registration request for moderators', function () { - - before(async function () { - await server.config.enableSignup(true) - }) - - it('Should send a notification on new registration request', async function () { - this.timeout(50000) - - const registrationReason = 'my reason' - await server.registrations.requestRegistration({ username: 'user_11', registrationReason }) - - await waitJobs([ server ]) - - await checkRegistrationRequest({ ...baseParams, username: 'user_11', registrationReason, checkType: 'presence' }) - - const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } - await checkRegistrationRequest({ ...baseParams, ...userOverride, username: 'user_11', registrationReason, checkType: 'absence' }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts deleted file mode 100644 index 55da10265..000000000 --- a/server/tests/api/notifications/user-notifications.ts +++ /dev/null @@ -1,574 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - CheckerBaseParams, - checkMyVideoImportIsFinished, - checkNewActorFollow, - checkNewVideoFromSubscription, - checkVideoIsPublished, - checkVideoStudioEditionIsFinished, - FIXTURE_URLS, - MockSmtpServer, - prepareNotificationsTest, - uploadRandomVideoOnServers -} from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { buildUUID } from '@shared/extra-utils' -import { UserNotification, UserNotificationType, VideoPrivacy, VideoStudioTask } from '@shared/models' -import { cleanupTests, findExternalSavedVideo, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands' - -describe('Test user notifications', function () { - let servers: PeerTubeServer[] = [] - let userAccessToken: string - - let userNotifications: UserNotification[] = [] - let adminNotifications: UserNotification[] = [] - let adminNotificationsServer2: UserNotification[] = [] - let emails: object[] = [] - - let channelId: number - - before(async function () { - this.timeout(120000) - - const res = await prepareNotificationsTest(3) - emails = res.emails - userAccessToken = res.userAccessToken - servers = res.servers - userNotifications = res.userNotifications - adminNotifications = res.adminNotifications - adminNotificationsServer2 = res.adminNotificationsServer2 - channelId = res.channelId - }) - - describe('New video from my subscription notification', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userAccessToken - } - }) - - it('Should not send notifications if the user does not follow the video publisher', async function () { - this.timeout(50000) - - await uploadRandomVideoOnServers(servers, 1) - - const notification = await servers[0].notifications.getLatest({ token: userAccessToken }) - expect(notification).to.be.undefined - - expect(emails).to.have.lengthOf(0) - expect(userNotifications).to.have.lengthOf(0) - }) - - it('Should send a new video notification if the user follows the local video publisher', async function () { - this.timeout(15000) - - await servers[0].subscriptions.add({ token: userAccessToken, targetUri: 'root_channel@' + servers[0].host }) - await waitJobs(servers) - - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 1) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a new video notification from a remote account', async function () { - this.timeout(150000) // Server 2 has transcoding enabled - - await servers[0].subscriptions.add({ token: userAccessToken, targetUri: 'root_channel@' + servers[1].host }) - await waitJobs(servers) - - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a new video notification on a scheduled publication', async function () { - this.timeout(50000) - - // In 2 seconds - const updateAt = new Date(new Date().getTime() + 2000) - - const data = { - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 1, data) - - await wait(6000) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a new video notification on a remote scheduled publication', async function () { - this.timeout(100000) - - // In 2 seconds - const updateAt = new Date(new Date().getTime() + 2000) - - const data = { - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2, data) - await waitJobs(servers) - - await wait(6000) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should not send a notification before the video is published', async function () { - this.timeout(150000) - - const updateAt = new Date(new Date().getTime() + 1000000) - - const data = { - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 1, data) - - await wait(6000) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should send a new video notification when a video becomes public', async function () { - this.timeout(50000) - - const data = { privacy: VideoPrivacy.PRIVATE } - const { name, uuid, shortUUID } = await uploadRandomVideoOnServers(servers, 1, data) - - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - - await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - - await waitJobs(servers) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a new video notification when a remote video becomes public', async function () { - this.timeout(120000) - - const data = { privacy: VideoPrivacy.PRIVATE } - const { name, uuid, shortUUID } = await uploadRandomVideoOnServers(servers, 2, data) - - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - - await servers[1].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - - await waitJobs(servers) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should not send a new video notification when a video becomes unlisted', async function () { - this.timeout(50000) - - const data = { privacy: VideoPrivacy.PRIVATE } - const { name, uuid, shortUUID } = await uploadRandomVideoOnServers(servers, 1, data) - - await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.UNLISTED } }) - - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should not send a new video notification when a remote video becomes unlisted', async function () { - this.timeout(100000) - - const data = { privacy: VideoPrivacy.PRIVATE } - const { name, uuid, shortUUID } = await uploadRandomVideoOnServers(servers, 2, data) - - await servers[1].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.UNLISTED } }) - - await waitJobs(servers) - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should send a new video notification after a video import', async function () { - this.timeout(100000) - - const name = 'video import ' + buildUUID() - - const attributes = { - name, - channelId, - privacy: VideoPrivacy.PUBLIC, - targetUrl: FIXTURE_URLS.goodVideo - } - const { video } = await servers[0].imports.importVideo({ attributes }) - - await waitJobs(servers) - - await checkNewVideoFromSubscription({ ...baseParams, videoName: name, shortUUID: video.shortUUID, checkType: 'presence' }) - }) - }) - - describe('My video is published', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[1], - emails, - socketNotifications: adminNotificationsServer2, - token: servers[1].accessToken - } - }) - - it('Should not send a notification if transcoding is not enabled', async function () { - this.timeout(50000) - - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 1) - await waitJobs(servers) - - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - }) - - it('Should not send a notification if the wait transcoding is false', async function () { - this.timeout(100_000) - - await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: false }) - await waitJobs(servers) - - const notification = await servers[0].notifications.getLatest({ token: userAccessToken }) - if (notification) { - expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) - } - }) - - it('Should send a notification even if the video is not transcoded in other resolutions', async function () { - this.timeout(100_000) - - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true, fixture: 'video_short_240p.mp4' }) - await waitJobs(servers) - - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a notification with a transcoded video', async function () { - this.timeout(100_000) - - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true }) - await waitJobs(servers) - - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should send a notification when an imported video is transcoded', async function () { - this.timeout(120000) - - const name = 'video import ' + buildUUID() - - const attributes = { - name, - channelId, - privacy: VideoPrivacy.PUBLIC, - targetUrl: FIXTURE_URLS.goodVideo, - waitTranscoding: true - } - const { video } = await servers[1].imports.importVideo({ attributes }) - - await waitJobs(servers) - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID: video.shortUUID, checkType: 'presence' }) - }) - - it('Should send a notification when the scheduled update has been proceeded', async function () { - this.timeout(70000) - - // In 2 seconds - const updateAt = new Date(new Date().getTime() + 2000) - - const data = { - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2, data) - - await wait(6000) - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - - it('Should not send a notification before the video is published', async function () { - this.timeout(150000) - - const updateAt = new Date(new Date().getTime() + 1000000) - - const data = { - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: updateAt.toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - const { name, shortUUID } = await uploadRandomVideoOnServers(servers, 2, data) - - await wait(6000) - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'absence' }) - }) - }) - - describe('My live replay is published', function () { - - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[1], - emails, - socketNotifications: adminNotificationsServer2, - token: servers[1].accessToken - } - }) - - it('Should send a notification is a live replay of a non permanent live is published', async function () { - this.timeout(120000) - - const { shortUUID } = await servers[1].live.create({ - fields: { - name: 'non permanent live', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[1].store.channel.id, - saveReplay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC }, - permanentLive: false - } - }) - - const ffmpegCommand = await servers[1].live.sendRTMPStreamInVideo({ videoId: shortUUID }) - - await waitJobs(servers) - await servers[1].live.waitUntilPublished({ videoId: shortUUID }) - - await stopFfmpeg(ffmpegCommand) - await servers[1].live.waitUntilReplacedByReplay({ videoId: shortUUID }) - - await waitJobs(servers) - await checkVideoIsPublished({ ...baseParams, videoName: 'non permanent live', shortUUID, checkType: 'presence' }) - }) - - it('Should send a notification is a live replay of a permanent live is published', async function () { - this.timeout(120000) - - const { shortUUID } = await servers[1].live.create({ - fields: { - name: 'permanent live', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[1].store.channel.id, - saveReplay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC }, - permanentLive: true - } - }) - - const ffmpegCommand = await servers[1].live.sendRTMPStreamInVideo({ videoId: shortUUID }) - - await waitJobs(servers) - await servers[1].live.waitUntilPublished({ videoId: shortUUID }) - - const liveDetails = await servers[1].videos.get({ id: shortUUID }) - - await stopFfmpeg(ffmpegCommand) - - await servers[1].live.waitUntilWaiting({ videoId: shortUUID }) - await waitJobs(servers) - - const video = await findExternalSavedVideo(servers[1], liveDetails) - expect(video).to.exist - - await checkVideoIsPublished({ ...baseParams, videoName: video.name, shortUUID: video.shortUUID, checkType: 'presence' }) - }) - }) - - describe('Video studio', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[1], - emails, - socketNotifications: adminNotificationsServer2, - token: servers[1].accessToken - } - }) - - it('Should send a notification after studio edition', async function () { - this.timeout(240000) - - const { name, shortUUID, id } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true }) - - await waitJobs(servers) - await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - - const tasks: VideoStudioTask[] = [ - { - name: 'cut', - options: { - start: 0, - end: 1 - } - } - ] - await servers[1].videoStudio.createEditionTasks({ videoId: id, tasks }) - await waitJobs(servers) - - await checkVideoStudioEditionIsFinished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) - }) - }) - - describe('My video is imported', function () { - let baseParams: CheckerBaseParams - - before(() => { - baseParams = { - server: servers[0], - emails, - socketNotifications: adminNotifications, - token: servers[0].accessToken - } - }) - - it('Should send a notification when the video import failed', async function () { - this.timeout(70000) - - const name = 'video import ' + buildUUID() - - const attributes = { - name, - channelId, - privacy: VideoPrivacy.PRIVATE, - targetUrl: FIXTURE_URLS.badVideo - } - const { video: { shortUUID } } = await servers[0].imports.importVideo({ attributes }) - - await waitJobs(servers) - - const url = FIXTURE_URLS.badVideo - await checkMyVideoImportIsFinished({ ...baseParams, videoName: name, shortUUID, url, success: false, checkType: 'presence' }) - }) - - it('Should send a notification when the video import succeeded', async function () { - this.timeout(70000) - - const name = 'video import ' + buildUUID() - - const attributes = { - name, - channelId, - privacy: VideoPrivacy.PRIVATE, - targetUrl: FIXTURE_URLS.goodVideo - } - const { video: { shortUUID } } = await servers[0].imports.importVideo({ attributes }) - - await waitJobs(servers) - - const url = FIXTURE_URLS.goodVideo - await checkMyVideoImportIsFinished({ ...baseParams, videoName: name, shortUUID, url, success: true, checkType: 'presence' }) - }) - }) - - describe('New actor follow', function () { - let baseParams: CheckerBaseParams - const myChannelName = 'super channel name' - const myUserName = 'super user name' - - before(async function () { - baseParams = { - server: servers[0], - emails, - socketNotifications: userNotifications, - token: userAccessToken - } - - await servers[0].users.updateMe({ displayName: 'super root name' }) - - await servers[0].users.updateMe({ - token: userAccessToken, - displayName: myUserName - }) - - await servers[1].users.updateMe({ displayName: 'super root 2 name' }) - - await servers[0].channels.update({ - token: userAccessToken, - channelName: 'user_1_channel', - attributes: { displayName: myChannelName } - }) - }) - - it('Should notify when a local channel is following one of our channel', async function () { - this.timeout(50000) - - await servers[0].subscriptions.add({ targetUri: 'user_1_channel@' + servers[0].host }) - await waitJobs(servers) - - await checkNewActorFollow({ - ...baseParams, - followType: 'channel', - followerName: 'root', - followerDisplayName: 'super root name', - followingDisplayName: myChannelName, - checkType: 'presence' - }) - - await servers[0].subscriptions.remove({ uri: 'user_1_channel@' + servers[0].host }) - }) - - it('Should notify when a remote channel is following one of our channel', async function () { - this.timeout(50000) - - await servers[1].subscriptions.add({ targetUri: 'user_1_channel@' + servers[0].host }) - await waitJobs(servers) - - await checkNewActorFollow({ - ...baseParams, - followType: 'channel', - followerName: 'root', - followerDisplayName: 'super root 2 name', - followingDisplayName: myChannelName, - checkType: 'presence' - }) - - await servers[1].subscriptions.remove({ uri: 'user_1_channel@' + servers[0].host }) - }) - - // PeerTube does not support account -> account follows - // it('Should notify when a local account is following one of our channel', async function () { - // this.timeout(50000) - // - // await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@' + servers[0].host) - // - // await waitJobs(servers) - // - // await checkNewActorFollow(baseParams, 'account', 'root', 'super root name', myUserName, 'presence') - // }) - - // it('Should notify when a remote account is following one of our channel', async function () { - // this.timeout(50000) - // - // await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@' + servers[0].host) - // - // await waitJobs(servers) - // - // await checkNewActorFollow(baseParams, 'account', 'root', 'super root 2 name', myUserName, 'presence') - // }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/object-storage/index.ts b/server/tests/api/object-storage/index.ts deleted file mode 100644 index 1f4489fa3..000000000 --- a/server/tests/api/object-storage/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './live' -export * from './video-imports' -export * from './video-static-file-privacy' -export * from './videos' diff --git a/server/tests/api/object-storage/live.ts b/server/tests/api/object-storage/live.ts deleted file mode 100644 index 07ff4763b..000000000 --- a/server/tests/api/object-storage/live.ts +++ /dev/null @@ -1,311 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectStartWith, MockObjectStorageProxy, SQLCommand, testLiveVideoResolutions } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - findExternalSavedVideo, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs, - waitUntilLivePublishedOnAllServers, - waitUntilLiveReplacedByReplayOnAllServers, - waitUntilLiveWaitingOnAllServers -} from '@shared/server-commands' - -async function createLive (server: PeerTubeServer, permanent: boolean) { - const attributes: LiveVideoCreate = { - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC, - name: 'my super live', - saveReplay: true, - replaySettings: { privacy: VideoPrivacy.PUBLIC }, - permanentLive: permanent - } - - const { uuid } = await server.live.create({ fields: attributes }) - - return uuid -} - -async function checkFilesExist (options: { - servers: PeerTubeServer[] - videoUUID: string - numberOfFiles: number - objectStorage: ObjectStorageCommand -}) { - const { servers, videoUUID, numberOfFiles, objectStorage } = options - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.files).to.have.lengthOf(0) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const files = video.streamingPlaylists[0].files - expect(files).to.have.lengthOf(numberOfFiles) - - for (const file of files) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - } -} - -async function checkFilesCleanup (options: { - server: PeerTubeServer - videoUUID: string - resolutions: number[] - objectStorage: ObjectStorageCommand -}) { - const { server, videoUUID, resolutions, objectStorage } = options - - const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`) - - for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) { - await server.live.getPlaylistFile({ - videoUUID, - playlistName, - expectedStatus: HttpStatusCode.NOT_FOUND_404, - objectStorage - }) - } - - await server.live.getSegmentFile({ - videoUUID, - playlistNumber: 0, - segment: 0, - objectStorage, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) -} - -describe('Object storage for lives', function () { - if (areMockObjectStorageTestsDisabled()) return - - let servers: PeerTubeServer[] - let sqlCommandServer1: SQLCommand - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - await objectStorage.prepareDefaultMockBuckets() - servers = await createMultipleServers(2, objectStorage.getDefaultMockConfig()) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableTranscoding() - - sqlCommandServer1 = new SQLCommand(servers[0]) - }) - - describe('Without live transcoding', function () { - let videoUUID: string - - before(async function () { - await servers[0].config.enableLive({ transcoding: false }) - - videoUUID = await createLive(servers[0], false) - }) - - it('Should create a live and publish it on object storage', async function () { - this.timeout(220000) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID }) - await waitUntilLivePublishedOnAllServers(servers, videoUUID) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: videoUUID, - resolutions: [ 720 ], - transcoded: false, - objectStorage - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have saved the replay on object storage', async function () { - this.timeout(220000) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID) - await waitJobs(servers) - - await checkFilesExist({ servers, videoUUID, numberOfFiles: 1, objectStorage }) - }) - - it('Should have cleaned up live files from object storage', async function () { - await checkFilesCleanup({ server: servers[0], videoUUID, resolutions: [ 720 ], objectStorage }) - }) - }) - - describe('With live transcoding', function () { - const resolutions = [ 720, 480, 360, 240, 144 ] - - before(async function () { - await servers[0].config.enableLive({ transcoding: true }) - }) - - describe('Normal replay', function () { - let videoUUIDNonPermanent: string - - before(async function () { - videoUUIDNonPermanent = await createLive(servers[0], false) - }) - - it('Should create a live and publish it on object storage', async function () { - this.timeout(240000) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent }) - await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: videoUUIDNonPermanent, - resolutions, - transcoded: true, - objectStorage - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have saved the replay on object storage', async function () { - this.timeout(220000) - - await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent) - await waitJobs(servers) - - await checkFilesExist({ servers, videoUUID: videoUUIDNonPermanent, numberOfFiles: 5, objectStorage }) - }) - - it('Should have cleaned up live files from object storage', async function () { - await checkFilesCleanup({ server: servers[0], videoUUID: videoUUIDNonPermanent, resolutions, objectStorage }) - }) - }) - - describe('Permanent replay', function () { - let videoUUIDPermanent: string - - before(async function () { - videoUUIDPermanent = await createLive(servers[0], true) - }) - - it('Should create a live and publish it on object storage', async function () { - this.timeout(240000) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent }) - await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: videoUUIDPermanent, - resolutions, - transcoded: true, - objectStorage - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have saved the replay on object storage', async function () { - this.timeout(220000) - - await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent) - await waitJobs(servers) - - const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent }) - const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) - - await checkFilesExist({ servers, videoUUID: replay.uuid, numberOfFiles: 5, objectStorage }) - }) - - it('Should have cleaned up live files from object storage', async function () { - await checkFilesCleanup({ server: servers[0], videoUUID: videoUUIDPermanent, resolutions, objectStorage }) - }) - }) - }) - - describe('With object storage base url', function () { - const mockObjectStorageProxy = new MockObjectStorageProxy() - let baseMockUrl: string - - before(async function () { - this.timeout(120000) - - const port = await mockObjectStorageProxy.initialize() - const bucketName = objectStorage.getMockStreamingPlaylistsBucketName() - baseMockUrl = `http://127.0.0.1:${port}/${bucketName}` - - await objectStorage.prepareDefaultMockBuckets() - - const config = { - object_storage: { - enabled: true, - endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(), - region: ObjectStorageCommand.getMockRegion(), - - credentials: ObjectStorageCommand.getMockCredentialsConfig(), - - streaming_playlists: { - bucket_name: bucketName, - prefix: '', - base_url: baseMockUrl - } - } - } - - await servers[0].kill() - await servers[0].run(config) - - await servers[0].config.enableLive({ transcoding: true, resolutions: 'min' }) - }) - - it('Should publish a live and replace the base url', async function () { - this.timeout(240000) - - const videoUUIDPermanent = await createLive(servers[0], true) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent }) - await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: videoUUIDPermanent, - resolutions: [ 720 ], - transcoded: true, - objectStorage, - objectStorageBaseUrl: baseMockUrl - }) - - await stopFfmpeg(ffmpegCommand) - }) - }) - - after(async function () { - await sqlCommandServer1.cleanup() - await objectStorage.cleanupMock() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/object-storage/video-imports.ts b/server/tests/api/object-storage/video-imports.ts deleted file mode 100644 index 57150e5a6..000000000 --- a/server/tests/api/object-storage/video-imports.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectStartWith, FIXTURE_URLS } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -async function importVideo (server: PeerTubeServer) { - const attributes = { - name: 'import 2', - privacy: VideoPrivacy.PUBLIC, - channelId: server.store.channel.id, - targetUrl: FIXTURE_URLS.goodVideo720 - } - - const { video: { uuid } } = await server.imports.importVideo({ attributes }) - - return uuid -} - -describe('Object storage for video import', function () { - if (areMockObjectStorageTestsDisabled()) return - - let server: PeerTubeServer - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - await objectStorage.prepareDefaultMockBuckets() - - server = await createSingleServer(1, objectStorage.getDefaultMockConfig()) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableImports() - }) - - describe('Without transcoding', async function () { - - before(async function () { - await server.config.disableTranscoding() - }) - - it('Should import a video and have sent it to object storage', async function () { - this.timeout(120000) - - const uuid = await importVideo(server) - await waitJobs(server) - - const video = await server.videos.get({ id: uuid }) - - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(0) - - const fileUrl = video.files[0].fileUrl - expectStartWith(fileUrl, objectStorage.getMockWebVideosBaseUrl()) - - await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('With transcoding', async function () { - - before(async function () { - await server.config.enableTranscoding() - }) - - it('Should import a video and have sent it to object storage', async function () { - this.timeout(120000) - - const uuid = await importVideo(server) - await waitJobs(server) - - const video = await server.videos.get({ id: uuid }) - - expect(video.files).to.have.lengthOf(5) - expect(video.streamingPlaylists).to.have.lengthOf(1) - expect(video.streamingPlaylists[0].files).to.have.lengthOf(5) - - for (const file of video.files) { - expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - for (const file of video.streamingPlaylists[0].files) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - }) - - after(async function () { - await objectStorage.cleanupMock() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/object-storage/video-static-file-privacy.ts b/server/tests/api/object-storage/video-static-file-privacy.ts deleted file mode 100644 index 64ab542a5..000000000 --- a/server/tests/api/object-storage/video-static-file-privacy.ts +++ /dev/null @@ -1,570 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { basename } from 'path' -import { checkVideoFileTokenReinjection, expectStartWith, SQLCommand } from '@server/tests/shared' -import { areScalewayObjectStorageTestsDisabled, getAllFiles, getHLS } from '@shared/core-utils' -import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - findExternalSavedVideo, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -function extractFilenameFromUrl (url: string) { - const parts = basename(url).split(':') - - return parts[parts.length - 1] -} - -describe('Object storage for video static file privacy', function () { - // We need real world object storage to check ACL - if (areScalewayObjectStorageTestsDisabled()) return - - let server: PeerTubeServer - let sqlCommand: SQLCommand - let userToken: string - - // --------------------------------------------------------------------------- - - async function checkPrivateVODFiles (uuid: string) { - const video = await server.videos.getWithToken({ id: uuid }) - - for (const file of video.files) { - expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/web-videos/private/') - - await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - } - - for (const file of getAllFiles(video)) { - const internalFileUrl = await sqlCommand.getInternalFileUrl(file.id) - expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl()) - await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - } - - const hls = getHLS(video) - - if (hls) { - for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { - expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') - } - - await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - - for (const file of hls.files) { - expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') - - await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - } - } - } - - async function checkPublicVODFiles (uuid: string) { - const video = await server.videos.getWithToken({ id: uuid }) - - for (const file of getAllFiles(video)) { - expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl()) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - const hls = getHLS(video) - - if (hls) { - expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl()) - expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl()) - - await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - // --------------------------------------------------------------------------- - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig({ serverNumber: 1 })) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableMinimumTranscoding() - - userToken = await server.users.generateUserAndToken('user1') - - sqlCommand = new SQLCommand(server) - }) - - describe('VOD', function () { - let privateVideoUUID: string - let publicVideoUUID: string - let passwordProtectedVideoUUID: string - let userPrivateVideoUUID: string - - const correctPassword = 'my super password' - const correctPasswordHeader = { 'x-peertube-video-password': correctPassword } - const incorrectPasswordHeader = { 'x-peertube-video-password': correctPassword + 'toto' } - - // --------------------------------------------------------------------------- - - async function getSampleFileUrls (videoId: string) { - const video = await server.videos.getWithToken({ id: videoId }) - - return { - webVideoFile: video.files[0].fileUrl, - hlsFile: getHLS(video).files[0].fileUrl - } - } - - // --------------------------------------------------------------------------- - - it('Should upload a private video and have appropriate object storage ACL', async function () { - this.timeout(120000) - - { - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - privateVideoUUID = uuid - } - - { - const { uuid } = await server.videos.quickUpload({ name: 'user video', token: userToken, privacy: VideoPrivacy.PRIVATE }) - userPrivateVideoUUID = uuid - } - - await waitJobs([ server ]) - - await checkPrivateVODFiles(privateVideoUUID) - }) - - it('Should upload a password protected video and have appropriate object storage ACL', async function () { - this.timeout(120000) - - { - const { uuid } = await server.videos.quickUpload({ - name: 'video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ correctPassword ] - }) - passwordProtectedVideoUUID = uuid - } - await waitJobs([ server ]) - - await checkPrivateVODFiles(passwordProtectedVideoUUID) - }) - - it('Should upload a public video and have appropriate object storage ACL', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED }) - await waitJobs([ server ]) - - publicVideoUUID = uuid - - await checkPublicVODFiles(publicVideoUUID) - }) - - it('Should not get files without appropriate OAuth token', async function () { - this.timeout(60000) - - const { webVideoFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) - - await makeRawRequest({ url: webVideoFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url: webVideoFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should not get files without appropriate password or appropriate OAuth token', async function () { - this.timeout(60000) - - const { webVideoFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) - - await makeRawRequest({ url: webVideoFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ - url: webVideoFile, - token: null, - headers: incorrectPasswordHeader, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - await makeRawRequest({ url: webVideoFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ - url: webVideoFile, - token: null, - headers: correctPasswordHeader, - expectedStatus: HttpStatusCode.OK_200 - }) - - await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ - url: hlsFile, - token: null, - headers: incorrectPasswordHeader, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ - url: hlsFile, - token: null, - headers: correctPasswordHeader, - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should not get HLS file of another video', async function () { - this.timeout(60000) - - const privateVideo = await server.videos.getWithToken({ id: privateVideoUUID }) - const hlsFilename = basename(getHLS(privateVideo).files[0].fileUrl) - - const badUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + userPrivateVideoUUID + '/' + hlsFilename - const goodUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + privateVideoUUID + '/' + hlsFilename - - await makeRawRequest({ url: badUrl, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should correctly check OAuth, video file token of private video', async function () { - this.timeout(60000) - - const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) - const goodVideoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID }) - - const { webVideoFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) - - for (const url of [ webVideoFile, hlsFile ]) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - } - }) - - it('Should correctly check OAuth, video file token or video password of password protected video', async function () { - this.timeout(60000) - - const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) - const goodVideoFileToken = await server.videoToken.getVideoFileToken({ - videoId: passwordProtectedVideoUUID, - videoPassword: correctPassword - }) - - const { webVideoFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) - - for (const url of [ hlsFile, webVideoFile ]) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ - url, - headers: incorrectPasswordHeader, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - await makeRawRequest({ url, headers: correctPasswordHeader, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should reinject video file token', async function () { - this.timeout(120000) - - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID }) - - await checkVideoFileTokenReinjection({ - server, - videoUUID: privateVideoUUID, - videoFileToken, - resolutions: [ 240, 720 ], - isLive: false - }) - }) - - it('Should update public video to private', async function () { - this.timeout(60000) - - await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.INTERNAL } }) - - await checkPrivateVODFiles(publicVideoUUID) - }) - - it('Should update private video to public', async function () { - this.timeout(60000) - - await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } }) - - await checkPublicVODFiles(publicVideoUUID) - }) - }) - - describe('Live', function () { - let normalLiveId: string - let normalLive: LiveVideo - - let permanentLiveId: string - let permanentLive: LiveVideo - - let passwordProtectedLiveId: string - let passwordProtectedLive: LiveVideo - - const correctPassword = 'my super password' - - let unrelatedFileToken: string - - // --------------------------------------------------------------------------- - - async function checkLiveFiles (live: LiveVideo, liveId: string, videoPassword?: string) { - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await server.live.waitUntilPublished({ videoId: liveId }) - - const video = videoPassword - ? await server.videos.getWithPassword({ id: liveId, password: videoPassword }) - : await server.videos.getWithToken({ id: liveId }) - - const fileToken = videoPassword - ? await server.videoToken.getVideoFileToken({ token: null, videoId: video.uuid, videoPassword }) - : await server.videoToken.getVideoFileToken({ videoId: video.uuid }) - - const hls = video.streamingPlaylists[0] - - for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { - expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') - - await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - if (videoPassword) { - await makeRawRequest({ url, headers: { 'x-peertube-video-password': videoPassword }, expectedStatus: HttpStatusCode.OK_200 }) - } - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - if (videoPassword) { - await makeRawRequest({ - url, - headers: { 'x-peertube-video-password': 'incorrectPassword' }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - } - - await stopFfmpeg(ffmpegCommand) - } - - async function checkReplay (replay: VideoDetails) { - const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) - - const hls = replay.streamingPlaylists[0] - expect(hls.files).to.not.have.lengthOf(0) - - for (const file of hls.files) { - await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ - url: file.fileUrl, - query: { videoFileToken: unrelatedFileToken }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - - for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { - expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') - - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - } - } - - // --------------------------------------------------------------------------- - - before(async function () { - await server.config.enableMinimumTranscoding() - - const { uuid } = await server.videos.quickUpload({ name: 'another video' }) - unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - - await server.config.enableLive({ - allowReplay: true, - transcoding: true, - resolutions: 'min' - }) - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: true, - permanentLive: false, - privacy: VideoPrivacy.PRIVATE - }) - normalLiveId = video.uuid - normalLive = live - } - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: true, - permanentLive: true, - privacy: VideoPrivacy.PRIVATE - }) - permanentLiveId = video.uuid - permanentLive = live - } - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: false, - permanentLive: false, - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ correctPassword ] - }) - passwordProtectedLiveId = video.uuid - passwordProtectedLive = live - } - }) - - it('Should create a private normal live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles(normalLive, normalLiveId) - }) - - it('Should create a private permanent live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles(permanentLive, permanentLiveId) - }) - - it('Should create a password protected live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles(passwordProtectedLive, passwordProtectedLiveId, correctPassword) - }) - - it('Should reinject video file token in permanent live', async function () { - this.timeout(240000) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: permanentLive.rtmpUrl, streamKey: permanentLive.streamKey }) - await server.live.waitUntilPublished({ videoId: permanentLiveId }) - - const video = await server.videos.getWithToken({ id: permanentLiveId }) - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) - - await checkVideoFileTokenReinjection({ - server, - videoUUID: permanentLiveId, - videoFileToken, - resolutions: [ 720 ], - isLive: true - }) - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have created a replay of the normal live with a private static path', async function () { - this.timeout(240000) - - await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) - - const replay = await server.videos.getWithToken({ id: normalLiveId }) - await checkReplay(replay) - }) - - it('Should have created a replay of the permanent live with a private static path', async function () { - this.timeout(240000) - - await server.live.waitUntilWaiting({ videoId: permanentLiveId }) - await waitJobs([ server ]) - - const live = await server.videos.getWithToken({ id: permanentLiveId }) - const replayFromList = await findExternalSavedVideo(server, live) - const replay = await server.videos.getWithToken({ id: replayFromList.id }) - - await checkReplay(replay) - }) - }) - - describe('With private files proxy disabled and public ACL for private files', function () { - let videoUUID: string - - before(async function () { - this.timeout(240000) - - await server.kill() - - const config = ObjectStorageCommand.getDefaultScalewayConfig({ - serverNumber: 1, - enablePrivateProxy: false, - privateACL: 'public-read' - }) - await server.run(config) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - videoUUID = uuid - - await waitJobs([ server ]) - }) - - it('Should display object storage path for a private video and be able to access them', async function () { - this.timeout(60000) - - await checkPublicVODFiles(videoUUID) - }) - - it('Should not be able to access object storage proxy', async function () { - const privateVideo = await server.videos.getWithToken({ id: videoUUID }) - const webVideoFilename = extractFilenameFromUrl(privateVideo.files[0].fileUrl) - const hlsFilename = extractFilenameFromUrl(getHLS(privateVideo).files[0].fileUrl) - - await makeRawRequest({ - url: server.url + '/object-storage-proxy/web-videos/private/' + webVideoFilename, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeRawRequest({ - url: server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + videoUUID + '/' + hlsFilename, - token: server.accessToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - }) - - after(async function () { - this.timeout(240000) - - const { data } = await server.videos.listAllForAdmin() - - for (const v of data) { - await server.videos.remove({ id: v.uuid }) - } - - for (const v of data) { - await server.servers.waitUntilLog('Removed files of video ' + v.url) - } - - await sqlCommand.cleanup() - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/object-storage/videos.ts b/server/tests/api/object-storage/videos.ts deleted file mode 100644 index dcc52ef06..000000000 --- a/server/tests/api/object-storage/videos.ts +++ /dev/null @@ -1,438 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import bytes from 'bytes' -import { expect } from 'chai' -import { stat } from 'fs-extra' -import { merge } from 'lodash' -import { - checkTmpIsEmpty, - checkWebTorrentWorks, - expectLogDoesNotContain, - expectStartWith, - generateHighBitrateVideo, - MockObjectStorageProxy, - SQLCommand -} from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { sha1 } from '@shared/extra-utils' -import { HttpStatusCode, VideoDetails } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - createSingleServer, - doubleFollow, - killallServers, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -async function checkFiles (options: { - server: PeerTubeServer - originServer: PeerTubeServer - originSQLCommand: SQLCommand - - video: VideoDetails - - baseMockUrl?: string - - playlistBucket: string - playlistPrefix?: string - - webVideoBucket: string - webVideoPrefix?: string -}) { - const { - server, - originServer, - originSQLCommand, - video, - playlistBucket, - webVideoBucket, - baseMockUrl, - playlistPrefix, - webVideoPrefix - } = options - - let allFiles = video.files - - for (const file of video.files) { - const baseUrl = baseMockUrl - ? `${baseMockUrl}/${webVideoBucket}/` - : `http://${webVideoBucket}.${ObjectStorageCommand.getMockEndpointHost()}/` - - const prefix = webVideoPrefix || '' - const start = baseUrl + prefix - - expectStartWith(file.fileUrl, start) - - const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) - const location = res.headers['location'] - expectStartWith(location, start) - - await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) - } - - const hls = video.streamingPlaylists[0] - - if (hls) { - allFiles = allFiles.concat(hls.files) - - const baseUrl = baseMockUrl - ? `${baseMockUrl}/${playlistBucket}/` - : `http://${playlistBucket}.${ObjectStorageCommand.getMockEndpointHost()}/` - - const prefix = playlistPrefix || '' - const start = baseUrl + prefix - - expectStartWith(hls.playlistUrl, start) - expectStartWith(hls.segmentsSha256Url, start) - - await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - - const resSha = await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) - expect(JSON.stringify(resSha.body)).to.not.throw - - let i = 0 - for (const file of hls.files) { - expectStartWith(file.fileUrl, start) - - const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) - const location = res.headers['location'] - expectStartWith(location, start) - - await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) - - if (originServer.internalServerNumber === server.internalServerNumber) { - const infohash = sha1(`${2 + hls.playlistUrl}+V${i}`) - const dbInfohashes = await originSQLCommand.getPlaylistInfohash(hls.id) - - expect(dbInfohashes).to.include(infohash) - } - - i++ - } - } - - for (const file of allFiles) { - await checkWebTorrentWorks(file.magnetUri) - - const res = await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.have.length.above(100) - } - - return allFiles.map(f => f.fileUrl) -} - -function runTestSuite (options: { - fixture?: string - - maxUploadPart?: string - - playlistBucket: string - playlistPrefix?: string - - webVideoBucket: string - webVideoPrefix?: string - - useMockBaseUrl?: boolean -}) { - const mockObjectStorageProxy = new MockObjectStorageProxy() - const { fixture } = options - let baseMockUrl: string - - let servers: PeerTubeServer[] - let sqlCommands: SQLCommand[] = [] - const objectStorage = new ObjectStorageCommand() - - let keptUrls: string[] = [] - - const uuidsToDelete: string[] = [] - let deletedUrls: string[] = [] - - before(async function () { - this.timeout(240000) - - const port = await mockObjectStorageProxy.initialize() - baseMockUrl = options.useMockBaseUrl - ? `http://127.0.0.1:${port}` - : undefined - - await objectStorage.createMockBucket(options.playlistBucket) - await objectStorage.createMockBucket(options.webVideoBucket) - - const config = { - object_storage: { - enabled: true, - endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(), - region: ObjectStorageCommand.getMockRegion(), - - credentials: ObjectStorageCommand.getMockCredentialsConfig(), - - max_upload_part: options.maxUploadPart || '5MB', - - streaming_playlists: { - bucket_name: options.playlistBucket, - prefix: options.playlistPrefix, - base_url: baseMockUrl - ? `${baseMockUrl}/${options.playlistBucket}` - : undefined - }, - - web_videos: { - bucket_name: options.webVideoBucket, - prefix: options.webVideoPrefix, - base_url: baseMockUrl - ? `${baseMockUrl}/${options.webVideoBucket}` - : undefined - } - } - } - - servers = await createMultipleServers(2, config) - - await setAccessTokensToServers(servers) - await doubleFollow(servers[0], servers[1]) - - for (const server of servers) { - const { uuid } = await server.videos.quickUpload({ name: 'video to keep' }) - await waitJobs(servers) - - const files = await server.videos.listFiles({ id: uuid }) - keptUrls = keptUrls.concat(files.map(f => f.fileUrl)) - } - - sqlCommands = servers.map(s => new SQLCommand(s)) - }) - - it('Should upload a video and move it to the object storage without transcoding', async function () { - this.timeout(40000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1', fixture }) - uuidsToDelete.push(uuid) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - const files = await checkFiles({ ...options, server, originServer: servers[0], originSQLCommand: sqlCommands[0], video, baseMockUrl }) - - deletedUrls = deletedUrls.concat(files) - } - }) - - it('Should upload a video and move it to the object storage with transcoding', async function () { - this.timeout(120000) - - const { uuid } = await servers[1].videos.quickUpload({ name: 'video 2', fixture }) - uuidsToDelete.push(uuid) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - const files = await checkFiles({ ...options, server, originServer: servers[0], originSQLCommand: sqlCommands[0], video, baseMockUrl }) - - deletedUrls = deletedUrls.concat(files) - } - }) - - it('Should fetch correctly all the files', async function () { - for (const url of deletedUrls.concat(keptUrls)) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should correctly delete the files', async function () { - await servers[0].videos.remove({ id: uuidsToDelete[0] }) - await servers[1].videos.remove({ id: uuidsToDelete[1] }) - - await waitJobs(servers) - - for (const url of deletedUrls) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - - it('Should have kept other files', async function () { - for (const url of keptUrls) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should have an empty tmp directory', async function () { - for (const server of servers) { - await checkTmpIsEmpty(server) - } - }) - - it('Should not have downloaded files from object storage', async function () { - for (const server of servers) { - await expectLogDoesNotContain(server, 'from object storage') - } - }) - - after(async function () { - await mockObjectStorageProxy.terminate() - await objectStorage.cleanupMock() - - for (const sqlCommand of sqlCommands) { - await sqlCommand.cleanup() - } - - await cleanupTests(servers) - }) -} - -describe('Object storage for videos', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - describe('Test config', function () { - let server: PeerTubeServer - - const baseConfig = objectStorage.getDefaultMockConfig() - - const badCredentials = { - access_key_id: 'AKIAIOSFODNN7EXAMPLE', - secret_access_key: 'aJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' - } - - it('Should fail with same bucket names without prefix', function (done) { - const config = merge({}, baseConfig, { - object_storage: { - streaming_playlists: { - bucket_name: 'aaa' - }, - - web_videos: { - bucket_name: 'aaa' - } - } - }) - - createSingleServer(1, config) - .then(() => done(new Error('Did not throw'))) - .catch(() => done()) - }) - - it('Should fail with bad credentials', async function () { - this.timeout(60000) - - await objectStorage.prepareDefaultMockBuckets() - - const config = merge({}, baseConfig, { - object_storage: { - credentials: badCredentials - } - }) - - server = await createSingleServer(1, config) - await setAccessTokensToServers([ server ]) - - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - - await waitJobs([ server ], { skipDelayed: true }) - const video = await server.videos.get({ id: uuid }) - - expectStartWith(video.files[0].fileUrl, server.url) - - await killallServers([ server ]) - }) - - it('Should succeed with credentials from env', async function () { - this.timeout(60000) - - await objectStorage.prepareDefaultMockBuckets() - - const config = merge({}, baseConfig, { - object_storage: { - credentials: { - access_key_id: '', - secret_access_key: '' - } - } - }) - - const goodCredentials = ObjectStorageCommand.getMockCredentialsConfig() - - server = await createSingleServer(1, config, { - env: { - AWS_ACCESS_KEY_ID: goodCredentials.access_key_id, - AWS_SECRET_ACCESS_KEY: goodCredentials.secret_access_key - } - }) - - await setAccessTokensToServers([ server ]) - - const { uuid } = await server.videos.quickUpload({ name: 'video' }) - - await waitJobs([ server ], { skipDelayed: true }) - const video = await server.videos.get({ id: uuid }) - - expectStartWith(video.files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) - }) - - after(async function () { - await objectStorage.cleanupMock() - - await cleanupTests([ server ]) - }) - }) - - describe('Test simple object storage', function () { - runTestSuite({ - playlistBucket: objectStorage.getMockBucketName('streaming-playlists'), - webVideoBucket: objectStorage.getMockBucketName('web-videos') - }) - }) - - describe('Test object storage with prefix', function () { - runTestSuite({ - playlistBucket: objectStorage.getMockBucketName('mybucket'), - webVideoBucket: objectStorage.getMockBucketName('mybucket'), - - playlistPrefix: 'streaming-playlists_', - webVideoPrefix: 'webvideo_' - }) - }) - - describe('Test object storage with prefix and base URL', function () { - runTestSuite({ - playlistBucket: objectStorage.getMockBucketName('mybucket'), - webVideoBucket: objectStorage.getMockBucketName('mybucket'), - - playlistPrefix: 'streaming-playlists/', - webVideoPrefix: 'webvideo/', - - useMockBaseUrl: true - }) - }) - - describe('Test object storage with file bigger than upload part', function () { - let fixture: string - const maxUploadPart = '5MB' - - before(async function () { - this.timeout(120000) - - fixture = await generateHighBitrateVideo() - - const { size } = await stat(fixture) - - if (bytes.parse(maxUploadPart) > size) { - throw Error(`Fixture file is too small (${size}) to make sense for this test.`) - } - }) - - runTestSuite({ - maxUploadPart, - playlistBucket: objectStorage.getMockBucketName('streaming-playlists'), - webVideoBucket: objectStorage.getMockBucketName('web-videos'), - fixture - }) - }) -}) diff --git a/server/tests/api/redundancy/index.ts b/server/tests/api/redundancy/index.ts deleted file mode 100644 index 37dc3f88c..000000000 --- a/server/tests/api/redundancy/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import './redundancy-constraints' -import './redundancy' -import './manage-redundancy' diff --git a/server/tests/api/redundancy/manage-redundancy.ts b/server/tests/api/redundancy/manage-redundancy.ts deleted file mode 100644 index 404b65a99..000000000 --- a/server/tests/api/redundancy/manage-redundancy.ts +++ /dev/null @@ -1,324 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - RedundancyCommand, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { VideoPrivacy, VideoRedundanciesTarget } from '@shared/models' - -describe('Test manage videos redundancy', function () { - const targets: VideoRedundanciesTarget[] = [ 'my-videos', 'remote-videos' ] - - let servers: PeerTubeServer[] - let video1Server2UUID: string - let video2Server2UUID: string - let redundanciesToRemove: number[] = [] - - let commands: RedundancyCommand[] - - before(async function () { - this.timeout(120000) - - const config = { - transcoding: { - hls: { - enabled: true - } - }, - redundancy: { - videos: { - check_interval: '1 second', - strategies: [ - { - strategy: 'recently-added', - min_lifetime: '1 hour', - size: '10MB', - min_views: 0 - } - ] - } - } - } - servers = await createMultipleServers(3, config) - - // Get the access tokens - await setAccessTokensToServers(servers) - - commands = servers.map(s => s.redundancy) - - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 1 server 2' } }) - video1Server2UUID = uuid - } - - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 2 server 2' } }) - video2Server2UUID = uuid - } - - await waitJobs(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - await doubleFollow(servers[0], servers[2]) - await commands[0].updateRedundancy({ host: servers[1].host, redundancyAllowed: true }) - - await waitJobs(servers) - }) - - it('Should not have redundancies on server 3', async function () { - for (const target of targets) { - const body = await commands[2].listVideos({ target }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should correctly list followings by redundancy', async function () { - const body = await servers[0].follows.getFollowings({ sort: '-redundancyAllowed' }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - expect(body.data[0].following.host).to.equal(servers[1].host) - expect(body.data[1].following.host).to.equal(servers[2].host) - }) - - it('Should not have "remote-videos" redundancies on server 2', async function () { - this.timeout(120000) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 10) - await waitJobs(servers) - - const body = await commands[1].listVideos({ target: 'remote-videos' }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should have "my-videos" redundancies on server 2', async function () { - this.timeout(120000) - - const body = await commands[1].listVideos({ target: 'my-videos' }) - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - - const videos1 = videos.find(v => v.uuid === video1Server2UUID) - const videos2 = videos.find(v => v.uuid === video2Server2UUID) - - expect(videos1.name).to.equal('video 1 server 2') - expect(videos2.name).to.equal('video 2 server 2') - - expect(videos1.redundancies.files).to.have.lengthOf(4) - expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) - - const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) - - for (const r of redundancies) { - expect(r.strategy).to.be.null - expect(r.fileUrl).to.exist - expect(r.createdAt).to.exist - expect(r.updatedAt).to.exist - expect(r.expiresOn).to.exist - } - }) - - it('Should not have "my-videos" redundancies on server 1', async function () { - const body = await commands[0].listVideos({ target: 'my-videos' }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should have "remote-videos" redundancies on server 1', async function () { - this.timeout(120000) - - const body = await commands[0].listVideos({ target: 'remote-videos' }) - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - - const videos1 = videos.find(v => v.uuid === video1Server2UUID) - const videos2 = videos.find(v => v.uuid === video2Server2UUID) - - expect(videos1.name).to.equal('video 1 server 2') - expect(videos2.name).to.equal('video 2 server 2') - - expect(videos1.redundancies.files).to.have.lengthOf(4) - expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) - - const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) - - for (const r of redundancies) { - expect(r.strategy).to.equal('recently-added') - expect(r.fileUrl).to.exist - expect(r.createdAt).to.exist - expect(r.updatedAt).to.exist - expect(r.expiresOn).to.exist - } - }) - - it('Should correctly paginate and sort results', async function () { - { - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: 'name', - start: 0, - count: 2 - }) - - const videos = body.data - expect(videos[0].name).to.equal('video 1 server 2') - expect(videos[1].name).to.equal('video 2 server 2') - } - - { - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: '-name', - start: 0, - count: 2 - }) - - const videos = body.data - expect(videos[0].name).to.equal('video 2 server 2') - expect(videos[1].name).to.equal('video 1 server 2') - } - - { - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: '-name', - start: 1, - count: 1 - }) - - expect(body.data[0].name).to.equal('video 1 server 2') - } - }) - - it('Should manually add a redundancy and list it', async function () { - this.timeout(120000) - - const uuid = (await servers[1].videos.quickUpload({ name: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid - await waitJobs(servers) - const videoId = await servers[0].videos.getId({ uuid }) - - await commands[0].addVideo({ videoId }) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 15) - await waitJobs(servers) - - { - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: '-name', - start: 0, - count: 5 - }) - - const video = body.data[0] - - expect(video.name).to.equal('video 3 server 2') - expect(video.redundancies.files).to.have.lengthOf(4) - expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) - - const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) - - for (const r of redundancies) { - redundanciesToRemove.push(r.id) - - expect(r.strategy).to.equal('manual') - expect(r.fileUrl).to.exist - expect(r.createdAt).to.exist - expect(r.updatedAt).to.exist - expect(r.expiresOn).to.be.null - } - } - - const body = await commands[1].listVideos({ - target: 'my-videos', - sort: '-name', - start: 0, - count: 5 - }) - - const video = body.data[0] - expect(video.name).to.equal('video 3 server 2') - expect(video.redundancies.files).to.have.lengthOf(4) - expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) - - const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) - - for (const r of redundancies) { - expect(r.strategy).to.be.null - expect(r.fileUrl).to.exist - expect(r.createdAt).to.exist - expect(r.updatedAt).to.exist - expect(r.expiresOn).to.be.null - } - }) - - it('Should manually remove a redundancy and remove it from the list', async function () { - this.timeout(120000) - - for (const redundancyId of redundanciesToRemove) { - await commands[0].removeVideo({ redundancyId }) - } - - { - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: '-name', - start: 0, - count: 5 - }) - - const videos = body.data - - expect(videos).to.have.lengthOf(2) - - const video = videos[0] - expect(video.name).to.equal('video 2 server 2') - expect(video.redundancies.files).to.have.lengthOf(4) - expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) - - const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) - - redundanciesToRemove = redundancies.map(r => r.id) - } - }) - - it('Should remove another (auto) redundancy', async function () { - for (const redundancyId of redundanciesToRemove) { - await commands[0].removeVideo({ redundancyId }) - } - - const body = await commands[0].listVideos({ - target: 'remote-videos', - sort: '-name', - start: 0, - count: 5 - }) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('video 1 server 2') - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/redundancy/redundancy-constraints.ts b/server/tests/api/redundancy/redundancy-constraints.ts deleted file mode 100644 index c86573168..000000000 --- a/server/tests/api/redundancy/redundancy-constraints.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test redundancy constraints', function () { - let remoteServer: PeerTubeServer - let localServer: PeerTubeServer - let servers: PeerTubeServer[] - - const remoteServerConfig = { - redundancy: { - videos: { - check_interval: '1 second', - strategies: [ - { - strategy: 'recently-added', - min_lifetime: '1 hour', - size: '100MB', - min_views: 0 - } - ] - } - } - } - - async function uploadWrapper (videoName: string) { - // Wait for transcoding - const { id } = await localServer.videos.upload({ attributes: { name: 'to transcode', privacy: VideoPrivacy.PRIVATE } }) - await waitJobs([ localServer ]) - - // Update video to schedule a federation - await localServer.videos.update({ id, attributes: { name: videoName, privacy: VideoPrivacy.PUBLIC } }) - } - - async function getTotalRedundanciesLocalServer () { - const body = await localServer.redundancy.listVideos({ target: 'my-videos' }) - - return body.total - } - - async function getTotalRedundanciesRemoteServer () { - const body = await remoteServer.redundancy.listVideos({ target: 'remote-videos' }) - - return body.total - } - - before(async function () { - this.timeout(120000) - - { - remoteServer = await createSingleServer(1, remoteServerConfig) - } - - { - const config = { - remote_redundancy: { - videos: { - accept_from: 'nobody' - } - } - } - localServer = await createSingleServer(2, config) - } - - servers = [ remoteServer, localServer ] - - // Get the access tokens - await setAccessTokensToServers(servers) - - await localServer.videos.upload({ attributes: { name: 'video 1 server 2' } }) - - await waitJobs(servers) - - // Server 1 and server 2 follow each other - await remoteServer.follows.follow({ hosts: [ localServer.url ] }) - await waitJobs(servers) - await remoteServer.redundancy.updateRedundancy({ host: localServer.host, redundancyAllowed: true }) - - await waitJobs(servers) - }) - - it('Should have redundancy on server 1 but not on server 2 with a nobody filter', async function () { - this.timeout(120000) - - await waitJobs(servers) - await remoteServer.servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - { - const total = await getTotalRedundanciesRemoteServer() - expect(total).to.equal(1) - } - - { - const total = await getTotalRedundanciesLocalServer() - expect(total).to.equal(0) - } - }) - - it('Should have redundancy on server 1 and on server 2 with an anybody filter', async function () { - this.timeout(120000) - - const config = { - remote_redundancy: { - videos: { - accept_from: 'anybody' - } - } - } - await killallServers([ localServer ]) - await localServer.run(config) - - await uploadWrapper('video 2 server 2') - - await remoteServer.servers.waitUntilLog('Duplicated ', 10) - await waitJobs(servers) - - { - const total = await getTotalRedundanciesRemoteServer() - expect(total).to.equal(2) - } - - { - const total = await getTotalRedundanciesLocalServer() - expect(total).to.equal(1) - } - }) - - it('Should have redundancy on server 1 but not on server 2 with a followings filter', async function () { - this.timeout(120000) - - const config = { - remote_redundancy: { - videos: { - accept_from: 'followings' - } - } - } - await killallServers([ localServer ]) - await localServer.run(config) - - await uploadWrapper('video 3 server 2') - - await remoteServer.servers.waitUntilLog('Duplicated ', 15) - await waitJobs(servers) - - { - const total = await getTotalRedundanciesRemoteServer() - expect(total).to.equal(3) - } - - { - const total = await getTotalRedundanciesLocalServer() - expect(total).to.equal(1) - } - }) - - it('Should have redundancy on server 1 and on server 2 with followings filter now server 2 follows server 1', async function () { - this.timeout(120000) - - await localServer.follows.follow({ hosts: [ remoteServer.url ] }) - await waitJobs(servers) - - await uploadWrapper('video 4 server 2') - await remoteServer.servers.waitUntilLog('Duplicated ', 20) - await waitJobs(servers) - - { - const total = await getTotalRedundanciesRemoteServer() - expect(total).to.equal(4) - } - - { - const total = await getTotalRedundanciesLocalServer() - expect(total).to.equal(2) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts deleted file mode 100644 index 0c5c27225..000000000 --- a/server/tests/api/redundancy/redundancy.ts +++ /dev/null @@ -1,742 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readdir } from 'fs-extra' -import { decode as magnetUriDecode } from 'magnet-uri' -import { basename, join } from 'path' -import { checkSegmentHash, checkVideoFilesWereRemoved, saveVideoInServers } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { - HttpStatusCode, - VideoDetails, - VideoFile, - VideoPrivacy, - VideoRedundancyStrategy, - VideoRedundancyStrategyWithManual -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - makeRawRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -let servers: PeerTubeServer[] = [] -let video1Server2: VideoDetails - -async function checkMagnetWebseeds (file: VideoFile, baseWebseeds: string[], server: PeerTubeServer) { - const parsed = magnetUriDecode(file.magnetUri) - - for (const ws of baseWebseeds) { - const found = parsed.urlList.find(url => url === `${ws}${basename(file.fileUrl)}`) - expect(found, `Webseed ${ws} not found in ${file.magnetUri} on server ${server.url}`).to.not.be.undefined - } - - expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) - - for (const url of parsed.urlList) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - } -} - -async function createServers (strategy: VideoRedundancyStrategy | null, additionalParams: any = {}, withWebVideo = true) { - const strategies: any[] = [] - - if (strategy !== null) { - strategies.push( - { - min_lifetime: '1 hour', - strategy, - size: '400KB', - - ...additionalParams - } - ) - } - - const config = { - transcoding: { - web_videos: { - enabled: withWebVideo - }, - hls: { - enabled: true - } - }, - redundancy: { - videos: { - check_interval: '5 seconds', - strategies - } - } - } - - servers = await createMultipleServers(3, config) - - // Get the access tokens - await setAccessTokensToServers(servers) - - { - const { id } = await servers[1].videos.upload({ attributes: { name: 'video 1 server 2' } }) - video1Server2 = await servers[1].videos.get({ id }) - - await servers[1].views.simulateView({ id }) - } - - await waitJobs(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - // Server 1 and server 3 follow each other - await doubleFollow(servers[0], servers[2]) - // Server 2 and server 3 follow each other - await doubleFollow(servers[1], servers[2]) - - await waitJobs(servers) -} - -async function ensureSameFilenames (videoUUID: string) { - let webVideoFilenames: string[] - let hlsFilenames: string[] - - for (const server of servers) { - const video = await server.videos.getWithToken({ id: videoUUID }) - - // Ensure we use the same filenames that the origin - - const localWebVideoFilenames = video.files.map(f => basename(f.fileUrl)).sort() - const localHLSFilenames = video.streamingPlaylists[0].files.map(f => basename(f.fileUrl)).sort() - - if (webVideoFilenames) expect(webVideoFilenames).to.deep.equal(localWebVideoFilenames) - else webVideoFilenames = localWebVideoFilenames - - if (hlsFilenames) expect(hlsFilenames).to.deep.equal(localHLSFilenames) - else hlsFilenames = localHLSFilenames - } - - return { webVideoFilenames, hlsFilenames } -} - -async function check1WebSeed (videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2.uuid - - const webseeds = [ - `${servers[1].url}/static/web-videos/` - ] - - for (const server of servers) { - // With token to avoid issues with video follow constraints - const video = await server.videos.getWithToken({ id: videoUUID }) - - for (const f of video.files) { - await checkMagnetWebseeds(f, webseeds, server) - } - } - - await ensureSameFilenames(videoUUID) -} - -async function check2Webseeds (videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2.uuid - - const webseeds = [ - `${servers[0].url}/static/redundancy/`, - `${servers[1].url}/static/web-videos/` - ] - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - for (const file of video.files) { - await checkMagnetWebseeds(file, webseeds, server) - } - } - - const { webVideoFilenames } = await ensureSameFilenames(videoUUID) - - const directories = [ - servers[0].getDirectoryPath('redundancy'), - servers[1].getDirectoryPath('web-videos') - ] - - for (const directory of directories) { - const files = await readdir(directory) - expect(files).to.have.length.at.least(4) - - // Ensure we files exist on disk - expect(files.find(f => webVideoFilenames.includes(f))).to.exist - } -} - -async function check0PlaylistRedundancies (videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2.uuid - - for (const server of servers) { - // With token to avoid issues with video follow constraints - const video = await server.videos.getWithToken({ id: videoUUID }) - - expect(video.streamingPlaylists).to.be.an('array') - expect(video.streamingPlaylists).to.have.lengthOf(1) - expect(video.streamingPlaylists[0].redundancies).to.have.lengthOf(0) - } - - await ensureSameFilenames(videoUUID) -} - -async function check1PlaylistRedundancies (videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2.uuid - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.streamingPlaylists).to.have.lengthOf(1) - expect(video.streamingPlaylists[0].redundancies).to.have.lengthOf(1) - - const redundancy = video.streamingPlaylists[0].redundancies[0] - - expect(redundancy.baseUrl).to.equal(servers[0].url + '/static/redundancy/hls/' + videoUUID) - } - - const baseUrlPlaylist = servers[1].url + '/static/streaming-playlists/hls/' + videoUUID - const baseUrlSegment = servers[0].url + '/static/redundancy/hls/' + videoUUID - - const video = await servers[0].videos.get({ id: videoUUID }) - const hlsPlaylist = video.streamingPlaylists[0] - - for (const resolution of [ 240, 360, 480, 720 ]) { - await checkSegmentHash({ server: servers[1], baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist }) - } - - const { hlsFilenames } = await ensureSameFilenames(videoUUID) - - const directories = [ - servers[0].getDirectoryPath('redundancy/hls'), - servers[1].getDirectoryPath('streaming-playlists/hls') - ] - - for (const directory of directories) { - const files = await readdir(join(directory, videoUUID)) - expect(files).to.have.length.at.least(4) - - // Ensure we files exist on disk - expect(files.find(f => hlsFilenames.includes(f))).to.exist - } -} - -async function checkStatsGlobal (strategy: VideoRedundancyStrategyWithManual) { - let totalSize: number = null - let statsLength = 1 - - if (strategy !== 'manual') { - totalSize = 409600 - statsLength = 2 - } - - const data = await servers[0].stats.get() - expect(data.videosRedundancy).to.have.lengthOf(statsLength) - - const stat = data.videosRedundancy[0] - expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(totalSize) - - return stat -} - -async function checkStatsWith1Redundancy (strategy: VideoRedundancyStrategyWithManual, onlyHls = false) { - const stat = await checkStatsGlobal(strategy) - - expect(stat.totalUsed).to.be.at.least(1).and.below(409601) - expect(stat.totalVideoFiles).to.equal(onlyHls ? 4 : 8) - expect(stat.totalVideos).to.equal(1) -} - -async function checkStatsWithoutRedundancy (strategy: VideoRedundancyStrategyWithManual) { - const stat = await checkStatsGlobal(strategy) - - expect(stat.totalUsed).to.equal(0) - expect(stat.totalVideoFiles).to.equal(0) - expect(stat.totalVideos).to.equal(0) -} - -async function findServerFollows () { - const body = await servers[0].follows.getFollowings({ start: 0, count: 5, sort: '-createdAt' }) - const follows = body.data - const server2 = follows.find(f => f.following.host === `${servers[1].host}`) - const server3 = follows.find(f => f.following.host === `${servers[2].host}`) - - return { server2, server3 } -} - -async function enableRedundancyOnServer1 () { - await servers[0].redundancy.updateRedundancy({ host: servers[1].host, redundancyAllowed: true }) - - const { server2, server3 } = await findServerFollows() - - expect(server3).to.not.be.undefined - expect(server3.following.hostRedundancyAllowed).to.be.false - - expect(server2).to.not.be.undefined - expect(server2.following.hostRedundancyAllowed).to.be.true -} - -async function disableRedundancyOnServer1 () { - await servers[0].redundancy.updateRedundancy({ host: servers[1].host, redundancyAllowed: false }) - - const { server2, server3 } = await findServerFollows() - - expect(server3).to.not.be.undefined - expect(server3.following.hostRedundancyAllowed).to.be.false - - expect(server2).to.not.be.undefined - expect(server2.following.hostRedundancyAllowed).to.be.false -} - -describe('Test videos redundancy', function () { - - describe('With most-views strategy', function () { - const strategy = 'most-views' - - before(function () { - this.timeout(240000) - - return createServers(strategy) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed() - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy) - }) - - it('Should undo redundancy on server 1 and remove duplicated videos', async function () { - this.timeout(80000) - - await disableRedundancyOnServer1() - - await waitJobs(servers) - await wait(5000) - - await check1WebSeed() - await check0PlaylistRedundancies() - - await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true }) - }) - - after(async function () { - return cleanupTests(servers) - }) - }) - - describe('With trending strategy', function () { - const strategy = 'trending' - - before(function () { - this.timeout(240000) - - return createServers(strategy) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed() - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy) - }) - - it('Should unfollow server 3 and keep duplicated videos', async function () { - this.timeout(80000) - - await servers[0].follows.unfollow({ target: servers[2] }) - - await waitJobs(servers) - await wait(5000) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy) - }) - - it('Should unfollow server 2 and remove duplicated videos', async function () { - this.timeout(80000) - - await servers[0].follows.unfollow({ target: servers[1] }) - - await waitJobs(servers) - await wait(5000) - - await check1WebSeed() - await check0PlaylistRedundancies() - - await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true }) - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('With recently added strategy', function () { - const strategy = 'recently-added' - - before(function () { - this.timeout(240000) - - return createServers(strategy, { min_views: 3 }) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed() - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should still have 1 webseed on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await wait(15000) - await waitJobs(servers) - - await check1WebSeed() - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy(strategy) - }) - - it('Should view 2 times the first video to have > min_views config', async function () { - this.timeout(80000) - - await servers[0].views.simulateView({ id: video1Server2.uuid }) - await servers[2].views.simulateView({ id: video1Server2.uuid }) - - await wait(10000) - await waitJobs(servers) - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy) - }) - - it('Should remove the video and the redundancy files', async function () { - this.timeout(20000) - - await saveVideoInServers(servers, video1Server2.uuid) - await servers[1].videos.remove({ id: video1Server2.uuid }) - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails }) - } - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('With only HLS files', function () { - const strategy = 'recently-added' - - before(async function () { - this.timeout(240000) - - await createServers(strategy, { min_views: 3 }, false) - }) - - it('Should have 0 playlist redundancy on the first video', async function () { - await check1WebSeed() - await check0PlaylistRedundancies() - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should still have 0 redundancy on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await wait(15000) - await waitJobs(servers) - - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy(strategy) - }) - - it('Should have 1 redundancy on the first video', async function () { - this.timeout(160000) - - await servers[0].views.simulateView({ id: video1Server2.uuid }) - await servers[2].views.simulateView({ id: video1Server2.uuid }) - - await wait(10000) - await waitJobs(servers) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 1) - await waitJobs(servers) - - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy, true) - }) - - it('Should remove the video and the redundancy files', async function () { - this.timeout(20000) - - await saveVideoInServers(servers, video1Server2.uuid) - await servers[1].videos.remove({ id: video1Server2.uuid }) - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails }) - } - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('With manual strategy', function () { - before(function () { - this.timeout(240000) - - return createServers(null) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed() - await check0PlaylistRedundancies() - await checkStatsWithoutRedundancy('manual') - }) - - it('Should create a redundancy on first video', async function () { - await servers[0].redundancy.addVideo({ videoId: video1Server2.id }) - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(80000) - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy('manual') - }) - - it('Should manually remove redundancies on server 1 and remove duplicated videos', async function () { - this.timeout(80000) - - const body = await servers[0].redundancy.listVideos({ target: 'remote-videos' }) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - - const video = videos[0] - - for (const r of video.redundancies.files.concat(video.redundancies.streamingPlaylists)) { - await servers[0].redundancy.removeVideo({ redundancyId: r.id }) - } - - await waitJobs(servers) - await wait(5000) - - await check1WebSeed() - await check0PlaylistRedundancies() - - await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true }) - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('Test expiration', function () { - const strategy = 'recently-added' - - async function checkContains (servers: PeerTubeServer[], str: string) { - for (const server of servers) { - const video = await server.videos.get({ id: video1Server2.uuid }) - - for (const f of video.files) { - expect(f.magnetUri).to.contain(str) - } - } - } - - async function checkNotContains (servers: PeerTubeServer[], str: string) { - for (const server of servers) { - const video = await server.videos.get({ id: video1Server2.uuid }) - - for (const f of video.files) { - expect(f.magnetUri).to.not.contain(str) - } - } - } - - before(async function () { - this.timeout(240000) - - await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) - - await enableRedundancyOnServer1() - }) - - it('Should still have 2 webseeds after 10 seconds', async function () { - this.timeout(80000) - - await wait(10000) - - try { - await checkContains(servers, 'http%3A%2F%2F' + servers[0].hostname + '%3A' + servers[0].port) - } catch { - // Maybe a server deleted a redundancy in the scheduler - await wait(2000) - - await checkContains(servers, 'http%3A%2F%2F' + servers[0].hostname + '%3A' + servers[0].port) - } - }) - - it('Should stop server 1 and expire video redundancy', async function () { - this.timeout(80000) - - await killallServers([ servers[0] ]) - - await wait(15000) - - await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2F' + servers[0].port + '%3A' + servers[0].port) - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('Test file replacement', function () { - let video2Server2UUID: string - const strategy = 'recently-added' - - before(async function () { - this.timeout(240000) - - await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) - - await enableRedundancyOnServer1() - - await waitJobs(servers) - await servers[0].servers.waitUntilLog('Duplicated ', 5) - await waitJobs(servers) - - await check2Webseeds() - await check1PlaylistRedundancies() - await checkStatsWith1Redundancy(strategy) - - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 2 server 2', privacy: VideoPrivacy.PRIVATE } }) - video2Server2UUID = uuid - - // Wait transcoding before federation - await waitJobs(servers) - - await servers[1].videos.update({ id: video2Server2UUID, attributes: { privacy: VideoPrivacy.PUBLIC } }) - }) - - it('Should cache video 2 webseeds on the first video', async function () { - this.timeout(240000) - - await waitJobs(servers) - - let checked = false - - while (checked === false) { - await wait(1000) - - try { - await check1WebSeed() - await check0PlaylistRedundancies() - - await check2Webseeds(video2Server2UUID) - await check1PlaylistRedundancies(video2Server2UUID) - - checked = true - } catch { - checked = false - } - } - }) - - it('Should disable strategy and remove redundancies', async function () { - this.timeout(80000) - - await waitJobs(servers) - - await killallServers([ servers[0] ]) - await servers[0].run({ - redundancy: { - videos: { - check_interval: '1 second', - strategies: [] - } - } - }) - - await waitJobs(servers) - - await checkVideoFilesWereRemoved({ server: servers[0], video: video1Server2, onlyVideoFiles: true }) - }) - - after(async function () { - await cleanupTests(servers) - }) - }) -}) diff --git a/server/tests/api/runners/index.ts b/server/tests/api/runners/index.ts deleted file mode 100644 index 642a3a96d..000000000 --- a/server/tests/api/runners/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './runner-common' -export * from './runner-live-transcoding' -export * from './runner-socket' -export * from './runner-studio-transcoding' -export * from './runner-vod-transcoding' diff --git a/server/tests/api/runners/runner-common.ts b/server/tests/api/runners/runner-common.ts deleted file mode 100644 index 9b2eb8b27..000000000 --- a/server/tests/api/runners/runner-common.ts +++ /dev/null @@ -1,743 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { - HttpStatusCode, - Runner, - RunnerJob, - RunnerJobAdmin, - RunnerJobState, - RunnerJobVODWebVideoTranscodingPayload, - RunnerRegistrationToken -} from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test runner common actions', function () { - let server: PeerTubeServer - let registrationToken: string - let runnerToken: string - let jobMaxPriority: string - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1, { - remote_runners: { - stalled_jobs: { - vod: '5 seconds' - } - } - }) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableTranscoding({ hls: true, webVideo: true }) - await server.config.enableRemoteTranscoding() - }) - - describe('Managing runner registration tokens', function () { - let base: RunnerRegistrationToken[] - let registrationTokenToDelete: RunnerRegistrationToken - - it('Should have a default registration token', async function () { - const { total, data } = await server.runnerRegistrationTokens.list() - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const token = data[0] - expect(token.id).to.exist - expect(token.createdAt).to.exist - expect(token.updatedAt).to.exist - expect(token.registeredRunnersCount).to.equal(0) - expect(token.registrationToken).to.exist - }) - - it('Should create other registration tokens', async function () { - await server.runnerRegistrationTokens.generate() - await server.runnerRegistrationTokens.generate() - - const { total, data } = await server.runnerRegistrationTokens.list() - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - }) - - it('Should list registration tokens', async function () { - { - const { total, data } = await server.runnerRegistrationTokens.list({ sort: 'createdAt' }) - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - expect(new Date(data[0].createdAt)).to.be.below(new Date(data[1].createdAt)) - expect(new Date(data[1].createdAt)).to.be.below(new Date(data[2].createdAt)) - - base = data - - registrationTokenToDelete = data[0] - registrationToken = data[1].registrationToken - } - - { - const { total, data } = await server.runnerRegistrationTokens.list({ sort: '-createdAt', start: 2, count: 1 }) - expect(total).to.equal(3) - expect(data).to.have.lengthOf(1) - expect(data[0].registrationToken).to.equal(base[0].registrationToken) - } - }) - - it('Should have appropriate registeredRunnersCount for registration tokens', async function () { - await server.runners.register({ name: 'to delete 1', registrationToken: registrationTokenToDelete.registrationToken }) - await server.runners.register({ name: 'to delete 2', registrationToken: registrationTokenToDelete.registrationToken }) - - const { data } = await server.runnerRegistrationTokens.list() - - for (const d of data) { - if (d.registrationToken === registrationTokenToDelete.registrationToken) { - expect(d.registeredRunnersCount).to.equal(2) - } else { - expect(d.registeredRunnersCount).to.equal(0) - } - } - - const { data: runners } = await server.runners.list() - expect(runners).to.have.lengthOf(2) - }) - - it('Should delete a registration token', async function () { - await server.runnerRegistrationTokens.delete({ id: registrationTokenToDelete.id }) - - const { total, data } = await server.runnerRegistrationTokens.list({ sort: 'createdAt' }) - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const d of data) { - expect(d.registeredRunnersCount).to.equal(0) - expect(d.registrationToken).to.not.equal(registrationTokenToDelete.registrationToken) - } - }) - - it('Should have removed runners of this registration token', async function () { - const { data: runners } = await server.runners.list() - expect(runners).to.have.lengthOf(0) - }) - }) - - describe('Managing runners', function () { - let toDelete: Runner - - it('Should not have runners available', async function () { - const { total, data } = await server.runners.list() - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - }) - - it('Should register runners', async function () { - const now = new Date() - - const result = await server.runners.register({ - name: 'runner 1', - description: 'my super runner 1', - registrationToken - }) - expect(result.runnerToken).to.exist - runnerToken = result.runnerToken - - await server.runners.register({ - name: 'runner 2', - registrationToken - }) - - const { total, data } = await server.runners.list({ sort: 'createdAt' }) - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const d of data) { - expect(d.id).to.exist - expect(d.createdAt).to.exist - expect(d.updatedAt).to.exist - expect(new Date(d.createdAt)).to.be.above(now) - expect(new Date(d.updatedAt)).to.be.above(now) - expect(new Date(d.lastContact)).to.be.above(now) - expect(d.ip).to.exist - } - - expect(data[0].name).to.equal('runner 1') - expect(data[0].description).to.equal('my super runner 1') - - expect(data[1].name).to.equal('runner 2') - expect(data[1].description).to.be.null - - toDelete = data[1] - }) - - it('Should list runners', async function () { - const { total, data } = await server.runners.list({ sort: '-createdAt', start: 1, count: 1 }) - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('runner 1') - }) - - it('Should delete a runner', async function () { - await server.runners.delete({ id: toDelete.id }) - - const { total, data } = await server.runners.list() - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('runner 1') - }) - - it('Should unregister a runner', async function () { - const registered = await server.runners.autoRegisterRunner() - - { - const { total, data } = await server.runners.list() - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - } - - await server.runners.unregister({ runnerToken: registered }) - - { - const { total, data } = await server.runners.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('runner 1') - } - }) - }) - - describe('Managing runner jobs', function () { - let jobUUID: string - let jobToken: string - let lastRunnerContact: Date - let failedJob: RunnerJob - - async function checkMainJobState ( - mainJobState: RunnerJobState, - otherJobStates: RunnerJobState[] = [ RunnerJobState.PENDING, RunnerJobState.WAITING_FOR_PARENT_JOB ] - ) { - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - for (const job of data) { - if (job.uuid === jobUUID) { - expect(job.state.id).to.equal(mainJobState) - } else { - expect(otherJobStates).to.include(job.state.id) - } - } - } - - function getMainJob () { - return server.runnerJobs.getJob({ uuid: jobUUID }) - } - - describe('List jobs', function () { - - it('Should not have jobs', async function () { - const { total, data } = await server.runnerJobs.list() - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - }) - - it('Should upload a video and have available jobs', async function () { - await server.videos.quickUpload({ name: 'to transcode' }) - await waitJobs([ server ]) - - const { total, data } = await server.runnerJobs.list() - - expect(data).to.have.lengthOf(10) - expect(total).to.equal(10) - - for (const job of data) { - expect(job.startedAt).to.not.exist - expect(job.finishedAt).to.not.exist - expect(job.payload).to.exist - expect(job.privatePayload).to.exist - } - - const hlsJobs = data.filter(d => d.type === 'vod-hls-transcoding') - const webVideoJobs = data.filter(d => d.type === 'vod-web-video-transcoding') - - expect(hlsJobs).to.have.lengthOf(5) - expect(webVideoJobs).to.have.lengthOf(5) - - const pendingJobs = data.filter(d => d.state.id === RunnerJobState.PENDING) - const waitingJobs = data.filter(d => d.state.id === RunnerJobState.WAITING_FOR_PARENT_JOB) - - expect(pendingJobs).to.have.lengthOf(1) - expect(waitingJobs).to.have.lengthOf(9) - }) - - it('Should upload another video and list/sort jobs', async function () { - await server.videos.quickUpload({ name: 'to transcode 2' }) - await waitJobs([ server ]) - - { - const { total, data } = await server.runnerJobs.list({ start: 0, count: 30 }) - - expect(data).to.have.lengthOf(20) - expect(total).to.equal(20) - - jobUUID = data[16].uuid - } - - { - const { total, data } = await server.runnerJobs.list({ start: 3, count: 1, sort: 'createdAt' }) - expect(total).to.equal(20) - - expect(data).to.have.lengthOf(1) - expect(data[0].uuid).to.equal(jobUUID) - } - - { - let previousPriority = Infinity - const { total, data } = await server.runnerJobs.list({ start: 0, count: 100, sort: '-priority' }) - expect(total).to.equal(20) - - for (const job of data) { - expect(job.priority).to.be.at.most(previousPriority) - previousPriority = job.priority - - if (job.state.id === RunnerJobState.PENDING) { - jobMaxPriority = job.uuid - } - } - } - }) - - it('Should search jobs', async function () { - { - const { total, data } = await server.runnerJobs.list({ search: jobUUID }) - - expect(data).to.have.lengthOf(1) - expect(total).to.equal(1) - - expect(data[0].uuid).to.equal(jobUUID) - } - - { - const { total, data } = await server.runnerJobs.list({ search: 'toto' }) - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - } - - { - const { total, data } = await server.runnerJobs.list({ search: 'hls' }) - - expect(data).to.not.have.lengthOf(0) - expect(total).to.not.equal(0) - - for (const job of data) { - expect(job.type).to.include('hls') - } - } - }) - - it('Should filter jobs', async function () { - { - const { total, data } = await server.runnerJobs.list({ stateOneOf: [ RunnerJobState.WAITING_FOR_PARENT_JOB ] }) - - expect(data).to.not.have.lengthOf(0) - expect(total).to.not.equal(0) - - for (const job of data) { - expect(job.state.label).to.equal('Waiting for parent job to finish') - } - } - - { - const { total, data } = await server.runnerJobs.list({ stateOneOf: [ RunnerJobState.COMPLETED ] }) - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - } - }) - }) - - describe('Accept/update/abort/process a job', function () { - - it('Should request available jobs', async function () { - lastRunnerContact = new Date() - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - - // Only optimize jobs are available - expect(availableJobs).to.have.lengthOf(2) - - for (const job of availableJobs) { - expect(job.uuid).to.exist - expect(job.payload.input).to.exist - expect((job.payload as RunnerJobVODWebVideoTranscodingPayload).output).to.exist - - expect((job as RunnerJobAdmin).privatePayload).to.not.exist - } - - const hlsJobs = availableJobs.filter(d => d.type === 'vod-hls-transcoding') - const webVideoJobs = availableJobs.filter(d => d.type === 'vod-web-video-transcoding') - - expect(hlsJobs).to.have.lengthOf(0) - expect(webVideoJobs).to.have.lengthOf(2) - - jobUUID = webVideoJobs[0].uuid - }) - - it('Should have sorted available jobs by priority', async function () { - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - - expect(availableJobs[0].uuid).to.equal(jobMaxPriority) - }) - - it('Should have last runner contact updated', async function () { - await wait(1000) - - const { data } = await server.runners.list({ sort: 'createdAt' }) - expect(new Date(data[0].lastContact)).to.be.above(lastRunnerContact) - }) - - it('Should accept a job', async function () { - const startedAt = new Date() - - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const checkProcessingJob = (job: RunnerJob & { jobToken?: string }, fromAccept: boolean) => { - expect(job.uuid).to.equal(jobUUID) - - expect(job.type).to.equal('vod-web-video-transcoding') - expect(job.state.label).to.equal('Processing') - expect(job.state.id).to.equal(RunnerJobState.PROCESSING) - - expect(job.runner).to.exist - expect(job.runner.name).to.equal('runner 1') - expect(job.runner.description).to.equal('my super runner 1') - - expect(job.progress).to.be.null - - expect(job.startedAt).to.exist - expect(new Date(job.startedAt)).to.be.above(startedAt) - - expect(job.finishedAt).to.not.exist - - expect(job.failures).to.equal(0) - - expect(job.payload).to.exist - - if (fromAccept) { - expect(job.jobToken).to.exist - expect((job as RunnerJobAdmin).privatePayload).to.not.exist - } else { - expect(job.jobToken).to.not.exist - expect((job as RunnerJobAdmin).privatePayload).to.exist - } - } - - checkProcessingJob(job, true) - - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - const processingJob = data.find(j => j.uuid === jobUUID) - checkProcessingJob(processingJob, false) - - await checkMainJobState(RunnerJobState.PROCESSING) - }) - - it('Should update a job', async function () { - await server.runnerJobs.update({ runnerToken, jobUUID, jobToken, progress: 53 }) - - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - for (const job of data) { - if (job.state.id === RunnerJobState.PROCESSING) { - expect(job.progress).to.equal(53) - } else { - expect(job.progress).to.be.null - } - } - }) - - it('Should abort a job', async function () { - await server.runnerJobs.abort({ runnerToken, jobUUID, jobToken, reason: 'for tests' }) - - await checkMainJobState(RunnerJobState.PENDING) - - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - for (const job of data) { - expect(job.progress).to.be.null - } - }) - - it('Should accept the same job again and post a success', async function () { - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - expect(availableJobs.find(j => j.uuid === jobUUID)).to.exist - - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - await checkMainJobState(RunnerJobState.PROCESSING) - - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - for (const job of data) { - expect(job.progress).to.be.null - } - - const payload = { - videoFile: 'video_short.mp4' - } - - await server.runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - }) - - it('Should not have available jobs anymore', async function () { - await checkMainJobState(RunnerJobState.COMPLETED) - - const job = await getMainJob() - expect(job.finishedAt).to.exist - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - expect(availableJobs.find(j => j.uuid === jobUUID)).to.not.exist - }) - }) - - describe('Error job', function () { - - it('Should accept another job and post an error', async function () { - await server.runnerJobs.cancelAllJobs() - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - jobUUID = availableJobs[0].uuid - - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - await server.runnerJobs.error({ runnerToken, jobUUID, jobToken, message: 'Error' }) - }) - - it('Should have job failures increased', async function () { - const job = await getMainJob() - expect(job.state.id).to.equal(RunnerJobState.PENDING) - expect(job.failures).to.equal(1) - expect(job.error).to.be.null - expect(job.progress).to.be.null - expect(job.finishedAt).to.not.exist - }) - - it('Should error a job when job attempts is too big', async function () { - for (let i = 0; i < 4; i++) { - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - await server.runnerJobs.error({ runnerToken, jobUUID, jobToken, message: 'Error ' + i }) - } - - const job = await getMainJob() - expect(job.failures).to.equal(5) - expect(job.state.id).to.equal(RunnerJobState.ERRORED) - expect(job.state.label).to.equal('Errored') - expect(job.error).to.equal('Error 3') - expect(job.progress).to.be.null - expect(job.finishedAt).to.exist - - failedJob = job - }) - - it('Should have failed children jobs too', async function () { - const { data } = await server.runnerJobs.list({ count: 50, sort: '-updatedAt' }) - - const children = data.filter(j => j.parent?.uuid === failedJob.uuid) - expect(children).to.have.lengthOf(9) - - for (const child of children) { - expect(child.parent.uuid).to.equal(failedJob.uuid) - expect(child.parent.type).to.equal(failedJob.type) - expect(child.parent.state.id).to.equal(failedJob.state.id) - expect(child.parent.state.label).to.equal(failedJob.state.label) - - expect(child.state.id).to.equal(RunnerJobState.PARENT_ERRORED) - expect(child.state.label).to.equal('Parent job failed') - } - }) - }) - - describe('Cancel', function () { - - it('Should cancel a pending job', async function () { - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - { - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - const pendingJob = data.find(j => j.state.id === RunnerJobState.PENDING) - jobUUID = pendingJob.uuid - - await server.runnerJobs.cancelByAdmin({ jobUUID }) - } - - { - const job = await getMainJob() - expect(job.state.id).to.equal(RunnerJobState.CANCELLED) - expect(job.state.label).to.equal('Cancelled') - } - - { - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - const children = data.filter(j => j.parent?.uuid === jobUUID) - expect(children).to.have.lengthOf(9) - - for (const child of children) { - expect(child.state.id).to.equal(RunnerJobState.PARENT_CANCELLED) - } - } - }) - - it('Should cancel an already accepted job and skip success/error', async function () { - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - jobUUID = availableJobs[0].uuid - - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - await server.runnerJobs.cancelByAdmin({ jobUUID }) - - await server.runnerJobs.abort({ runnerToken, jobUUID, jobToken, reason: 'aborted', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Remove', function () { - - it('Should remove a pending job', async function () { - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - { - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - const pendingJob = data.find(j => j.state.id === RunnerJobState.PENDING) - jobUUID = pendingJob.uuid - - await server.runnerJobs.deleteByAdmin({ jobUUID }) - } - - { - const { data } = await server.runnerJobs.list({ count: 10, sort: '-updatedAt' }) - - const parent = data.find(j => j.uuid === jobUUID) - expect(parent).to.not.exist - - const children = data.filter(j => j.parent?.uuid === jobUUID) - expect(children).to.have.lengthOf(0) - } - }) - }) - - describe('Stalled jobs', function () { - - it('Should abort stalled jobs', async function () { - this.timeout(60000) - - await server.videos.quickUpload({ name: 'video' }) - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { job: job1 } = await server.runnerJobs.autoAccept({ runnerToken }) - const { job: stalledJob } = await server.runnerJobs.autoAccept({ runnerToken }) - - for (let i = 0; i < 6; i++) { - await wait(2000) - - await server.runnerJobs.update({ runnerToken, jobToken: job1.jobToken, jobUUID: job1.uuid }) - } - - const refreshedJob1 = await server.runnerJobs.getJob({ uuid: job1.uuid }) - const refreshedStalledJob = await server.runnerJobs.getJob({ uuid: stalledJob.uuid }) - - expect(refreshedJob1.state.id).to.equal(RunnerJobState.PROCESSING) - expect(refreshedStalledJob.state.id).to.equal(RunnerJobState.PENDING) - }) - }) - - describe('Rate limit', function () { - - before(async function () { - this.timeout(60000) - - await server.kill() - - await server.run({ - rates_limit: { - api: { - max: 10 - } - } - }) - }) - - it('Should rate limit an unknown runner, but not a registered one', async function () { - this.timeout(60000) - - await server.videos.quickUpload({ name: 'video' }) - await waitJobs([ server ]) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken }) - - for (let i = 0; i < 20; i++) { - try { - await server.runnerJobs.request({ runnerToken }) - await server.runnerJobs.update({ runnerToken, jobToken: job.jobToken, jobUUID: job.uuid }) - } catch {} - } - - // Invalid - { - await server.runnerJobs.request({ runnerToken: 'toto', expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - await server.runnerJobs.update({ - runnerToken: 'toto', - jobToken: job.jobToken, - jobUUID: job.uuid, - expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 - }) - } - - // Not provided - { - await server.runnerJobs.request({ runnerToken: undefined, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - await server.runnerJobs.update({ - runnerToken: undefined, - jobToken: job.jobToken, - jobUUID: job.uuid, - expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 - }) - } - - // Registered - { - await server.runnerJobs.request({ runnerToken }) - await server.runnerJobs.update({ runnerToken, jobToken: job.jobToken, jobUUID: job.uuid }) - } - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/runners/runner-live-transcoding.ts b/server/tests/api/runners/runner-live-transcoding.ts deleted file mode 100644 index b11d54039..000000000 --- a/server/tests/api/runners/runner-live-transcoding.ts +++ /dev/null @@ -1,330 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FfmpegCommand } from 'fluent-ffmpeg' -import { readFile } from 'fs-extra' -import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' -import { - HttpStatusCode, - LiveRTMPHLSTranscodingUpdatePayload, - LiveVideo, - LiveVideoError, - RunnerJob, - RunnerJobLiveRTMPHLSTranscodingPayload, - Video, - VideoPrivacy, - VideoState -} from '@shared/models' -import { - cleanupTests, - createSingleServer, - makeRawRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - testFfmpegStreamError, - waitJobs -} from '@shared/server-commands' - -describe('Test runner live transcoding', function () { - let server: PeerTubeServer - let runnerToken: string - let baseUrl: string - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableRemoteTranscoding() - await server.config.enableTranscoding() - runnerToken = await server.runners.autoRegisterRunner() - - baseUrl = server.url + '/static/streaming-playlists/hls' - }) - - describe('Without transcoding enabled', function () { - - before(async function () { - await server.config.enableLive({ - allowReplay: false, - resolutions: 'min', - transcoding: false - }) - }) - - it('Should not have available jobs', async function () { - this.timeout(120000) - - const { live, video } = await server.live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await server.live.waitUntilPublished({ videoId: video.id }) - - await waitJobs([ server ]) - - const { availableJobs } = await server.runnerJobs.requestLive({ runnerToken }) - expect(availableJobs).to.have.lengthOf(0) - - await stopFfmpeg(ffmpegCommand) - }) - }) - - describe('With transcoding enabled on classic live', function () { - let live: LiveVideo - let video: Video - let ffmpegCommand: FfmpegCommand - let jobUUID: string - let acceptedJob: RunnerJob & { jobToken: string } - - async function testPlaylistFile (fixture: string, expected: string) { - const text = await server.streamingPlaylists.get({ url: `${baseUrl}/${video.uuid}/${fixture}` }) - expect(await readFile(buildAbsoluteFixturePath(expected), 'utf-8')).to.equal(text) - - } - - async function testTSFile (fixture: string, expected: string) { - const { body } = await makeRawRequest({ url: `${baseUrl}/${video.uuid}/${fixture}`, expectedStatus: HttpStatusCode.OK_200 }) - expect(await readFile(buildAbsoluteFixturePath(expected))).to.deep.equal(body) - } - - before(async function () { - await server.config.enableLive({ - allowReplay: true, - resolutions: 'max', - transcoding: true - }) - }) - - it('Should publish a a live and have available jobs', async function () { - this.timeout(120000) - - const data = await server.live.quickCreate({ permanentLive: false, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) - live = data.live - video = data.video - - ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await waitJobs([ server ]) - - const job = await server.runnerJobs.requestLiveJob(runnerToken) - jobUUID = job.uuid - - expect(job.type).to.equal('live-rtmp-hls-transcoding') - expect(job.payload.input.rtmpUrl).to.exist - - expect(job.payload.output.toTranscode).to.have.lengthOf(5) - - for (const { resolution, fps } of job.payload.output.toTranscode) { - expect([ 720, 480, 360, 240, 144 ]).to.contain(resolution) - - expect(fps).to.be.above(25) - expect(fps).to.be.below(70) - } - }) - - it('Should update the live with a new chunk', async function () { - this.timeout(120000) - - const { job } = await server.runnerJobs.accept({ jobUUID, runnerToken }) - acceptedJob = job - - { - const payload: LiveRTMPHLSTranscodingUpdatePayload = { - masterPlaylistFile: 'live/master.m3u8', - resolutionPlaylistFile: 'live/0.m3u8', - resolutionPlaylistFilename: '0.m3u8', - type: 'add-chunk', - videoChunkFile: 'live/0-000067.ts', - videoChunkFilename: '0-000067.ts' - } - await server.runnerJobs.update({ jobUUID, runnerToken, jobToken: job.jobToken, payload, progress: 50 }) - - const updatedJob = await server.runnerJobs.getJob({ uuid: job.uuid }) - expect(updatedJob.progress).to.equal(50) - } - - { - const payload: LiveRTMPHLSTranscodingUpdatePayload = { - resolutionPlaylistFile: 'live/1.m3u8', - resolutionPlaylistFilename: '1.m3u8', - type: 'add-chunk', - videoChunkFile: 'live/1-000068.ts', - videoChunkFilename: '1-000068.ts' - } - await server.runnerJobs.update({ jobUUID, runnerToken, jobToken: job.jobToken, payload }) - } - - await wait(1000) - - await testPlaylistFile('master.m3u8', 'live/master.m3u8') - await testPlaylistFile('0.m3u8', 'live/0.m3u8') - await testPlaylistFile('1.m3u8', 'live/1.m3u8') - - await testTSFile('0-000067.ts', 'live/0-000067.ts') - await testTSFile('1-000068.ts', 'live/1-000068.ts') - }) - - it('Should replace existing m3u8 on update', async function () { - this.timeout(120000) - - const payload: LiveRTMPHLSTranscodingUpdatePayload = { - masterPlaylistFile: 'live/1.m3u8', - resolutionPlaylistFilename: '0.m3u8', - resolutionPlaylistFile: 'live/1.m3u8', - type: 'add-chunk', - videoChunkFile: 'live/1-000069.ts', - videoChunkFilename: '1-000068.ts' - } - await server.runnerJobs.update({ jobUUID, runnerToken, jobToken: acceptedJob.jobToken, payload }) - await wait(1000) - - await testPlaylistFile('master.m3u8', 'live/1.m3u8') - await testPlaylistFile('0.m3u8', 'live/1.m3u8') - await testTSFile('1-000068.ts', 'live/1-000069.ts') - }) - - it('Should update the live with removed chunks', async function () { - this.timeout(120000) - - const payload: LiveRTMPHLSTranscodingUpdatePayload = { - resolutionPlaylistFile: 'live/0.m3u8', - resolutionPlaylistFilename: '0.m3u8', - type: 'remove-chunk', - videoChunkFilename: '1-000068.ts' - } - await server.runnerJobs.update({ jobUUID, runnerToken, jobToken: acceptedJob.jobToken, payload }) - - await wait(1000) - - await server.streamingPlaylists.get({ url: `${baseUrl}/${video.uuid}/master.m3u8` }) - await server.streamingPlaylists.get({ url: `${baseUrl}/${video.uuid}/0.m3u8` }) - await server.streamingPlaylists.get({ url: `${baseUrl}/${video.uuid}/1.m3u8` }) - await makeRawRequest({ url: `${baseUrl}/${video.uuid}/0-000067.ts`, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: `${baseUrl}/${video.uuid}/1-000068.ts`, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should complete the live and save the replay', async function () { - this.timeout(120000) - - for (const segment of [ '0-000069.ts', '0-000070.ts' ]) { - const payload: LiveRTMPHLSTranscodingUpdatePayload = { - masterPlaylistFile: 'live/master.m3u8', - resolutionPlaylistFilename: '0.m3u8', - resolutionPlaylistFile: 'live/0.m3u8', - type: 'add-chunk', - videoChunkFile: 'live/' + segment, - videoChunkFilename: segment - } - await server.runnerJobs.update({ jobUUID, runnerToken, jobToken: acceptedJob.jobToken, payload }) - - await wait(1000) - } - - await waitJobs([ server ]) - - { - const { state } = await server.videos.get({ id: video.uuid }) - expect(state.id).to.equal(VideoState.PUBLISHED) - } - - await stopFfmpeg(ffmpegCommand) - - await server.runnerJobs.success({ jobUUID, runnerToken, jobToken: acceptedJob.jobToken, payload: {} }) - - await wait(1500) - await waitJobs([ server ]) - - { - const { state } = await server.videos.get({ id: video.uuid }) - expect(state.id).to.equal(VideoState.LIVE_ENDED) - - const session = await server.live.findLatestSession({ videoId: video.uuid }) - expect(session.error).to.be.null - } - }) - }) - - describe('With transcoding enabled on cancelled/aborted/errored live', function () { - let live: LiveVideo - let video: Video - let ffmpegCommand: FfmpegCommand - - async function prepare () { - ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await server.runnerJobs.requestLiveJob(runnerToken) - - const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'live-rtmp-hls-transcoding' }) - - return job - } - - async function checkSessionError (error: LiveVideoError) { - await wait(1500) - await waitJobs([ server ]) - - const session = await server.live.findLatestSession({ videoId: video.uuid }) - expect(session.error).to.equal(error) - } - - before(async function () { - await server.config.enableLive({ - allowReplay: true, - resolutions: 'max', - transcoding: true - }) - - const data = await server.live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) - live = data.live - video = data.video - }) - - it('Should abort a running live', async function () { - this.timeout(120000) - - const job = await prepare() - - await Promise.all([ - server.runnerJobs.abort({ jobUUID: job.uuid, runnerToken, jobToken: job.jobToken, reason: 'abort' }), - testFfmpegStreamError(ffmpegCommand, true) - ]) - - // Abort is not supported - await checkSessionError(LiveVideoError.RUNNER_JOB_ERROR) - }) - - it('Should cancel a running live', async function () { - this.timeout(120000) - - const job = await prepare() - - await Promise.all([ - server.runnerJobs.cancelByAdmin({ jobUUID: job.uuid }), - testFfmpegStreamError(ffmpegCommand, true) - ]) - - await checkSessionError(LiveVideoError.RUNNER_JOB_CANCEL) - }) - - it('Should error a running live', async function () { - this.timeout(120000) - - const job = await prepare() - - await Promise.all([ - server.runnerJobs.error({ jobUUID: job.uuid, runnerToken, jobToken: job.jobToken, message: 'error' }), - testFfmpegStreamError(ffmpegCommand, true) - ]) - - await checkSessionError(LiveVideoError.RUNNER_JOB_ERROR) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/runners/runner-socket.ts b/server/tests/api/runners/runner-socket.ts deleted file mode 100644 index 215164e48..000000000 --- a/server/tests/api/runners/runner-socket.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test runner socket', function () { - let server: PeerTubeServer - let runnerToken: string - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableTranscoding({ hls: true, webVideo: true }) - await server.config.enableRemoteTranscoding() - runnerToken = await server.runners.autoRegisterRunner() - }) - - it('Should throw an error without runner token', function (done) { - const localSocket = server.socketIO.getRunnersSocket({ runnerToken: null }) - localSocket.on('connect_error', err => { - expect(err.message).to.contain('No runner token provided') - done() - }) - }) - - it('Should throw an error with a bad runner token', function (done) { - const localSocket = server.socketIO.getRunnersSocket({ runnerToken: 'ergag' }) - localSocket.on('connect_error', err => { - expect(err.message).to.contain('Invalid runner token') - done() - }) - }) - - it('Should not send ping if there is no available jobs', async function () { - let pings = 0 - const localSocket = server.socketIO.getRunnersSocket({ runnerToken }) - localSocket.on('available-jobs', () => pings++) - - expect(pings).to.equal(0) - }) - - it('Should send a ping on available job', async function () { - let pings = 0 - const localSocket = server.socketIO.getRunnersSocket({ runnerToken }) - localSocket.on('available-jobs', () => pings++) - - await server.videos.quickUpload({ name: 'video1' }) - await waitJobs([ server ]) - - // eslint-disable-next-line no-unmodified-loop-condition - while (pings !== 1) { - await wait(500) - } - - await server.videos.quickUpload({ name: 'video2' }) - await waitJobs([ server ]) - - // eslint-disable-next-line no-unmodified-loop-condition - while ((pings as number) !== 2) { - await wait(500) - } - - await server.runnerJobs.cancelAllJobs() - }) - - it('Should send a ping when a child is ready', async function () { - let pings = 0 - const localSocket = server.socketIO.getRunnersSocket({ runnerToken }) - localSocket.on('available-jobs', () => pings++) - - await server.videos.quickUpload({ name: 'video3' }) - await waitJobs([ server ]) - - // eslint-disable-next-line no-unmodified-loop-condition - while (pings !== 1) { - await wait(500) - } - - await server.runnerJobs.autoProcessWebVideoJob(runnerToken) - await waitJobs([ server ]) - - // eslint-disable-next-line no-unmodified-loop-condition - while ((pings as number) !== 2) { - await wait(500) - } - }) - - it('Should not send a ping if the ended job does not have a child', async function () { - let pings = 0 - const localSocket = server.socketIO.getRunnersSocket({ runnerToken }) - localSocket.on('available-jobs', () => pings++) - - const { availableJobs } = await server.runnerJobs.request({ runnerToken }) - const job = availableJobs.find(j => j.type === 'vod-web-video-transcoding') - await server.runnerJobs.autoProcessWebVideoJob(runnerToken, job.uuid) - - // Wait for debounce - await wait(1000) - await waitJobs([ server ]) - - expect(pings).to.equal(0) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/runners/runner-studio-transcoding.ts b/server/tests/api/runners/runner-studio-transcoding.ts deleted file mode 100644 index f5cea6cea..000000000 --- a/server/tests/api/runners/runner-studio-transcoding.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readFile } from 'fs-extra' -import { checkPersistentTmpIsEmpty, checkVideoDuration } from '@server/tests/shared' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { - RunnerJobStudioTranscodingPayload, - VideoStudioTranscodingSuccess, - VideoState, - VideoStudioTask, - VideoStudioTaskIntro -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - VideoStudioCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test runner video studio transcoding', function () { - let servers: PeerTubeServer[] = [] - let runnerToken: string - let videoUUID: string - let jobUUID: string - - async function renewStudio (tasks: VideoStudioTask[] = VideoStudioCommand.getComplexTask()) { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - videoUUID = uuid - - await waitJobs(servers) - - await servers[0].videoStudio.createEditionTasks({ videoId: uuid, tasks }) - await waitJobs(servers) - - const { availableJobs } = await servers[0].runnerJobs.request({ runnerToken }) - expect(availableJobs).to.have.lengthOf(1) - - jobUUID = availableJobs[0].uuid - } - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - await servers[0].config.enableStudio() - await servers[0].config.enableRemoteStudio() - - runnerToken = await servers[0].runners.autoRegisterRunner() - }) - - it('Should error a studio transcoding job', async function () { - this.timeout(60000) - - await renewStudio() - - for (let i = 0; i < 5; i++) { - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - const jobToken = job.jobToken - - await servers[0].runnerJobs.error({ runnerToken, jobUUID, jobToken, message: 'Error' }) - } - - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.state.id).to.equal(VideoState.PUBLISHED) - - await checkPersistentTmpIsEmpty(servers[0]) - }) - - it('Should cancel a transcoding job', async function () { - this.timeout(60000) - - await renewStudio() - - await servers[0].runnerJobs.cancelByAdmin({ jobUUID }) - - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.state.id).to.equal(VideoState.PUBLISHED) - - await checkPersistentTmpIsEmpty(servers[0]) - }) - - it('Should execute a remote studio job', async function () { - this.timeout(240_000) - - const tasks = [ - { - name: 'add-outro' as 'add-outro', - options: { - file: 'video_short.webm' - } - }, - { - name: 'add-watermark' as 'add-watermark', - options: { - file: 'custom-thumbnail.png' - } - }, - { - name: 'add-intro' as 'add-intro', - options: { - file: 'video_very_short_240p.mp4' - } - } - ] - - await renewStudio(tasks) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 5) - } - - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - const jobToken = job.jobToken - - expect(job.type === 'video-studio-transcoding') - expect(job.payload.input.videoFileUrl).to.exist - - // Check video input file - { - await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - } - - // Check task files - for (let i = 0; i < tasks.length; i++) { - const task = tasks[i] - const payloadTask = job.payload.tasks[i] - - expect(payloadTask.name).to.equal(task.name) - - const inputFile = await readFile(buildAbsoluteFixturePath(task.options.file)) - - const { body } = await servers[0].runnerJobs.getJobFile({ - url: (payloadTask as VideoStudioTaskIntro).options.file as string, - jobToken, - runnerToken - }) - - expect(body).to.deep.equal(inputFile) - } - - const payload: VideoStudioTranscodingSuccess = { videoFile: 'video_very_short_240p.mp4' } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 2) - } - - await checkPersistentTmpIsEmpty(servers[0]) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/runners/runner-vod-transcoding.ts b/server/tests/api/runners/runner-vod-transcoding.ts deleted file mode 100644 index ee6be4ee9..000000000 --- a/server/tests/api/runners/runner-vod-transcoding.ts +++ /dev/null @@ -1,545 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readFile } from 'fs-extra' -import { completeCheckHlsPlaylist } from '@server/tests/shared' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { - HttpStatusCode, - RunnerJobSuccessPayload, - RunnerJobVODAudioMergeTranscodingPayload, - RunnerJobVODHLSTranscodingPayload, - RunnerJobVODPayload, - RunnerJobVODWebVideoTranscodingPayload, - VideoState, - VODAudioMergeTranscodingSuccess, - VODHLSTranscodingSuccess, - VODWebVideoTranscodingSuccess -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - makeRawRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -async function processAllJobs (server: PeerTubeServer, runnerToken: string) { - do { - const { availableJobs } = await server.runnerJobs.requestVOD({ runnerToken }) - if (availableJobs.length === 0) break - - const { job } = await server.runnerJobs.accept({ runnerToken, jobUUID: availableJobs[0].uuid }) - - const payload: RunnerJobSuccessPayload = { - videoFile: `video_short_${job.payload.output.resolution}p.mp4`, - resolutionPlaylistFile: `video_short_${job.payload.output.resolution}p.m3u8` - } - await server.runnerJobs.success({ runnerToken, jobUUID: job.uuid, jobToken: job.jobToken, payload }) - } while (true) - - await waitJobs([ server ]) -} - -describe('Test runner VOD transcoding', function () { - let servers: PeerTubeServer[] = [] - let runnerToken: string - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableRemoteTranscoding() - runnerToken = await servers[0].runners.autoRegisterRunner() - }) - - describe('Without transcoding', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].config.disableTranscoding() - await servers[0].videos.quickUpload({ name: 'video' }) - - await waitJobs(servers) - }) - - it('Should not have available jobs', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(0) - }) - }) - - describe('With classic transcoding enabled', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - }) - - it('Should error a transcoding job', async function () { - this.timeout(60000) - - await servers[0].runnerJobs.cancelAllJobs() - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - await waitJobs(servers) - - const { availableJobs } = await servers[0].runnerJobs.request({ runnerToken }) - const jobUUID = availableJobs[0].uuid - - for (let i = 0; i < 5; i++) { - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - const jobToken = job.jobToken - - await servers[0].runnerJobs.error({ runnerToken, jobUUID, jobToken, message: 'Error' }) - } - - const video = await servers[0].videos.get({ id: uuid }) - expect(video.state.id).to.equal(VideoState.TRANSCODING_FAILED) - }) - - it('Should cancel a transcoding job', async function () { - await servers[0].runnerJobs.cancelAllJobs() - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - await waitJobs(servers) - - const { availableJobs } = await servers[0].runnerJobs.request({ runnerToken }) - const jobUUID = availableJobs[0].uuid - - await servers[0].runnerJobs.cancelByAdmin({ jobUUID }) - - const video = await servers[0].videos.get({ id: uuid }) - expect(video.state.id).to.equal(VideoState.PUBLISHED) - }) - }) - - describe('Web video transcoding only', function () { - let videoUUID: string - let jobToken: string - let jobUUID: string - - before(async function () { - this.timeout(60000) - - await servers[0].runnerJobs.cancelAllJobs() - await servers[0].config.enableTranscoding({ hls: false, webVideo: true }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'web video', fixture: 'video_short.webm' }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should have jobs available for remote runners', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(1) - - jobUUID = availableJobs[0].uuid - }) - - it('Should have a valid first transcoding job', async function () { - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - expect(job.type === 'vod-web-video-transcoding') - expect(job.payload.input.videoFileUrl).to.exist - expect(job.payload.output.resolution).to.equal(720) - expect(job.payload.output.fps).to.equal(25) - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('video_short.webm')) - - expect(body).to.deep.equal(inputFile) - }) - - it('Should transcode the max video resolution and send it back to the server', async function () { - this.timeout(60000) - - const payload: VODWebVideoTranscodingSuccess = { - videoFile: 'video_short.mp4' - } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(0) - - const { body } = await makeRawRequest({ url: video.files[0].fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(body).to.deep.equal(await readFile(buildAbsoluteFixturePath('video_short.mp4'))) - } - }) - - it('Should have 4 lower resolution to transcode', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(4) - - for (const resolution of [ 480, 360, 240, 144 ]) { - const job = availableJobs.find(j => j.payload.output.resolution === resolution) - expect(job).to.exist - expect(job.type).to.equal('vod-web-video-transcoding') - - if (resolution === 240) jobUUID = job.uuid - } - }) - - it('Should process one of these transcoding jobs', async function () { - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('video_short.mp4')) - - expect(body).to.deep.equal(inputFile) - - const payload: VODWebVideoTranscodingSuccess = { videoFile: `video_short_${job.payload.output.resolution}p.mp4` } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - }) - - it('Should process all other jobs', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(3) - - for (const resolution of [ 480, 360, 144 ]) { - const availableJob = availableJobs.find(j => j.payload.output.resolution === resolution) - expect(availableJob).to.exist - jobUUID = availableJob.uuid - - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('video_short.mp4')) - expect(body).to.deep.equal(inputFile) - - const payload: VODWebVideoTranscodingSuccess = { videoFile: `video_short_${resolution}p.mp4` } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - } - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.files).to.have.lengthOf(5) - expect(video.streamingPlaylists).to.have.lengthOf(0) - - const { body } = await makeRawRequest({ url: video.files[0].fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(body).to.deep.equal(await readFile(buildAbsoluteFixturePath('video_short.mp4'))) - - for (const file of video.files) { - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - - it('Should not have available jobs anymore', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(0) - }) - }) - - describe('HLS transcoding only', function () { - let videoUUID: string - let jobToken: string - let jobUUID: string - - before(async function () { - this.timeout(60000) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: false }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'hls video', fixture: 'video_short.webm' }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should run the optimize job', async function () { - this.timeout(60000) - - await servers[0].runnerJobs.autoProcessWebVideoJob(runnerToken) - }) - - it('Should have 5 HLS resolution to transcode', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(5) - - for (const resolution of [ 720, 480, 360, 240, 144 ]) { - const job = availableJobs.find(j => j.payload.output.resolution === resolution) - expect(job).to.exist - expect(job.type).to.equal('vod-hls-transcoding') - - if (resolution === 480) jobUUID = job.uuid - } - }) - - it('Should process one of these transcoding jobs', async function () { - this.timeout(60000) - - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('video_short.mp4')) - - expect(body).to.deep.equal(inputFile) - - const payload: VODHLSTranscodingSuccess = { - videoFile: 'video_short_480p.mp4', - resolutionPlaylistFile: 'video_short_480p.m3u8' - } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const hls = video.streamingPlaylists[0] - expect(hls.files).to.have.lengthOf(1) - - await completeCheckHlsPlaylist({ videoUUID, hlsOnly: false, servers, resolutions: [ 480 ] }) - } - }) - - it('Should process all other jobs', async function () { - this.timeout(60000) - - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(4) - - let maxQualityFile = 'video_short.mp4' - - for (const resolution of [ 720, 360, 240, 144 ]) { - const availableJob = availableJobs.find(j => j.payload.output.resolution === resolution) - expect(availableJob).to.exist - jobUUID = availableJob.uuid - - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath(maxQualityFile)) - expect(body).to.deep.equal(inputFile) - - const payload: VODHLSTranscodingSuccess = { - videoFile: `video_short_${resolution}p.mp4`, - resolutionPlaylistFile: `video_short_${resolution}p.m3u8` - } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - if (resolution === 720) { - maxQualityFile = 'video_short_720p.mp4' - } - } - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.files).to.have.lengthOf(0) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const hls = video.streamingPlaylists[0] - expect(hls.files).to.have.lengthOf(5) - - await completeCheckHlsPlaylist({ videoUUID, hlsOnly: true, servers, resolutions: [ 720, 480, 360, 240, 144 ] }) - } - }) - - it('Should not have available jobs anymore', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(0) - }) - }) - - describe('Web video and HLS transcoding', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - - await servers[0].videos.quickUpload({ name: 'web video and hls video', fixture: 'video_short.webm' }) - - await waitJobs(servers) - }) - - it('Should process the first optimize job', async function () { - this.timeout(60000) - - await servers[0].runnerJobs.autoProcessWebVideoJob(runnerToken) - }) - - it('Should have 9 jobs to process', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - - expect(availableJobs).to.have.lengthOf(9) - - const webVideoJobs = availableJobs.filter(j => j.type === 'vod-web-video-transcoding') - const hlsJobs = availableJobs.filter(j => j.type === 'vod-hls-transcoding') - - expect(webVideoJobs).to.have.lengthOf(4) - expect(hlsJobs).to.have.lengthOf(5) - }) - - it('Should process all available jobs', async function () { - await processAllJobs(servers[0], runnerToken) - }) - }) - - describe('Audio merge transcoding', function () { - let videoUUID: string - let jobToken: string - let jobUUID: string - - before(async function () { - this.timeout(60000) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - - const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' } - const { uuid } = await servers[0].videos.upload({ attributes, mode: 'legacy' }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should have an audio merge transcoding job', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(1) - - expect(availableJobs[0].type).to.equal('vod-audio-merge-transcoding') - - jobUUID = availableJobs[0].uuid - }) - - it('Should have a valid remote audio merge transcoding job', async function () { - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - expect(job.type === 'vod-audio-merge-transcoding') - expect(job.payload.input.audioFileUrl).to.exist - expect(job.payload.input.previewFileUrl).to.exist - expect(job.payload.output.resolution).to.equal(480) - - { - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.audioFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('sample.ogg')) - expect(body).to.deep.equal(inputFile) - } - - { - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.previewFileUrl, jobToken, runnerToken }) - - const video = await servers[0].videos.get({ id: videoUUID }) - const { body: inputFile } = await makeGetRequest({ - url: servers[0].url, - path: video.previewPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(body).to.deep.equal(inputFile) - } - }) - - it('Should merge the audio', async function () { - this.timeout(60000) - - const payload: VODAudioMergeTranscodingSuccess = { videoFile: 'video_short_480p.mp4' } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(0) - - const { body } = await makeRawRequest({ url: video.files[0].fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(body).to.deep.equal(await readFile(buildAbsoluteFixturePath('video_short_480p.mp4'))) - } - }) - - it('Should have 7 lower resolutions to transcode', async function () { - const { availableJobs } = await servers[0].runnerJobs.requestVOD({ runnerToken }) - expect(availableJobs).to.have.lengthOf(7) - - for (const resolution of [ 360, 240, 144 ]) { - const jobs = availableJobs.filter(j => j.payload.output.resolution === resolution) - expect(jobs).to.have.lengthOf(2) - } - - jobUUID = availableJobs.find(j => j.payload.output.resolution === 480).uuid - }) - - it('Should process one other job', async function () { - this.timeout(60000) - - const { job } = await servers[0].runnerJobs.accept({ runnerToken, jobUUID }) - jobToken = job.jobToken - - const { body } = await servers[0].runnerJobs.getJobFile({ url: job.payload.input.videoFileUrl, jobToken, runnerToken }) - const inputFile = await readFile(buildAbsoluteFixturePath('video_short_480p.mp4')) - expect(body).to.deep.equal(inputFile) - - const payload: VODHLSTranscodingSuccess = { - videoFile: `video_short_480p.mp4`, - resolutionPlaylistFile: `video_short_480p.m3u8` - } - await servers[0].runnerJobs.success({ runnerToken, jobUUID, jobToken, payload }) - - await waitJobs(servers) - }) - - it('Should have the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const hls = video.streamingPlaylists[0] - expect(hls.files).to.have.lengthOf(1) - - await completeCheckHlsPlaylist({ videoUUID, hlsOnly: false, servers, resolutions: [ 480 ] }) - } - }) - - it('Should process all available jobs', async function () { - await processAllJobs(servers[0], runnerToken) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/search/index.ts b/server/tests/api/search/index.ts deleted file mode 100644 index a976d210d..000000000 --- a/server/tests/api/search/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import './search-activitypub-video-playlists' -import './search-activitypub-video-channels' -import './search-activitypub-videos' -import './search-channels' -import './search-index' -import './search-playlists' -import './search-videos' diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts deleted file mode 100644 index 003bd34d0..000000000 --- a/server/tests/api/search/search-activitypub-video-channels.ts +++ /dev/null @@ -1,255 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideoChannel } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test ActivityPub video channels search', function () { - let servers: PeerTubeServer[] - let userServer2Token: string - let videoServer2UUID: string - let channelIdServer2: number - let command: SearchCommand - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - { - await servers[0].users.create({ username: 'user1_server1', password: 'password' }) - const channel = { - name: 'channel1_server1', - displayName: 'Channel 1 server 1' - } - await servers[0].channels.create({ attributes: channel }) - } - - { - const user = { username: 'user1_server2', password: 'password' } - await servers[1].users.create({ username: user.username, password: user.password }) - userServer2Token = await servers[1].login.getAccessToken(user) - - const channel = { - name: 'channel1_server2', - displayName: 'Channel 1 server 2' - } - const created = await servers[1].channels.create({ token: userServer2Token, attributes: channel }) - channelIdServer2 = created.id - - const attributes = { name: 'video 1 server 2', channelId: channelIdServer2 } - const { uuid } = await servers[1].videos.upload({ token: userServer2Token, attributes }) - videoServer2UUID = uuid - } - - await waitJobs(servers) - - command = servers[0].search - }) - - it('Should not find a remote video channel', async function () { - this.timeout(15000) - - { - const search = servers[1].url + '/video-channels/channel1_server3' - const body = await command.searchChannels({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - // Without token - const search = servers[1].url + '/video-channels/channel1_server2' - const body = await command.searchChannels({ search }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should search a local video channel', async function () { - const searches = [ - servers[0].url + '/video-channels/channel1_server1', - 'channel1_server1@' + servers[0].host - ] - - for (const search of searches) { - const body = await command.searchChannels({ search }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('channel1_server1') - expect(body.data[0].displayName).to.equal('Channel 1 server 1') - } - }) - - it('Should search a local video channel with an alternative URL', async function () { - const search = servers[0].url + '/c/channel1_server1' - - for (const token of [ undefined, servers[0].accessToken ]) { - const body = await command.searchChannels({ search, token }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('channel1_server1') - expect(body.data[0].displayName).to.equal('Channel 1 server 1') - } - }) - - it('Should search a local video channel with a query in URL', async function () { - const searches = [ - servers[0].url + '/video-channels/channel1_server1', - servers[0].url + '/c/channel1_server1' - ] - - for (const search of searches) { - for (const token of [ undefined, servers[0].accessToken ]) { - const body = await command.searchChannels({ search: search + '?param=2', token }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('channel1_server1') - expect(body.data[0].displayName).to.equal('Channel 1 server 1') - } - } - }) - - it('Should search a remote video channel with URL or handle', async function () { - const searches = [ - servers[1].url + '/video-channels/channel1_server2', - servers[1].url + '/c/channel1_server2', - servers[1].url + '/c/channel1_server2/videos', - 'channel1_server2@' + servers[1].host - ] - - for (const search of searches) { - const body = await command.searchChannels({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('channel1_server2') - expect(body.data[0].displayName).to.equal('Channel 1 server 2') - } - }) - - it('Should not list this remote video channel', async function () { - const body = await servers[0].channels.list() - expect(body.total).to.equal(3) - expect(body.data).to.have.lengthOf(3) - expect(body.data[0].name).to.equal('channel1_server1') - expect(body.data[1].name).to.equal('user1_server1_channel') - expect(body.data[2].name).to.equal('root_channel') - }) - - it('Should list video channel videos of server 2 without token', async function () { - this.timeout(30000) - - await waitJobs(servers) - - const { total, data } = await servers[0].videos.listByChannel({ - token: null, - handle: 'channel1_server2@' + servers[1].host - }) - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - }) - - it('Should list video channel videos of server 2 with token', async function () { - const { total, data } = await servers[0].videos.listByChannel({ - handle: 'channel1_server2@' + servers[1].host - }) - - expect(total).to.equal(1) - expect(data[0].name).to.equal('video 1 server 2') - }) - - it('Should update video channel of server 2, and refresh it on server 1', async function () { - this.timeout(120000) - - await servers[1].channels.update({ - token: userServer2Token, - channelName: 'channel1_server2', - attributes: { displayName: 'channel updated' } - }) - await servers[1].users.updateMe({ token: userServer2Token, displayName: 'user updated' }) - - await waitJobs(servers) - // Expire video channel - await wait(10000) - - const search = servers[1].url + '/video-channels/channel1_server2' - const body = await command.searchChannels({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const videoChannel: VideoChannel = body.data[0] - expect(videoChannel.displayName).to.equal('channel updated') - - // We don't return the owner account for now - // expect(videoChannel.ownerAccount.displayName).to.equal('user updated') - }) - - it('Should update and add a video on server 2, and update it on server 1 after a search', async function () { - this.timeout(120000) - - await servers[1].videos.update({ token: userServer2Token, id: videoServer2UUID, attributes: { name: 'video 1 updated' } }) - await servers[1].videos.upload({ token: userServer2Token, attributes: { name: 'video 2 server 2', channelId: channelIdServer2 } }) - - await waitJobs(servers) - - // Expire video channel - await wait(10000) - - const search = servers[1].url + '/video-channels/channel1_server2' - await command.searchChannels({ search, token: servers[0].accessToken }) - - await waitJobs(servers) - - const handle = 'channel1_server2@' + servers[1].host - const { total, data } = await servers[0].videos.listByChannel({ handle, sort: '-createdAt' }) - - expect(total).to.equal(2) - expect(data[0].name).to.equal('video 2 server 2') - expect(data[1].name).to.equal('video 1 updated') - }) - - it('Should delete video channel of server 2, and delete it on server 1', async function () { - this.timeout(120000) - - await servers[1].channels.delete({ token: userServer2Token, channelName: 'channel1_server2' }) - - await waitJobs(servers) - // Expire video - await wait(10000) - - const search = servers[1].url + '/video-channels/channel1_server2' - const body = await command.searchChannels({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/search/search-activitypub-video-playlists.ts b/server/tests/api/search/search-activitypub-video-playlists.ts deleted file mode 100644 index 2bb5d869a..000000000 --- a/server/tests/api/search/search-activitypub-video-playlists.ts +++ /dev/null @@ -1,214 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideoPlaylistPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test ActivityPub playlists search', function () { - let servers: PeerTubeServer[] - let playlistServer1UUID: string - let playlistServer2UUID: string - let video2Server2: string - - let command: SearchCommand - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - { - const video1 = (await servers[0].videos.quickUpload({ name: 'video 1' })).uuid - const video2 = (await servers[0].videos.quickUpload({ name: 'video 2' })).uuid - - const attributes = { - displayName: 'playlist 1 on server 1', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[0].store.channel.id - } - const created = await servers[0].playlists.create({ attributes }) - playlistServer1UUID = created.uuid - - for (const videoId of [ video1, video2 ]) { - await servers[0].playlists.addElement({ playlistId: playlistServer1UUID, attributes: { videoId } }) - } - } - - { - const videoId = (await servers[1].videos.quickUpload({ name: 'video 1' })).uuid - video2Server2 = (await servers[1].videos.quickUpload({ name: 'video 2' })).uuid - - const attributes = { - displayName: 'playlist 1 on server 2', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[1].store.channel.id - } - const created = await servers[1].playlists.create({ attributes }) - playlistServer2UUID = created.uuid - - await servers[1].playlists.addElement({ playlistId: playlistServer2UUID, attributes: { videoId } }) - } - - await waitJobs(servers) - - command = servers[0].search - }) - - it('Should not find a remote playlist', async function () { - { - const search = servers[1].url + '/video-playlists/43' - const body = await command.searchPlaylists({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - // Without token - const search = servers[1].url + '/video-playlists/' + playlistServer2UUID - const body = await command.searchPlaylists({ search }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should search a local playlist', async function () { - const search = servers[0].url + '/video-playlists/' + playlistServer1UUID - const body = await command.searchPlaylists({ search }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('playlist 1 on server 1') - expect(body.data[0].videosLength).to.equal(2) - }) - - it('Should search a local playlist with an alternative URL', async function () { - const searches = [ - servers[0].url + '/videos/watch/playlist/' + playlistServer1UUID, - servers[0].url + '/w/p/' + playlistServer1UUID - ] - - for (const search of searches) { - for (const token of [ undefined, servers[0].accessToken ]) { - const body = await command.searchPlaylists({ search, token }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('playlist 1 on server 1') - expect(body.data[0].videosLength).to.equal(2) - } - } - }) - - it('Should search a local playlist with a query in URL', async function () { - const searches = [ - servers[0].url + '/videos/watch/playlist/' + playlistServer1UUID, - servers[0].url + '/w/p/' + playlistServer1UUID - ] - - for (const search of searches) { - for (const token of [ undefined, servers[0].accessToken ]) { - const body = await command.searchPlaylists({ search: search + '?param=1', token }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('playlist 1 on server 1') - expect(body.data[0].videosLength).to.equal(2) - } - } - }) - - it('Should search a remote playlist', async function () { - const searches = [ - servers[1].url + '/video-playlists/' + playlistServer2UUID, - servers[1].url + '/videos/watch/playlist/' + playlistServer2UUID, - servers[1].url + '/w/p/' + playlistServer2UUID - ] - - for (const search of searches) { - const body = await command.searchPlaylists({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('playlist 1 on server 2') - expect(body.data[0].videosLength).to.equal(1) - } - }) - - it('Should not list this remote playlist', async function () { - const body = await servers[0].playlists.list({ start: 0, count: 10 }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('playlist 1 on server 1') - }) - - it('Should update the playlist of server 2, and refresh it on server 1', async function () { - this.timeout(60000) - - await servers[1].playlists.addElement({ playlistId: playlistServer2UUID, attributes: { videoId: video2Server2 } }) - - await waitJobs(servers) - // Expire playlist - await wait(10000) - - // Will run refresh async - const search = servers[1].url + '/video-playlists/' + playlistServer2UUID - await command.searchPlaylists({ search, token: servers[0].accessToken }) - - // Wait refresh - await wait(5000) - - const body = await command.searchPlaylists({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.videosLength).to.equal(2) - }) - - it('Should delete playlist of server 2, and delete it on server 1', async function () { - this.timeout(60000) - - await servers[1].playlists.delete({ playlistId: playlistServer2UUID }) - - await waitJobs(servers) - // Expiration - await wait(10000) - - // Will run refresh async - const search = servers[1].url + '/video-playlists/' + playlistServer2UUID - await command.searchPlaylists({ search, token: servers[0].accessToken }) - - // Wait refresh - await wait(5000) - - const body = await command.searchPlaylists({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts deleted file mode 100644 index 4c7118422..000000000 --- a/server/tests/api/search/search-activitypub-videos.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test ActivityPub videos search', function () { - let servers: PeerTubeServer[] - let videoServer1UUID: string - let videoServer2UUID: string - - let command: SearchCommand - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1 on server 1' } }) - videoServer1UUID = uuid - } - - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 1 on server 2' } }) - videoServer2UUID = uuid - } - - await waitJobs(servers) - - command = servers[0].search - }) - - it('Should not find a remote video', async function () { - { - const search = servers[1].url + '/videos/watch/43' - const body = await command.searchVideos({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - // Without token - const search = servers[1].url + '/videos/watch/' + videoServer2UUID - const body = await command.searchVideos({ search }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should search a local video', async function () { - const search = servers[0].url + '/videos/watch/' + videoServer1UUID - const body = await command.searchVideos({ search }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('video 1 on server 1') - }) - - it('Should search a local video with an alternative URL', async function () { - const search = servers[0].url + '/w/' + videoServer1UUID - const body1 = await command.searchVideos({ search }) - const body2 = await command.searchVideos({ search, token: servers[0].accessToken }) - - for (const body of [ body1, body2 ]) { - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('video 1 on server 1') - } - }) - - it('Should search a local video with a query in URL', async function () { - const searches = [ - servers[0].url + '/w/' + videoServer1UUID, - servers[0].url + '/videos/watch/' + videoServer1UUID - ] - - for (const search of searches) { - for (const token of [ undefined, servers[0].accessToken ]) { - const body = await command.searchVideos({ search: search + '?startTime=4', token }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('video 1 on server 1') - } - } - }) - - it('Should search a remote video', async function () { - const searches = [ - servers[1].url + '/w/' + videoServer2UUID, - servers[1].url + '/videos/watch/' + videoServer2UUID - ] - - for (const search of searches) { - const body = await command.searchVideos({ search, token: servers[0].accessToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('video 1 on server 2') - } - }) - - it('Should not list this remote video', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('video 1 on server 1') - }) - - it('Should update video of server 2, and refresh it on server 1', async function () { - this.timeout(120000) - - const channelAttributes = { - name: 'super_channel', - displayName: 'super channel' - } - const created = await servers[1].channels.create({ attributes: channelAttributes }) - const videoChannelId = created.id - - const attributes = { - name: 'updated', - tag: [ 'tag1', 'tag2' ], - privacy: VideoPrivacy.UNLISTED, - channelId: videoChannelId - } - await servers[1].videos.update({ id: videoServer2UUID, attributes }) - - await waitJobs(servers) - // Expire video - await wait(10000) - - // Will run refresh async - const search = servers[1].url + '/videos/watch/' + videoServer2UUID - await command.searchVideos({ search, token: servers[0].accessToken }) - - // Wait refresh - await wait(5000) - - const body = await command.searchVideos({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const video = body.data[0] - expect(video.name).to.equal('updated') - expect(video.channel.name).to.equal('super_channel') - expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) - }) - - it('Should delete video of server 2, and delete it on server 1', async function () { - this.timeout(120000) - - await servers[1].videos.remove({ id: videoServer2UUID }) - - await waitJobs(servers) - // Expire video - await wait(10000) - - // Will run refresh async - const search = servers[1].url + '/videos/watch/' + videoServer2UUID - await command.searchVideos({ search, token: servers[0].accessToken }) - - // Wait refresh - await wait(5000) - - const body = await command.searchVideos({ search, token: servers[0].accessToken }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/search/search-channels.ts b/server/tests/api/search/search-channels.ts deleted file mode 100644 index c6b098a93..000000000 --- a/server/tests/api/search/search-channels.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { VideoChannel } from '@shared/models' -import { - cleanupTests, - createSingleServer, - doubleFollow, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar -} from '@shared/server-commands' - -describe('Test channels search', function () { - let server: PeerTubeServer - let remoteServer: PeerTubeServer - let command: SearchCommand - - before(async function () { - this.timeout(120000) - - const servers = await Promise.all([ - createSingleServer(1), - createSingleServer(2) - ]) - server = servers[0] - remoteServer = servers[1] - - await setAccessTokensToServers([ server, remoteServer ]) - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(server) - - await servers[1].config.disableTranscoding() - - { - await server.users.create({ username: 'user1' }) - const channel = { - name: 'squall_channel', - displayName: 'Squall channel' - } - await server.channels.create({ attributes: channel }) - } - - { - await remoteServer.users.create({ username: 'user1' }) - const channel = { - name: 'zell_channel', - displayName: 'Zell channel' - } - const { id } = await remoteServer.channels.create({ attributes: channel }) - - await remoteServer.videos.upload({ attributes: { channelId: id } }) - } - - await doubleFollow(server, remoteServer) - - command = server.search - }) - - it('Should make a simple search and not have results', async function () { - const body = await command.searchChannels({ search: 'abc' }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a search and have results', async function () { - { - const search = { - search: 'Squall', - start: 0, - count: 1 - } - const body = await command.advancedChannelSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const channel: VideoChannel = body.data[0] - expect(channel.name).to.equal('squall_channel') - expect(channel.displayName).to.equal('Squall channel') - } - - { - const search = { - search: 'Squall', - start: 1, - count: 1 - } - - const body = await command.advancedChannelSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should filter by host', async function () { - { - const search = { search: 'channel', host: remoteServer.host } - - const body = await command.advancedChannelSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('Zell channel') - } - - { - const search = { search: 'Sq', host: server.host } - - const body = await command.advancedChannelSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('Squall channel') - } - - { - const search = { search: 'Squall', host: 'example.com' } - - const body = await command.advancedChannelSearch({ search }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should filter by names', async function () { - { - const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel', 'zell_channel' ] } }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('Squall channel') - } - - { - const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel@' + server.host ] } }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].displayName).to.equal('Squall channel') - } - - { - const body = await command.advancedChannelSearch({ search: { handles: [ 'chocobozzz_channel' ] } }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel', 'zell_channel@' + remoteServer.host ] } }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - expect(body.data[0].displayName).to.equal('Squall channel') - expect(body.data[1].displayName).to.equal('Zell channel') - } - }) - - after(async function () { - await cleanupTests([ server, remoteServer ]) - }) -}) diff --git a/server/tests/api/search/search-index.ts b/server/tests/api/search/search-index.ts deleted file mode 100644 index cbe628ccc..000000000 --- a/server/tests/api/search/search-index.ts +++ /dev/null @@ -1,432 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - BooleanBothQuery, - VideoChannelsSearchQuery, - VideoPlaylistPrivacy, - VideoPlaylistsSearchQuery, - VideoPlaylistType, - VideosSearchQuery -} from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, SearchCommand, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test index search', function () { - const localVideoName = 'local video' + new Date().toISOString() - - let server: PeerTubeServer = null - let command: SearchCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - await server.videos.upload({ attributes: { name: localVideoName } }) - - command = server.search - }) - - describe('Default search', async function () { - - it('Should make a local videos search by default', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - search: { - searchIndex: { - enabled: true, - isDefaultSearch: false, - disableLocalSearch: false - } - } - } - }) - - const body = await command.searchVideos({ search: 'local video' }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal(localVideoName) - }) - - it('Should make a local channels search by default', async function () { - const body = await command.searchChannels({ search: 'root' }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('root_channel') - expect(body.data[0].host).to.equal(server.host) - }) - - it('Should make an index videos search by default', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - search: { - searchIndex: { - enabled: true, - isDefaultSearch: true, - disableLocalSearch: false - } - } - } - }) - - const body = await command.searchVideos({ search: 'local video' }) - expect(body.total).to.be.greaterThan(2) - }) - - it('Should make an index channels search by default', async function () { - const body = await command.searchChannels({ search: 'root' }) - expect(body.total).to.be.greaterThan(2) - }) - }) - - describe('Videos search', async function () { - - async function check (search: VideosSearchQuery, exists = true) { - const body = await command.advancedVideoSearch({ search }) - - if (exists === false) { - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - return - } - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const video = body.data[0] - - expect(video.name).to.equal('What is PeerTube?') - expect(video.category.label).to.equal('Science & Technology') - expect(video.licence.label).to.equal('Attribution - Share Alike') - expect(video.privacy.label).to.equal('Public') - expect(video.duration).to.equal(113) - expect(video.thumbnailUrl.startsWith('https://framatube.org/static/thumbnails')).to.be.true - - expect(video.account.host).to.equal('framatube.org') - expect(video.account.name).to.equal('framasoft') - expect(video.account.url).to.equal('https://framatube.org/accounts/framasoft') - expect(video.account.avatars.length).to.equal(2, 'Account should have one avatar image') - - expect(video.channel.host).to.equal('framatube.org') - expect(video.channel.name).to.equal('joinpeertube') - expect(video.channel.url).to.equal('https://framatube.org/video-channels/joinpeertube') - expect(video.channel.avatars.length).to.equal(2, 'Channel should have one avatar image') - } - - const baseSearch: VideosSearchQuery = { - search: 'what is peertube', - start: 0, - count: 2, - categoryOneOf: [ 15 ], - licenceOneOf: [ 2 ], - tagsAllOf: [ 'framasoft', 'peertube' ], - startDate: '2018-10-01T10:50:46.396Z', - endDate: '2018-10-01T10:55:46.396Z' - } - - it('Should make a simple search and not have results', async function () { - const body = await command.searchVideos({ search: 'djidane'.repeat(50) }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a simple search and have results', async function () { - const body = await command.searchVideos({ search: 'What is PeerTube' }) - - expect(body.total).to.be.greaterThan(1) - }) - - it('Should make a simple search', async function () { - await check(baseSearch) - }) - - it('Should search by start date', async function () { - const search = { ...baseSearch, startDate: '2018-10-01T10:54:46.396Z' } - await check(search, false) - }) - - it('Should search by tags', async function () { - const search = { ...baseSearch, tagsAllOf: [ 'toto', 'framasoft' ] } - await check(search, false) - }) - - it('Should search by duration', async function () { - const search = { ...baseSearch, durationMin: 2000 } - await check(search, false) - }) - - it('Should search by nsfw attribute', async function () { - { - const search = { ...baseSearch, nsfw: 'true' as BooleanBothQuery } - await check(search, false) - } - - { - const search = { ...baseSearch, nsfw: 'false' as BooleanBothQuery } - await check(search, true) - } - - { - const search = { ...baseSearch, nsfw: 'both' as BooleanBothQuery } - await check(search, true) - } - }) - - it('Should search by host', async function () { - { - const search = { ...baseSearch, host: 'example.com' } - await check(search, false) - } - - { - const search = { ...baseSearch, host: 'framatube.org' } - await check(search, true) - } - }) - - it('Should search by uuids', async function () { - const goodUUID = '9c9de5e8-0a1e-484a-b099-e80766180a6d' - const goodShortUUID = 'kkGMgK9ZtnKfYAgnEtQxbv' - const badUUID = 'c29c5b77-4a04-493d-96a9-2e9267e308f0' - const badShortUUID = 'rP5RgUeX9XwTSrspCdkDej' - - { - const uuidsMatrix = [ - [ goodUUID ], - [ goodUUID, badShortUUID ], - [ badShortUUID, goodShortUUID ], - [ goodUUID, goodShortUUID ] - ] - - for (const uuids of uuidsMatrix) { - const search = { ...baseSearch, uuids } - await check(search, true) - } - } - - { - const uuidsMatrix = [ - [ badUUID ], - [ badShortUUID ] - ] - - for (const uuids of uuidsMatrix) { - const search = { ...baseSearch, uuids } - await check(search, false) - } - } - }) - - it('Should have a correct pagination', async function () { - const search = { - search: 'video', - start: 0, - count: 5 - } - - const body = await command.advancedVideoSearch({ search }) - - expect(body.total).to.be.greaterThan(5) - expect(body.data).to.have.lengthOf(5) - }) - - it('Should use the nsfw instance policy as default', async function () { - let nsfwUUID: string - - { - await server.config.updateCustomSubConfig({ - newConfig: { - instance: { defaultNSFWPolicy: 'display' } - } - }) - - const body = await command.searchVideos({ search: 'NSFW search index', sort: '-match' }) - expect(body.data).to.have.length.greaterThan(0) - - const video = body.data[0] - expect(video.nsfw).to.be.true - - nsfwUUID = video.uuid - } - - { - await server.config.updateCustomSubConfig({ - newConfig: { - instance: { defaultNSFWPolicy: 'do_not_list' } - } - }) - - const body = await command.searchVideos({ search: 'NSFW search index', sort: '-match' }) - - try { - expect(body.data).to.have.lengthOf(0) - } catch { - const video = body.data[0] - - expect(video.uuid).not.equal(nsfwUUID) - } - } - }) - }) - - describe('Channels search', async function () { - - async function check (search: VideoChannelsSearchQuery, exists = true) { - const body = await command.advancedChannelSearch({ search }) - - if (exists === false) { - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - return - } - - expect(body.total).to.be.greaterThan(0) - expect(body.data).to.have.length.greaterThan(0) - - const videoChannel = body.data[0] - expect(videoChannel.url).to.equal('https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8') - expect(videoChannel.host).to.equal('framatube.org') - expect(videoChannel.avatars.length).to.equal(2, 'Channel should have two avatar images') - expect(videoChannel.displayName).to.exist - - expect(videoChannel.ownerAccount.url).to.equal('https://framatube.org/accounts/framasoft') - expect(videoChannel.ownerAccount.name).to.equal('framasoft') - expect(videoChannel.ownerAccount.host).to.equal('framatube.org') - expect(videoChannel.ownerAccount.avatars.length).to.equal(2, 'Account should have two avatar images') - } - - it('Should make a simple search and not have results', async function () { - const body = await command.searchChannels({ search: 'a'.repeat(500) }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a search and have results', async function () { - await check({ search: 'Framasoft', sort: 'createdAt' }, true) - }) - - it('Should make host search and have appropriate results', async function () { - await check({ search: 'Framasoft videos', host: 'example.com' }, false) - await check({ search: 'Framasoft videos', host: 'framatube.org' }, true) - }) - - it('Should make handles search and have appropriate results', async function () { - await check({ handles: [ 'bf54d359-cfad-4935-9d45-9d6be93f63e8@framatube.org' ] }, true) - await check({ handles: [ 'jeanine', 'bf54d359-cfad-4935-9d45-9d6be93f63e8@framatube.org' ] }, true) - await check({ handles: [ 'jeanine', 'chocobozzz_channel2@peertube2.cpy.re' ] }, false) - }) - - it('Should have a correct pagination', async function () { - const body = await command.advancedChannelSearch({ search: { search: 'root', start: 0, count: 2 } }) - - expect(body.total).to.be.greaterThan(2) - expect(body.data).to.have.lengthOf(2) - }) - }) - - describe('Playlists search', async function () { - - async function check (search: VideoPlaylistsSearchQuery, exists = true) { - const body = await command.advancedPlaylistSearch({ search }) - - if (exists === false) { - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - return - } - - expect(body.total).to.be.greaterThan(0) - expect(body.data).to.have.length.greaterThan(0) - - const videoPlaylist = body.data[0] - - expect(videoPlaylist.url).to.equal('https://peertube2.cpy.re/videos/watch/playlist/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') - expect(videoPlaylist.thumbnailUrl).to.exist - expect(videoPlaylist.embedUrl).to.equal('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') - - expect(videoPlaylist.type.id).to.equal(VideoPlaylistType.REGULAR) - expect(videoPlaylist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC) - expect(videoPlaylist.videosLength).to.exist - - expect(videoPlaylist.createdAt).to.exist - expect(videoPlaylist.updatedAt).to.exist - - expect(videoPlaylist.uuid).to.equal('73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') - expect(videoPlaylist.displayName).to.exist - - expect(videoPlaylist.ownerAccount.url).to.equal('https://peertube2.cpy.re/accounts/chocobozzz') - expect(videoPlaylist.ownerAccount.name).to.equal('chocobozzz') - expect(videoPlaylist.ownerAccount.host).to.equal('peertube2.cpy.re') - expect(videoPlaylist.ownerAccount.avatars.length).to.equal(2, 'Account should have two avatar images') - - expect(videoPlaylist.videoChannel.url).to.equal('https://peertube2.cpy.re/video-channels/chocobozzz_channel') - expect(videoPlaylist.videoChannel.name).to.equal('chocobozzz_channel') - expect(videoPlaylist.videoChannel.host).to.equal('peertube2.cpy.re') - expect(videoPlaylist.videoChannel.avatars.length).to.equal(2, 'Channel should have two avatar images') - } - - it('Should make a simple search and not have results', async function () { - const body = await command.searchPlaylists({ search: 'a'.repeat(500) }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a search and have results', async function () { - await check({ search: 'E2E playlist', sort: '-match' }, true) - }) - - it('Should make host search and have appropriate results', async function () { - await check({ search: 'E2E playlist', host: 'example.com' }, false) - await check({ search: 'E2E playlist', host: 'peertube2.cpy.re', sort: '-match' }, true) - }) - - it('Should make a search by uuids and have appropriate results', async function () { - const goodUUID = '73804a40-da9a-40c2-b1eb-2c6d9eec8f0a' - const goodShortUUID = 'fgei1ws1oa6FCaJ2qZPG29' - const badUUID = 'c29c5b77-4a04-493d-96a9-2e9267e308f0' - const badShortUUID = 'rP5RgUeX9XwTSrspCdkDej' - - { - const uuidsMatrix = [ - [ goodUUID ], - [ goodUUID, badShortUUID ], - [ badShortUUID, goodShortUUID ], - [ goodUUID, goodShortUUID ] - ] - - for (const uuids of uuidsMatrix) { - const search = { search: 'E2E playlist', sort: '-match', uuids } - await check(search, true) - } - } - - { - const uuidsMatrix = [ - [ badUUID ], - [ badShortUUID ] - ] - - for (const uuids of uuidsMatrix) { - const search = { search: 'E2E playlist', sort: '-match', uuids } - await check(search, false) - } - } - }) - - it('Should have a correct pagination', async function () { - const body = await command.advancedChannelSearch({ search: { search: 'root', start: 0, count: 2 } }) - - expect(body.total).to.be.greaterThan(2) - expect(body.data).to.have.lengthOf(2) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/search/search-playlists.ts b/server/tests/api/search/search-playlists.ts deleted file mode 100644 index a357674c2..000000000 --- a/server/tests/api/search/search-playlists.ts +++ /dev/null @@ -1,180 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { VideoPlaylistPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - doubleFollow, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - setDefaultVideoChannel -} from '@shared/server-commands' - -describe('Test playlists search', function () { - let server: PeerTubeServer - let remoteServer: PeerTubeServer - let command: SearchCommand - let playlistUUID: string - let playlistShortUUID: string - - before(async function () { - this.timeout(120000) - - const servers = await Promise.all([ - createSingleServer(1), - createSingleServer(2) - ]) - server = servers[0] - remoteServer = servers[1] - - await setAccessTokensToServers([ remoteServer, server ]) - await setDefaultVideoChannel([ remoteServer, server ]) - await setDefaultChannelAvatar([ remoteServer, server ]) - await setDefaultAccountAvatar([ remoteServer, server ]) - - await servers[1].config.disableTranscoding() - - { - const videoId = (await server.videos.upload()).uuid - - const attributes = { - displayName: 'Dr. Kenzo Tenma hospital videos', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id - } - const created = await server.playlists.create({ attributes }) - playlistUUID = created.uuid - playlistShortUUID = created.shortUUID - - await server.playlists.addElement({ playlistId: created.id, attributes: { videoId } }) - } - - { - const videoId = (await remoteServer.videos.upload()).uuid - - const attributes = { - displayName: 'Johan & Anna Libert music videos', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: remoteServer.store.channel.id - } - const created = await remoteServer.playlists.create({ attributes }) - - await remoteServer.playlists.addElement({ playlistId: created.id, attributes: { videoId } }) - } - - { - const attributes = { - displayName: 'Inspector Lunge playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id - } - await server.playlists.create({ attributes }) - } - - await doubleFollow(server, remoteServer) - - command = server.search - }) - - it('Should make a simple search and not have results', async function () { - const body = await command.searchPlaylists({ search: 'abc' }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a search and have results', async function () { - { - const search = { - search: 'tenma', - start: 0, - count: 1 - } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos') - expect(playlist.url).to.equal(server.url + '/video-playlists/' + playlist.uuid) - } - - { - const search = { - search: 'Anna Livert music', - start: 0, - count: 1 - } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.displayName).to.equal('Johan & Anna Libert music videos') - } - }) - - it('Should filter by host', async function () { - { - const search = { search: 'tenma', host: server.host } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos') - } - - { - const search = { search: 'Anna', host: 'example.com' } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const search = { search: 'video', host: remoteServer.host } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.displayName).to.equal('Johan & Anna Libert music videos') - } - }) - - it('Should filter by UUIDs', async function () { - for (const uuid of [ playlistUUID, playlistShortUUID ]) { - const body = await command.advancedPlaylistSearch({ search: { uuids: [ uuid ] } }) - - expect(body.total).to.equal(1) - expect(body.data[0].displayName).to.equal('Dr. Kenzo Tenma hospital videos') - } - - { - const body = await command.advancedPlaylistSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should not display playlists without videos', async function () { - const search = { - search: 'Lunge', - start: 0, - count: 1 - } - const body = await command.advancedPlaylistSearch({ search }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests([ server, remoteServer ]) - }) -}) diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts deleted file mode 100644 index f7f50147d..000000000 --- a/server/tests/api/search/search-videos.ts +++ /dev/null @@ -1,568 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - doubleFollow, - PeerTubeServer, - SearchCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - setDefaultVideoChannel, - stopFfmpeg -} from '@shared/server-commands' - -describe('Test videos search', function () { - let server: PeerTubeServer - let remoteServer: PeerTubeServer - let startDate: string - let videoUUID: string - let videoShortUUID: string - - let command: SearchCommand - - before(async function () { - this.timeout(360000) - - const servers = await Promise.all([ - createSingleServer(1), - createSingleServer(2) - ]) - server = servers[0] - remoteServer = servers[1] - - await setAccessTokensToServers([ server, remoteServer ]) - await setDefaultVideoChannel([ server, remoteServer ]) - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(servers) - - { - const attributes1 = { - name: '1111 2222 3333', - fixture: '60fps_720p_small.mp4', // 2 seconds - category: 1, - licence: 1, - nsfw: false, - language: 'fr' - } - await server.videos.upload({ attributes: attributes1 }) - - const attributes2 = { ...attributes1, name: attributes1.name + ' - 2', fixture: 'video_short.mp4' } - await server.videos.upload({ attributes: attributes2 }) - - { - const attributes3 = { ...attributes1, name: attributes1.name + ' - 3', language: undefined } - const { id, uuid, shortUUID } = await server.videos.upload({ attributes: attributes3 }) - videoUUID = uuid - videoShortUUID = shortUUID - - await server.captions.add({ - language: 'en', - videoId: id, - fixture: 'subtitle-good2.vtt', - mimeType: 'application/octet-stream' - }) - - await server.captions.add({ - language: 'aa', - videoId: id, - fixture: 'subtitle-good2.vtt', - mimeType: 'application/octet-stream' - }) - } - - const attributes4 = { ...attributes1, name: attributes1.name + ' - 4', language: 'pl', nsfw: true } - await server.videos.upload({ attributes: attributes4 }) - - await wait(1000) - - startDate = new Date().toISOString() - - const attributes5 = { ...attributes1, name: attributes1.name + ' - 5', licence: 2, language: undefined } - await server.videos.upload({ attributes: attributes5 }) - - const attributes6 = { ...attributes1, name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] } - await server.videos.upload({ attributes: attributes6 }) - - const attributes7 = { ...attributes1, name: attributes1.name + ' - 7', originallyPublishedAt: '2019-02-12T09:58:08.286Z' } - await server.videos.upload({ attributes: attributes7 }) - - const attributes8 = { ...attributes1, name: attributes1.name + ' - 8', licence: 4 } - await server.videos.upload({ attributes: attributes8 }) - } - - { - const attributes = { - name: '3333 4444 5555', - fixture: 'video_short.mp4', - category: 2, - licence: 2, - language: 'en' - } - await server.videos.upload({ attributes }) - - await server.videos.upload({ attributes: { ...attributes, name: attributes.name + ' duplicate' } }) - } - - { - const attributes = { - name: '6666 7777 8888', - fixture: 'video_short.mp4', - category: 3, - licence: 3, - language: 'pl' - } - await server.videos.upload({ attributes }) - } - - { - const attributes1 = { - name: '9999', - tags: [ 'aaaa', 'bbbb', 'cccc' ], - category: 1 - } - await server.videos.upload({ attributes: attributes1 }) - await server.videos.upload({ attributes: { ...attributes1, category: 2 } }) - - await server.videos.upload({ attributes: { ...attributes1, tags: [ 'cccc', 'dddd' ] } }) - await server.videos.upload({ attributes: { ...attributes1, tags: [ 'eeee', 'ffff' ] } }) - } - - { - const attributes1 = { - name: 'aaaa 2', - category: 1 - } - await server.videos.upload({ attributes: attributes1 }) - await server.videos.upload({ attributes: { ...attributes1, category: 2 } }) - } - - { - await remoteServer.videos.upload({ attributes: { name: 'remote video 1' } }) - await remoteServer.videos.upload({ attributes: { name: 'remote video 2' } }) - } - - await doubleFollow(server, remoteServer) - - command = server.search - }) - - it('Should make a simple search and not have results', async function () { - const body = await command.searchVideos({ search: 'abc' }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should make a simple search and have results', async function () { - const body = await command.searchVideos({ search: '4444 5555 duplicate' }) - - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - - // bestmatch - expect(videos[0].name).to.equal('3333 4444 5555 duplicate') - expect(videos[1].name).to.equal('3333 4444 5555') - }) - - it('Should make a search on tags too, and have results', async function () { - const search = { - search: 'aaaa', - categoryOneOf: [ 1 ] - } - const body = await command.advancedVideoSearch({ search }) - - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - - // bestmatch - expect(videos[0].name).to.equal('aaaa 2') - expect(videos[1].name).to.equal('9999') - }) - - it('Should filter on tags without a search', async function () { - const search = { - tagsAllOf: [ 'bbbb' ] - } - const body = await command.advancedVideoSearch({ search }) - - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - - expect(videos[0].name).to.equal('9999') - expect(videos[1].name).to.equal('9999') - }) - - it('Should filter on category without a search', async function () { - const search = { - categoryOneOf: [ 3 ] - } - const body = await command.advancedVideoSearch({ search }) - - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - - expect(videos[0].name).to.equal('6666 7777 8888') - }) - - it('Should search by tags (one of)', async function () { - const query = { - search: '9999', - categoryOneOf: [ 1 ], - tagsOneOf: [ 'aAaa', 'ffff' ] - } - - { - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(2) - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, tagsOneOf: [ 'blabla' ] } }) - expect(body.total).to.equal(0) - } - }) - - it('Should search by tags (all of)', async function () { - const query = { - search: '9999', - categoryOneOf: [ 1 ], - tagsAllOf: [ 'CCcc' ] - } - - { - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(2) - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'blAbla' ] } }) - expect(body.total).to.equal(0) - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'bbbb', 'CCCC' ] } }) - expect(body.total).to.equal(1) - } - }) - - it('Should search by category', async function () { - const query = { - search: '6666', - categoryOneOf: [ 3 ] - } - - { - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('6666 7777 8888') - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, categoryOneOf: [ 2 ] } }) - expect(body.total).to.equal(0) - } - }) - - it('Should search by licence', async function () { - const query = { - search: '4444 5555', - licenceOneOf: [ 2 ] - } - - { - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(2) - expect(body.data[0].name).to.equal('3333 4444 5555') - expect(body.data[1].name).to.equal('3333 4444 5555 duplicate') - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, licenceOneOf: [ 3 ] } }) - expect(body.total).to.equal(0) - } - }) - - it('Should search by languages', async function () { - const query = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'en' ] - } - - { - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(2) - expect(body.data[0].name).to.equal('1111 2222 3333 - 3') - expect(body.data[1].name).to.equal('1111 2222 3333 - 4') - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'pl', 'en', '_unknown' ] } }) - expect(body.total).to.equal(3) - expect(body.data[0].name).to.equal('1111 2222 3333 - 3') - expect(body.data[1].name).to.equal('1111 2222 3333 - 4') - expect(body.data[2].name).to.equal('1111 2222 3333 - 5') - } - - { - const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'eo' ] } }) - expect(body.total).to.equal(0) - } - }) - - it('Should search by start date', async function () { - const query = { - search: '1111 2222 3333', - startDate - } - - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos[0].name).to.equal('1111 2222 3333 - 5') - expect(videos[1].name).to.equal('1111 2222 3333 - 6') - expect(videos[2].name).to.equal('1111 2222 3333 - 7') - expect(videos[3].name).to.equal('1111 2222 3333 - 8') - }) - - it('Should make an advanced search', async function () { - const query = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'fr' ], - durationMax: 4, - nsfw: 'false' as 'false', - licenceOneOf: [ 1, 4 ] - } - - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos[0].name).to.equal('1111 2222 3333') - expect(videos[1].name).to.equal('1111 2222 3333 - 6') - expect(videos[2].name).to.equal('1111 2222 3333 - 7') - expect(videos[3].name).to.equal('1111 2222 3333 - 8') - }) - - it('Should make an advanced search and sort results', async function () { - const query = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'fr' ], - durationMax: 4, - nsfw: 'false' as 'false', - licenceOneOf: [ 1, 4 ], - sort: '-name' - } - - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos[0].name).to.equal('1111 2222 3333 - 8') - expect(videos[1].name).to.equal('1111 2222 3333 - 7') - expect(videos[2].name).to.equal('1111 2222 3333 - 6') - expect(videos[3].name).to.equal('1111 2222 3333') - }) - - it('Should make an advanced search and only show the first result', async function () { - const query = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'fr' ], - durationMax: 4, - nsfw: 'false' as 'false', - licenceOneOf: [ 1, 4 ], - sort: '-name', - start: 0, - count: 1 - } - - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos[0].name).to.equal('1111 2222 3333 - 8') - }) - - it('Should make an advanced search and only show the last result', async function () { - const query = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'fr' ], - durationMax: 4, - nsfw: 'false' as 'false', - licenceOneOf: [ 1, 4 ], - sort: '-name', - start: 3, - count: 1 - } - - const body = await command.advancedVideoSearch({ search: query }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos[0].name).to.equal('1111 2222 3333') - }) - - it('Should search on originally published date', async function () { - const baseQuery = { - search: '1111 2222 3333', - languageOneOf: [ 'pl', 'fr' ], - durationMax: 4, - nsfw: 'false' as 'false', - licenceOneOf: [ 1, 4 ] - } - - { - const query = { ...baseQuery, originallyPublishedStartDate: '2019-02-11T09:58:08.286Z' } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('1111 2222 3333 - 7') - } - - { - const query = { ...baseQuery, originallyPublishedEndDate: '2019-03-11T09:58:08.286Z' } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('1111 2222 3333 - 7') - } - - { - const query = { ...baseQuery, originallyPublishedEndDate: '2019-01-11T09:58:08.286Z' } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(0) - } - - { - const query = { ...baseQuery, originallyPublishedStartDate: '2019-03-11T09:58:08.286Z' } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(0) - } - - { - const query = { - ...baseQuery, - originallyPublishedStartDate: '2019-01-11T09:58:08.286Z', - originallyPublishedEndDate: '2019-01-10T09:58:08.286Z' - } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(0) - } - - { - const query = { - ...baseQuery, - originallyPublishedStartDate: '2019-01-11T09:58:08.286Z', - originallyPublishedEndDate: '2019-04-11T09:58:08.286Z' - } - const body = await command.advancedVideoSearch({ search: query }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('1111 2222 3333 - 7') - } - }) - - it('Should search by UUID', async function () { - const search = videoUUID - const body = await command.advancedVideoSearch({ search: { search } }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('1111 2222 3333 - 3') - }) - - it('Should filter by UUIDs', async function () { - for (const uuid of [ videoUUID, videoShortUUID ]) { - const body = await command.advancedVideoSearch({ search: { uuids: [ uuid ] } }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('1111 2222 3333 - 3') - } - - { - const body = await command.advancedVideoSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should search by host', async function () { - { - const body = await command.advancedVideoSearch({ search: { search: '6666 7777 8888', host: server.host } }) - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('6666 7777 8888') - } - - { - const body = await command.advancedVideoSearch({ search: { search: '1111', host: 'example.com' } }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await command.advancedVideoSearch({ search: { search: 'remote', host: remoteServer.host } }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - expect(body.data[0].name).to.equal('remote video 1') - expect(body.data[1].name).to.equal('remote video 2') - } - }) - - it('Should search by live', async function () { - this.timeout(120000) - - { - const newConfig = { - search: { - searchIndex: { enabled: false } - }, - live: { enabled: true } - } - await server.config.updateCustomSubConfig({ newConfig }) - } - - { - const body = await command.advancedVideoSearch({ search: { isLive: true } }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const liveCommand = server.live - - const liveAttributes = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.store.channel.id } - const live = await liveCommand.create({ fields: liveAttributes }) - - const ffmpegCommand = await liveCommand.sendRTMPStreamInVideo({ videoId: live.id }) - await liveCommand.waitUntilPublished({ videoId: live.id }) - - const body = await command.advancedVideoSearch({ search: { isLive: true } }) - - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('live') - - await stopFfmpeg(ffmpegCommand) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts deleted file mode 100644 index 6ce1a3799..000000000 --- a/server/tests/api/server/auto-follows.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockInstancesIndex } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { cleanupTests, createMultipleServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' - -async function checkFollow (follower: PeerTubeServer, following: PeerTubeServer, exists: boolean) { - { - const body = await following.follows.getFollowers({ start: 0, count: 5, sort: '-createdAt' }) - const follow = body.data.find(f => f.follower.host === follower.host && f.state === 'accepted') - - if (exists === true) expect(follow, `Follower ${follower.url} should exist on ${following.url}`).to.exist - else expect(follow, `Follower ${follower.url} should not exist on ${following.url}`).to.be.undefined - } - - { - const body = await follower.follows.getFollowings({ start: 0, count: 5, sort: '-createdAt' }) - const follow = body.data.find(f => f.following.host === following.host && f.state === 'accepted') - - if (exists === true) expect(follow, `Following ${following.url} should exist on ${follower.url}`).to.exist - else expect(follow, `Following ${following.url} should not exist on ${follower.url}`).to.be.undefined - } -} - -async function server1Follows2 (servers: PeerTubeServer[]) { - await servers[0].follows.follow({ hosts: [ servers[1].host ] }) - - await waitJobs(servers) -} - -async function resetFollows (servers: PeerTubeServer[]) { - try { - await servers[0].follows.unfollow({ target: servers[1] }) - await servers[1].follows.unfollow({ target: servers[0] }) - } catch { /* empty */ - } - - await waitJobs(servers) - - await checkFollow(servers[0], servers[1], false) - await checkFollow(servers[1], servers[0], false) -} - -describe('Test auto follows', function () { - let servers: PeerTubeServer[] = [] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - }) - - describe('Auto follow back', function () { - - it('Should not auto follow back if the option is not enabled', async function () { - this.timeout(15000) - - await server1Follows2(servers) - - await checkFollow(servers[0], servers[1], true) - await checkFollow(servers[1], servers[0], false) - - await resetFollows(servers) - }) - - it('Should auto follow back on auto accept if the option is enabled', async function () { - this.timeout(15000) - - const config = { - followings: { - instance: { - autoFollowBack: { enabled: true } - } - } - } - await servers[1].config.updateCustomSubConfig({ newConfig: config }) - - await server1Follows2(servers) - - await checkFollow(servers[0], servers[1], true) - await checkFollow(servers[1], servers[0], true) - - await resetFollows(servers) - }) - - it('Should wait the acceptation before auto follow back', async function () { - this.timeout(30000) - - const config = { - followings: { - instance: { - autoFollowBack: { enabled: true } - } - }, - followers: { - instance: { - manualApproval: true - } - } - } - await servers[1].config.updateCustomSubConfig({ newConfig: config }) - - await server1Follows2(servers) - - await checkFollow(servers[0], servers[1], false) - await checkFollow(servers[1], servers[0], false) - - await servers[1].follows.acceptFollower({ follower: 'peertube@' + servers[0].host }) - await waitJobs(servers) - - await checkFollow(servers[0], servers[1], true) - await checkFollow(servers[1], servers[0], true) - - await resetFollows(servers) - - config.followings.instance.autoFollowBack.enabled = false - config.followers.instance.manualApproval = false - await servers[1].config.updateCustomSubConfig({ newConfig: config }) - }) - }) - - describe('Auto follow index', function () { - const instanceIndexServer = new MockInstancesIndex() - let port: number - - before(async function () { - port = await instanceIndexServer.initialize() - }) - - it('Should not auto follow index if the option is not enabled', async function () { - this.timeout(30000) - - await wait(5000) - await waitJobs(servers) - - await checkFollow(servers[0], servers[1], false) - await checkFollow(servers[1], servers[0], false) - }) - - it('Should auto follow the index', async function () { - this.timeout(30000) - - instanceIndexServer.addInstance(servers[1].host) - - const config = { - followings: { - instance: { - autoFollowIndex: { - indexUrl: `http://127.0.0.1:${port}/api/v1/instances/hosts`, - enabled: true - } - } - } - } - await servers[0].config.updateCustomSubConfig({ newConfig: config }) - - await wait(5000) - await waitJobs(servers) - - await checkFollow(servers[0], servers[1], true) - - await resetFollows(servers) - }) - - it('Should follow new added instances in the index but not old ones', async function () { - this.timeout(30000) - - instanceIndexServer.addInstance(servers[2].host) - - await wait(5000) - await waitJobs(servers) - - await checkFollow(servers[0], servers[1], false) - await checkFollow(servers[0], servers[2], true) - }) - - after(async function () { - await instanceIndexServer.terminate() - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/bulk.ts b/server/tests/api/server/bulk.ts deleted file mode 100644 index 66d791a0f..000000000 --- a/server/tests/api/server/bulk.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - BulkCommand, - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test bulk actions', function () { - const commentsUser3: { videoId: number, commentId: number }[] = [] - - let servers: PeerTubeServer[] = [] - let user1Token: string - let user2Token: string - let user3Token: string - - let bulkCommand: BulkCommand - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - - { - const user = { username: 'user1', password: 'password' } - await servers[0].users.create({ username: user.username, password: user.password }) - - user1Token = await servers[0].login.getAccessToken(user) - } - - { - const user = { username: 'user2', password: 'password' } - await servers[0].users.create({ username: user.username, password: user.password }) - - user2Token = await servers[0].login.getAccessToken(user) - } - - { - const user = { username: 'user3', password: 'password' } - await servers[1].users.create({ username: user.username, password: user.password }) - - user3Token = await servers[1].login.getAccessToken(user) - } - - await doubleFollow(servers[0], servers[1]) - - bulkCommand = new BulkCommand(servers[0]) - }) - - describe('Bulk remove comments', function () { - async function checkInstanceCommentsRemoved () { - { - const { data } = await servers[0].videos.list() - - // Server 1 should not have these comments anymore - for (const video of data) { - const { data } = await servers[0].comments.listThreads({ videoId: video.id }) - const comment = data.find(c => c.text === 'comment by user 3') - - expect(comment).to.not.exist - } - } - - { - const { data } = await servers[1].videos.list() - - // Server 1 should not have these comments on videos of server 1 - for (const video of data) { - const { data } = await servers[1].comments.listThreads({ videoId: video.id }) - const comment = data.find(c => c.text === 'comment by user 3') - - if (video.account.host === servers[0].host) { - expect(comment).to.not.exist - } else { - expect(comment).to.exist - } - } - } - } - - before(async function () { - this.timeout(240000) - - await servers[0].videos.upload({ attributes: { name: 'video 1 server 1' } }) - await servers[0].videos.upload({ attributes: { name: 'video 2 server 1' } }) - await servers[0].videos.upload({ token: user1Token, attributes: { name: 'video 3 server 1' } }) - - await servers[1].videos.upload({ attributes: { name: 'video 1 server 2' } }) - - await waitJobs(servers) - - { - const { data } = await servers[0].videos.list() - for (const video of data) { - await servers[0].comments.createThread({ videoId: video.id, text: 'comment by root server 1' }) - await servers[0].comments.createThread({ token: user1Token, videoId: video.id, text: 'comment by user 1' }) - await servers[0].comments.createThread({ token: user2Token, videoId: video.id, text: 'comment by user 2' }) - } - } - - { - const { data } = await servers[1].videos.list() - - for (const video of data) { - await servers[1].comments.createThread({ videoId: video.id, text: 'comment by root server 2' }) - - const comment = await servers[1].comments.createThread({ token: user3Token, videoId: video.id, text: 'comment by user 3' }) - commentsUser3.push({ videoId: video.id, commentId: comment.id }) - } - } - - await waitJobs(servers) - }) - - it('Should delete comments of an account on my videos', async function () { - this.timeout(60000) - - await bulkCommand.removeCommentsOf({ - token: user1Token, - attributes: { - accountName: 'user2', - scope: 'my-videos' - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - for (const video of data) { - const { data } = await server.comments.listThreads({ videoId: video.id }) - const comment = data.find(c => c.text === 'comment by user 2') - - if (video.name === 'video 3 server 1') expect(comment).to.not.exist - else expect(comment).to.exist - } - } - }) - - it('Should delete comments of an account on the instance', async function () { - this.timeout(60000) - - await bulkCommand.removeCommentsOf({ - attributes: { - accountName: 'user3@' + servers[1].host, - scope: 'instance' - } - }) - - await waitJobs(servers) - - await checkInstanceCommentsRemoved() - }) - - it('Should not re create the comment on video update', async function () { - this.timeout(60000) - - for (const obj of commentsUser3) { - await servers[1].comments.addReply({ - token: user3Token, - videoId: obj.videoId, - toCommentId: obj.commentId, - text: 'comment by user 3 bis' - }) - } - - await waitJobs(servers) - - await checkInstanceCommentsRemoved() - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/config-defaults.ts b/server/tests/api/server/config-defaults.ts deleted file mode 100644 index 041032f2b..000000000 --- a/server/tests/api/server/config-defaults.ts +++ /dev/null @@ -1,288 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FIXTURE_URLS } from '@server/tests/shared' -import { VideoDetails, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' - -describe('Test config defaults', function () { - let server: PeerTubeServer - let channelId: number - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - channelId = server.store.channel.id - }) - - describe('Default publish values', function () { - - before(async function () { - const overrideConfig = { - defaults: { - publish: { - comments_enabled: false, - download_enabled: false, - privacy: VideoPrivacy.INTERNAL, - licence: 4 - } - } - } - - await server.kill() - await server.run(overrideConfig) - }) - - const attributes = { - name: 'video', - downloadEnabled: undefined, - commentsEnabled: undefined, - licence: undefined, - privacy: VideoPrivacy.PUBLIC // Privacy is mandatory for server - } - - function checkVideo (video: VideoDetails) { - expect(video.downloadEnabled).to.be.false - expect(video.commentsEnabled).to.be.false - expect(video.licence.id).to.equal(4) - } - - before(async function () { - await server.config.disableTranscoding() - await server.config.enableImports() - await server.config.enableLive({ allowReplay: false, transcoding: false }) - }) - - it('Should have the correct server configuration', async function () { - const config = await server.config.getConfig() - - expect(config.defaults.publish.commentsEnabled).to.be.false - expect(config.defaults.publish.downloadEnabled).to.be.false - expect(config.defaults.publish.licence).to.equal(4) - expect(config.defaults.publish.privacy).to.equal(VideoPrivacy.INTERNAL) - }) - - it('Should respect default values when uploading a video', async function () { - for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) { - const { id } = await server.videos.upload({ attributes, mode }) - - const video = await server.videos.get({ id }) - checkVideo(video) - } - }) - - it('Should respect default values when importing a video using URL', async function () { - const { video: { id } } = await server.imports.importVideo({ - attributes: { - ...attributes, - channelId, - targetUrl: FIXTURE_URLS.goodVideo - } - }) - - const video = await server.videos.get({ id }) - checkVideo(video) - }) - - it('Should respect default values when importing a video using magnet URI', async function () { - const { video: { id } } = await server.imports.importVideo({ - attributes: { - ...attributes, - channelId, - magnetUri: FIXTURE_URLS.magnet - } - }) - - const video = await server.videos.get({ id }) - checkVideo(video) - }) - - it('Should respect default values when creating a live', async function () { - const { id } = await server.live.create({ - fields: { - ...attributes, - channelId - } - }) - - const video = await server.videos.get({ id }) - checkVideo(video) - }) - }) - - describe('Default P2P values', function () { - - describe('Webapp default value', function () { - - before(async function () { - const overrideConfig = { - defaults: { - p2p: { - webapp: { - enabled: false - } - } - } - } - - await server.kill() - await server.run(overrideConfig) - }) - - it('Should have appropriate P2P config', async function () { - const config = await server.config.getConfig() - - expect(config.defaults.p2p.webapp.enabled).to.be.false - expect(config.defaults.p2p.embed.enabled).to.be.true - }) - - it('Should create a user with this default setting', async function () { - await server.users.create({ username: 'user_p2p_1' }) - const userToken = await server.login.getAccessToken('user_p2p_1') - - const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(p2pEnabled).to.be.false - }) - - it('Should register a user with this default setting', async function () { - await server.registrations.register({ username: 'user_p2p_2' }) - - const userToken = await server.login.getAccessToken('user_p2p_2') - - const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(p2pEnabled).to.be.false - }) - }) - - describe('Embed default value', function () { - - before(async function () { - const overrideConfig = { - defaults: { - p2p: { - embed: { - enabled: false - } - } - }, - signup: { - limit: 15 - } - } - - await server.kill() - await server.run(overrideConfig) - }) - - it('Should have appropriate P2P config', async function () { - const config = await server.config.getConfig() - - expect(config.defaults.p2p.webapp.enabled).to.be.true - expect(config.defaults.p2p.embed.enabled).to.be.false - }) - - it('Should create a user with this default setting', async function () { - await server.users.create({ username: 'user_p2p_3' }) - const userToken = await server.login.getAccessToken('user_p2p_3') - - const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(p2pEnabled).to.be.true - }) - - it('Should register a user with this default setting', async function () { - await server.registrations.register({ username: 'user_p2p_4' }) - - const userToken = await server.login.getAccessToken('user_p2p_4') - - const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(p2pEnabled).to.be.true - }) - }) - }) - - describe('Default user attributes', function () { - it('Should create a user and register a user with the default config', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - user: { - history: { - videos: { - enabled: true - } - }, - videoQuota : -1, - videoQuotaDaily: -1 - }, - signup: { - enabled: true, - requiresApproval: false - } - } - }) - - const config = await server.config.getConfig() - - expect(config.user.videoQuota).to.equal(-1) - expect(config.user.videoQuotaDaily).to.equal(-1) - - const user1Token = await server.users.generateUserAndToken('user1') - const user1 = await server.users.getMyInfo({ token: user1Token }) - - const user = { displayName: 'super user 2', username: 'user2', password: 'super password' } - const channel = { name: 'my_user_2_channel', displayName: 'my channel' } - await server.registrations.register({ ...user, channel }) - const user2Token = await server.login.getAccessToken(user) - const user2 = await server.users.getMyInfo({ token: user2Token }) - - for (const user of [ user1, user2 ]) { - expect(user.videosHistoryEnabled).to.be.true - expect(user.videoQuota).to.equal(-1) - expect(user.videoQuotaDaily).to.equal(-1) - } - }) - - it('Should update config and create a user and register a user with the new default config', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - user: { - history: { - videos: { - enabled: false - } - }, - videoQuota : 5242881, - videoQuotaDaily: 318742 - }, - signup: { - enabled: true, - requiresApproval: false - } - } - }) - - const user3Token = await server.users.generateUserAndToken('user3') - const user3 = await server.users.getMyInfo({ token: user3Token }) - - const user = { displayName: 'super user 4', username: 'user4', password: 'super password' } - const channel = { name: 'my_user_4_channel', displayName: 'my channel' } - await server.registrations.register({ ...user, channel }) - const user4Token = await server.login.getAccessToken(user) - const user4 = await server.users.getMyInfo({ token: user4Token }) - - for (const user of [ user3, user4 ]) { - expect(user.videosHistoryEnabled).to.be.false - expect(user.videoQuota).to.equal(5242881) - expect(user.videoQuotaDaily).to.equal(318742) - } - }) - - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts deleted file mode 100644 index a614d92d2..000000000 --- a/server/tests/api/server/config.ts +++ /dev/null @@ -1,645 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { parallelTests } from '@shared/core-utils' -import { CustomConfig, HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - killallServers, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' - -function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) { - expect(data.instance.name).to.equal('PeerTube') - expect(data.instance.shortDescription).to.equal( - 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' - ) - expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') - - expect(data.instance.terms).to.equal('No terms for now.') - expect(data.instance.creationReason).to.be.empty - expect(data.instance.codeOfConduct).to.be.empty - expect(data.instance.moderationInformation).to.be.empty - expect(data.instance.administrator).to.be.empty - expect(data.instance.maintenanceLifetime).to.be.empty - expect(data.instance.businessModel).to.be.empty - expect(data.instance.hardwareInformation).to.be.empty - - expect(data.instance.languages).to.have.lengthOf(0) - expect(data.instance.categories).to.have.lengthOf(0) - - expect(data.instance.defaultClientRoute).to.equal('/videos/trending') - expect(data.instance.isNSFW).to.be.false - expect(data.instance.defaultNSFWPolicy).to.equal('display') - expect(data.instance.customizations.css).to.be.empty - expect(data.instance.customizations.javascript).to.be.empty - - expect(data.services.twitter.username).to.equal('@Chocobozzz') - expect(data.services.twitter.whitelisted).to.be.false - - expect(data.client.videos.miniature.preferAuthorDisplayName).to.be.false - expect(data.client.menu.login.redirectOnSingleExternalAuth).to.be.false - - expect(data.cache.previews.size).to.equal(1) - expect(data.cache.captions.size).to.equal(1) - expect(data.cache.torrents.size).to.equal(1) - expect(data.cache.storyboards.size).to.equal(1) - - expect(data.signup.enabled).to.be.true - expect(data.signup.limit).to.equal(4) - expect(data.signup.minimumAge).to.equal(16) - expect(data.signup.requiresApproval).to.be.false - expect(data.signup.requiresEmailVerification).to.be.false - - expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com') - expect(data.contactForm.enabled).to.be.true - - expect(data.user.history.videos.enabled).to.be.true - expect(data.user.videoQuota).to.equal(5242880) - expect(data.user.videoQuotaDaily).to.equal(-1) - - expect(data.videoChannels.maxPerUser).to.equal(20) - - expect(data.transcoding.enabled).to.be.false - expect(data.transcoding.remoteRunners.enabled).to.be.false - expect(data.transcoding.allowAdditionalExtensions).to.be.false - expect(data.transcoding.allowAudioFiles).to.be.false - expect(data.transcoding.threads).to.equal(2) - expect(data.transcoding.concurrency).to.equal(2) - expect(data.transcoding.profile).to.equal('default') - expect(data.transcoding.resolutions['144p']).to.be.false - expect(data.transcoding.resolutions['240p']).to.be.true - expect(data.transcoding.resolutions['360p']).to.be.true - expect(data.transcoding.resolutions['480p']).to.be.true - expect(data.transcoding.resolutions['720p']).to.be.true - expect(data.transcoding.resolutions['1080p']).to.be.true - expect(data.transcoding.resolutions['1440p']).to.be.true - expect(data.transcoding.resolutions['2160p']).to.be.true - expect(data.transcoding.alwaysTranscodeOriginalResolution).to.be.true - expect(data.transcoding.webVideos.enabled).to.be.true - expect(data.transcoding.hls.enabled).to.be.true - - expect(data.live.enabled).to.be.false - expect(data.live.allowReplay).to.be.false - expect(data.live.latencySetting.enabled).to.be.true - expect(data.live.maxDuration).to.equal(-1) - expect(data.live.maxInstanceLives).to.equal(20) - expect(data.live.maxUserLives).to.equal(3) - expect(data.live.transcoding.enabled).to.be.false - expect(data.live.transcoding.remoteRunners.enabled).to.be.false - expect(data.live.transcoding.threads).to.equal(2) - expect(data.live.transcoding.profile).to.equal('default') - expect(data.live.transcoding.resolutions['144p']).to.be.false - expect(data.live.transcoding.resolutions['240p']).to.be.false - expect(data.live.transcoding.resolutions['360p']).to.be.false - expect(data.live.transcoding.resolutions['480p']).to.be.false - expect(data.live.transcoding.resolutions['720p']).to.be.false - expect(data.live.transcoding.resolutions['1080p']).to.be.false - expect(data.live.transcoding.resolutions['1440p']).to.be.false - expect(data.live.transcoding.resolutions['2160p']).to.be.false - expect(data.live.transcoding.alwaysTranscodeOriginalResolution).to.be.true - - expect(data.videoStudio.enabled).to.be.false - expect(data.videoStudio.remoteRunners.enabled).to.be.false - - expect(data.videoFile.update.enabled).to.be.false - - expect(data.import.videos.concurrency).to.equal(2) - expect(data.import.videos.http.enabled).to.be.true - expect(data.import.videos.torrent.enabled).to.be.true - expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.false - - expect(data.followers.instance.enabled).to.be.true - expect(data.followers.instance.manualApproval).to.be.false - - expect(data.followings.instance.autoFollowBack.enabled).to.be.false - expect(data.followings.instance.autoFollowIndex.enabled).to.be.false - expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('') - - expect(data.broadcastMessage.enabled).to.be.false - expect(data.broadcastMessage.level).to.equal('info') - expect(data.broadcastMessage.message).to.equal('') - expect(data.broadcastMessage.dismissable).to.be.false -} - -function checkUpdatedConfig (data: CustomConfig) { - expect(data.instance.name).to.equal('PeerTube updated') - expect(data.instance.shortDescription).to.equal('my short description') - expect(data.instance.description).to.equal('my super description') - - expect(data.instance.terms).to.equal('my super terms') - expect(data.instance.creationReason).to.equal('my super creation reason') - expect(data.instance.codeOfConduct).to.equal('my super coc') - expect(data.instance.moderationInformation).to.equal('my super moderation information') - expect(data.instance.administrator).to.equal('Kuja') - expect(data.instance.maintenanceLifetime).to.equal('forever') - expect(data.instance.businessModel).to.equal('my super business model') - expect(data.instance.hardwareInformation).to.equal('2vCore 3GB RAM') - - expect(data.instance.languages).to.deep.equal([ 'en', 'es' ]) - expect(data.instance.categories).to.deep.equal([ 1, 2 ]) - - expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added') - expect(data.instance.isNSFW).to.be.true - expect(data.instance.defaultNSFWPolicy).to.equal('blur') - expect(data.instance.customizations.javascript).to.equal('alert("coucou")') - expect(data.instance.customizations.css).to.equal('body { background-color: red; }') - - expect(data.services.twitter.username).to.equal('@Kuja') - expect(data.services.twitter.whitelisted).to.be.true - - expect(data.client.videos.miniature.preferAuthorDisplayName).to.be.true - expect(data.client.menu.login.redirectOnSingleExternalAuth).to.be.true - - expect(data.cache.previews.size).to.equal(2) - expect(data.cache.captions.size).to.equal(3) - expect(data.cache.torrents.size).to.equal(4) - expect(data.cache.storyboards.size).to.equal(5) - - expect(data.signup.enabled).to.be.false - expect(data.signup.limit).to.equal(5) - expect(data.signup.requiresApproval).to.be.false - expect(data.signup.requiresEmailVerification).to.be.false - expect(data.signup.minimumAge).to.equal(10) - - // We override admin email in parallel tests, so skip this exception - if (parallelTests() === false) { - expect(data.admin.email).to.equal('superadmin1@example.com') - } - - expect(data.contactForm.enabled).to.be.false - - expect(data.user.history.videos.enabled).to.be.false - expect(data.user.videoQuota).to.equal(5242881) - expect(data.user.videoQuotaDaily).to.equal(318742) - - expect(data.videoChannels.maxPerUser).to.equal(24) - - expect(data.transcoding.enabled).to.be.true - expect(data.transcoding.remoteRunners.enabled).to.be.true - expect(data.transcoding.threads).to.equal(1) - expect(data.transcoding.concurrency).to.equal(3) - expect(data.transcoding.allowAdditionalExtensions).to.be.true - expect(data.transcoding.allowAudioFiles).to.be.true - expect(data.transcoding.profile).to.equal('vod_profile') - expect(data.transcoding.resolutions['144p']).to.be.false - expect(data.transcoding.resolutions['240p']).to.be.false - expect(data.transcoding.resolutions['360p']).to.be.true - expect(data.transcoding.resolutions['480p']).to.be.true - expect(data.transcoding.resolutions['720p']).to.be.false - expect(data.transcoding.resolutions['1080p']).to.be.false - expect(data.transcoding.resolutions['2160p']).to.be.false - expect(data.transcoding.alwaysTranscodeOriginalResolution).to.be.false - expect(data.transcoding.hls.enabled).to.be.false - expect(data.transcoding.webVideos.enabled).to.be.true - - expect(data.live.enabled).to.be.true - expect(data.live.allowReplay).to.be.true - expect(data.live.latencySetting.enabled).to.be.false - expect(data.live.maxDuration).to.equal(5000) - expect(data.live.maxInstanceLives).to.equal(-1) - expect(data.live.maxUserLives).to.equal(10) - expect(data.live.transcoding.enabled).to.be.true - expect(data.live.transcoding.remoteRunners.enabled).to.be.true - expect(data.live.transcoding.threads).to.equal(4) - expect(data.live.transcoding.profile).to.equal('live_profile') - expect(data.live.transcoding.resolutions['144p']).to.be.true - expect(data.live.transcoding.resolutions['240p']).to.be.true - expect(data.live.transcoding.resolutions['360p']).to.be.true - expect(data.live.transcoding.resolutions['480p']).to.be.true - expect(data.live.transcoding.resolutions['720p']).to.be.true - expect(data.live.transcoding.resolutions['1080p']).to.be.true - expect(data.live.transcoding.resolutions['2160p']).to.be.true - expect(data.live.transcoding.alwaysTranscodeOriginalResolution).to.be.false - - expect(data.videoStudio.enabled).to.be.true - expect(data.videoStudio.remoteRunners.enabled).to.be.true - - expect(data.videoFile.update.enabled).to.be.true - - expect(data.import.videos.concurrency).to.equal(4) - expect(data.import.videos.http.enabled).to.be.false - expect(data.import.videos.torrent.enabled).to.be.false - expect(data.autoBlacklist.videos.ofUsers.enabled).to.be.true - - expect(data.followers.instance.enabled).to.be.false - expect(data.followers.instance.manualApproval).to.be.true - - expect(data.followings.instance.autoFollowBack.enabled).to.be.true - expect(data.followings.instance.autoFollowIndex.enabled).to.be.true - expect(data.followings.instance.autoFollowIndex.indexUrl).to.equal('https://updated.example.com') - - expect(data.broadcastMessage.enabled).to.be.true - expect(data.broadcastMessage.level).to.equal('error') - expect(data.broadcastMessage.message).to.equal('super bad message') - expect(data.broadcastMessage.dismissable).to.be.true -} - -const newCustomConfig: CustomConfig = { - instance: { - name: 'PeerTube updated', - shortDescription: 'my short description', - description: 'my super description', - terms: 'my super terms', - codeOfConduct: 'my super coc', - - creationReason: 'my super creation reason', - moderationInformation: 'my super moderation information', - administrator: 'Kuja', - maintenanceLifetime: 'forever', - businessModel: 'my super business model', - hardwareInformation: '2vCore 3GB RAM', - - languages: [ 'en', 'es' ], - categories: [ 1, 2 ], - - isNSFW: true, - defaultNSFWPolicy: 'blur' as 'blur', - - defaultClientRoute: '/videos/recently-added', - - customizations: { - javascript: 'alert("coucou")', - css: 'body { background-color: red; }' - } - }, - theme: { - default: 'default' - }, - services: { - twitter: { - username: '@Kuja', - whitelisted: true - } - }, - client: { - videos: { - miniature: { - preferAuthorDisplayName: true - } - }, - menu: { - login: { - redirectOnSingleExternalAuth: true - } - } - }, - cache: { - previews: { - size: 2 - }, - captions: { - size: 3 - }, - torrents: { - size: 4 - }, - storyboards: { - size: 5 - } - }, - signup: { - enabled: false, - limit: 5, - requiresApproval: false, - requiresEmailVerification: false, - minimumAge: 10 - }, - admin: { - email: 'superadmin1@example.com' - }, - contactForm: { - enabled: false - }, - user: { - history: { - videos: { - enabled: false - } - }, - videoQuota: 5242881, - videoQuotaDaily: 318742 - }, - videoChannels: { - maxPerUser: 24 - }, - transcoding: { - enabled: true, - remoteRunners: { - enabled: true - }, - allowAdditionalExtensions: true, - allowAudioFiles: true, - threads: 1, - concurrency: 3, - profile: 'vod_profile', - resolutions: { - '0p': false, - '144p': false, - '240p': false, - '360p': true, - '480p': true, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - alwaysTranscodeOriginalResolution: false, - webVideos: { - enabled: true - }, - hls: { - enabled: false - } - }, - live: { - enabled: true, - allowReplay: true, - latencySetting: { - enabled: false - }, - maxDuration: 5000, - maxInstanceLives: -1, - maxUserLives: 10, - transcoding: { - enabled: true, - remoteRunners: { - enabled: true - }, - threads: 4, - profile: 'live_profile', - resolutions: { - '144p': true, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - }, - alwaysTranscodeOriginalResolution: false - } - }, - videoStudio: { - enabled: true, - remoteRunners: { - enabled: true - } - }, - videoFile: { - update: { - enabled: true - } - }, - import: { - videos: { - concurrency: 4, - http: { - enabled: false - }, - torrent: { - enabled: false - } - }, - videoChannelSynchronization: { - enabled: false, - maxPerUser: 10 - } - }, - trending: { - videos: { - algorithms: { - enabled: [ 'hot', 'most-viewed', 'most-liked' ], - default: 'hot' - } - } - }, - autoBlacklist: { - videos: { - ofUsers: { - enabled: true - } - } - }, - followers: { - instance: { - enabled: false, - manualApproval: true - } - }, - followings: { - instance: { - autoFollowBack: { - enabled: true - }, - autoFollowIndex: { - enabled: true, - indexUrl: 'https://updated.example.com' - } - } - }, - broadcastMessage: { - enabled: true, - level: 'error', - message: 'super bad message', - dismissable: true - }, - search: { - remoteUri: { - anonymous: true, - users: true - }, - searchIndex: { - enabled: true, - url: 'https://search.joinpeertube.org', - disableLocalSearch: true, - isDefaultSearch: true - } - } -} - -describe('Test static config', function () { - let server: PeerTubeServer = null - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { webadmin: { configuration: { edition: { allowed: false } } } }) - await setAccessTokensToServers([ server ]) - }) - - it('Should tell the client that edits are not allowed', async function () { - const data = await server.config.getConfig() - - expect(data.webadmin.configuration.edition.allowed).to.be.false - }) - - it('Should error when client tries to update', async function () { - await server.config.updateCustomConfig({ newCustomConfig, expectedStatus: 405 }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) - -describe('Test config', function () { - let server: PeerTubeServer = null - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - }) - - it('Should have a correct config on a server with registration enabled', async function () { - const data = await server.config.getConfig() - - expect(data.signup.allowed).to.be.true - }) - - it('Should have a correct config on a server with registration enabled and a users limit', async function () { - this.timeout(5000) - - await Promise.all([ - server.registrations.register({ username: 'user1' }), - server.registrations.register({ username: 'user2' }), - server.registrations.register({ username: 'user3' }) - ]) - - const data = await server.config.getConfig() - - expect(data.signup.allowed).to.be.false - }) - - it('Should have the correct video allowed extensions', async function () { - const data = await server.config.getConfig() - - expect(data.video.file.extensions).to.have.lengthOf(3) - expect(data.video.file.extensions).to.contain('.mp4') - expect(data.video.file.extensions).to.contain('.webm') - expect(data.video.file.extensions).to.contain('.ogv') - - await server.videos.upload({ attributes: { fixture: 'video_short.mkv' }, expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 }) - await server.videos.upload({ attributes: { fixture: 'sample.ogg' }, expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 }) - - expect(data.contactForm.enabled).to.be.true - }) - - it('Should get the customized configuration', async function () { - const data = await server.config.getCustomConfig() - - checkInitialConfig(server, data) - }) - - it('Should update the customized configuration', async function () { - await server.config.updateCustomConfig({ newCustomConfig }) - - const data = await server.config.getCustomConfig() - checkUpdatedConfig(data) - }) - - it('Should have the correct updated video allowed extensions', async function () { - this.timeout(30000) - - const data = await server.config.getConfig() - - expect(data.video.file.extensions).to.have.length.above(4) - expect(data.video.file.extensions).to.contain('.mp4') - expect(data.video.file.extensions).to.contain('.webm') - expect(data.video.file.extensions).to.contain('.ogv') - expect(data.video.file.extensions).to.contain('.flv') - expect(data.video.file.extensions).to.contain('.wmv') - expect(data.video.file.extensions).to.contain('.mkv') - expect(data.video.file.extensions).to.contain('.mp3') - expect(data.video.file.extensions).to.contain('.ogg') - expect(data.video.file.extensions).to.contain('.flac') - - await server.videos.upload({ attributes: { fixture: 'video_short.mkv' }, expectedStatus: HttpStatusCode.OK_200 }) - await server.videos.upload({ attributes: { fixture: 'sample.ogg' }, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should have the configuration updated after a restart', async function () { - this.timeout(30000) - - await killallServers([ server ]) - - await server.run() - - const data = await server.config.getCustomConfig() - - checkUpdatedConfig(data) - }) - - it('Should fetch the about information', async function () { - const data = await server.config.getAbout() - - expect(data.instance.name).to.equal('PeerTube updated') - expect(data.instance.shortDescription).to.equal('my short description') - expect(data.instance.description).to.equal('my super description') - expect(data.instance.terms).to.equal('my super terms') - expect(data.instance.codeOfConduct).to.equal('my super coc') - - expect(data.instance.creationReason).to.equal('my super creation reason') - expect(data.instance.moderationInformation).to.equal('my super moderation information') - expect(data.instance.administrator).to.equal('Kuja') - expect(data.instance.maintenanceLifetime).to.equal('forever') - expect(data.instance.businessModel).to.equal('my super business model') - expect(data.instance.hardwareInformation).to.equal('2vCore 3GB RAM') - - expect(data.instance.languages).to.deep.equal([ 'en', 'es' ]) - expect(data.instance.categories).to.deep.equal([ 1, 2 ]) - }) - - it('Should remove the custom configuration', async function () { - await server.config.deleteCustomConfig() - - const data = await server.config.getCustomConfig() - checkInitialConfig(server, data) - }) - - it('Should enable/disable security headers', async function () { - this.timeout(25000) - - { - const res = await makeGetRequest({ - url: server.url, - path: '/api/v1/config', - expectedStatus: 200 - }) - - expect(res.headers['x-frame-options']).to.exist - expect(res.headers['x-powered-by']).to.equal('PeerTube') - } - - await killallServers([ server ]) - - const config = { - security: { - frameguard: { enabled: false }, - powered_by_header: { enabled: false } - } - } - await server.run(config) - - { - const res = await makeGetRequest({ - url: server.url, - path: '/api/v1/config', - expectedStatus: 200 - }) - - expect(res.headers['x-frame-options']).to.not.exist - expect(res.headers['x-powered-by']).to.not.exist - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts deleted file mode 100644 index 0256cc193..000000000 --- a/server/tests/api/server/contact-form.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockSmtpServer } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - ContactFormCommand, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test contact form', function () { - let server: PeerTubeServer - const emails: object[] = [] - let command: ContactFormCommand - - before(async function () { - this.timeout(30000) - - const port = await MockSmtpServer.Instance.collectEmails(emails) - - server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(port)) - await setAccessTokensToServers([ server ]) - - command = server.contactForm - }) - - it('Should send a contact form', async function () { - await command.send({ - fromEmail: 'toto@example.com', - body: 'my super message', - subject: 'my subject', - fromName: 'Super toto' - }) - - await waitJobs(server) - - expect(emails).to.have.lengthOf(1) - - const email = emails[0] - - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['replyTo'][0]['address']).equal('toto@example.com') - expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com') - expect(email['subject']).contains('my subject') - expect(email['text']).contains('my super message') - }) - - it('Should not have duplicated email address in text message', async function () { - const text = emails[0]['text'] as string - - const matches = text.match(/toto@example.com/g) - expect(matches).to.have.lengthOf(1) - }) - - it('Should not be able to send another contact form because of the anti spam checker', async function () { - await wait(1000) - - await command.send({ - fromEmail: 'toto@example.com', - body: 'my super message', - subject: 'my subject', - fromName: 'Super toto' - }) - - await command.send({ - fromEmail: 'toto@example.com', - body: 'my super message', - fromName: 'Super toto', - subject: 'my subject', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should be able to send another contact form after a while', async function () { - await wait(1000) - - await command.send({ - fromEmail: 'toto@example.com', - fromName: 'Super toto', - subject: 'my subject', - body: 'my super message' - }) - }) - - it('Should not have the manage preferences link in the email', async function () { - const email = emails[0] - expect(email['text']).to.not.contain('Manage your notification preferences') - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts deleted file mode 100644 index 9141cc697..000000000 --- a/server/tests/api/server/email.ts +++ /dev/null @@ -1,371 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockSmtpServer } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test emails', function () { - let server: PeerTubeServer - let userId: number - let userId2: number - let userAccessToken: string - - let videoShortUUID: string - let videoId: number - - let videoUserUUID: string - - let verificationString: string - let verificationString2: string - - const emails: object[] = [] - const user = { - username: 'user_1', - password: 'super_password' - } - - before(async function () { - this.timeout(120000) - - const emailPort = await MockSmtpServer.Instance.collectEmails(emails) - server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(emailPort)) - - await setAccessTokensToServers([ server ]) - await server.config.enableSignup(true) - - { - const created = await server.users.create({ username: user.username, password: user.password }) - userId = created.id - - userAccessToken = await server.login.getAccessToken(user) - } - - { - const attributes = { name: 'my super user video' } - const { uuid } = await server.videos.upload({ token: userAccessToken, attributes }) - videoUserUUID = uuid - } - - { - const attributes = { - name: 'my super name' - } - const { shortUUID, id } = await server.videos.upload({ attributes }) - videoShortUUID = shortUUID - videoId = id - } - }) - - describe('When resetting user password', function () { - - it('Should ask to reset the password', async function () { - await server.users.askResetPassword({ email: 'user_1@example.com' }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(1) - - const email = emails[0] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains('password') - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString = verificationStringMatches[1] - expect(verificationString).to.have.length.above(2) - - const userIdMatches = /userId=([0-9]+)/.exec(email['text']) - expect(userIdMatches).not.to.be.null - - userId = parseInt(userIdMatches[1], 10) - expect(verificationString).to.not.be.undefined - }) - - it('Should not reset the password with an invalid verification string', async function () { - await server.users.resetPassword({ - userId, - verificationString: verificationString + 'b', - password: 'super_password2', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should reset the password', async function () { - await server.users.resetPassword({ userId, verificationString, password: 'super_password2' }) - }) - - it('Should not reset the password with the same verification string', async function () { - await server.users.resetPassword({ - userId, - verificationString, - password: 'super_password3', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should login with this new password', async function () { - user.password = 'super_password2' - - await server.login.getAccessToken(user) - }) - }) - - describe('When creating a user without password', function () { - - it('Should send a create password email', async function () { - await server.users.create({ username: 'create_password', password: '' }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(2) - - const email = emails[1] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('create_password@example.com') - expect(email['subject']).contains('account') - expect(email['subject']).contains('password') - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString2 = verificationStringMatches[1] - expect(verificationString2).to.have.length.above(2) - - const userIdMatches = /userId=([0-9]+)/.exec(email['text']) - expect(userIdMatches).not.to.be.null - - userId2 = parseInt(userIdMatches[1], 10) - }) - - it('Should not reset the password with an invalid verification string', async function () { - await server.users.resetPassword({ - userId: userId2, - verificationString: verificationString2 + 'c', - password: 'newly_created_password', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should reset the password', async function () { - await server.users.resetPassword({ - userId: userId2, - verificationString: verificationString2, - password: 'newly_created_password' - }) - }) - - it('Should login with this new password', async function () { - await server.login.getAccessToken({ - username: 'create_password', - password: 'newly_created_password' - }) - }) - }) - - describe('When creating an abuse', function () { - - it('Should send the notification email', async function () { - const reason = 'my super bad reason' - await server.abuses.report({ token: userAccessToken, videoId, reason }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(3) - - const email = emails[2] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com') - expect(email['subject']).contains('abuse') - expect(email['text']).contains(videoShortUUID) - }) - }) - - describe('When blocking/unblocking user', function () { - - it('Should send the notification email when blocking a user', async function () { - const reason = 'my super bad reason' - await server.users.banUser({ userId, reason }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(4) - - const email = emails[3] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' blocked') - expect(email['text']).contains(' blocked') - expect(email['text']).contains('bad reason') - }) - - it('Should send the notification email when unblocking a user', async function () { - await server.users.unbanUser({ userId }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(5) - - const email = emails[4] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' unblocked') - expect(email['text']).contains(' unblocked') - }) - }) - - describe('When blacklisting a video', function () { - it('Should send the notification email', async function () { - const reason = 'my super reason' - await server.blacklist.add({ videoId: videoUserUUID, reason }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(6) - - const email = emails[5] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' blacklisted') - expect(email['text']).contains('my super user video') - expect(email['text']).contains('my super reason') - }) - - it('Should send the notification email', async function () { - await server.blacklist.remove({ videoId: videoUserUUID }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(7) - - const email = emails[6] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains(' unblacklisted') - expect(email['text']).contains('my super user video') - }) - - it('Should have the manage preferences link in the email', async function () { - const email = emails[6] - expect(email['text']).to.contain('Manage your notification preferences') - }) - }) - - describe('When verifying a user email', function () { - - it('Should ask to send the verification email', async function () { - await server.users.askSendVerifyEmail({ email: 'user_1@example.com' }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(8) - - const email = emails[7] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('user_1@example.com') - expect(email['subject']).contains('Verify') - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString = verificationStringMatches[1] - expect(verificationString).to.not.be.undefined - expect(verificationString).to.have.length.above(2) - - const userIdMatches = /userId=([0-9]+)/.exec(email['text']) - expect(userIdMatches).not.to.be.null - - userId = parseInt(userIdMatches[1], 10) - }) - - it('Should not verify the email with an invalid verification string', async function () { - await server.users.verifyEmail({ - userId, - verificationString: verificationString + 'b', - isPendingEmail: false, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should verify the email', async function () { - await server.users.verifyEmail({ userId, verificationString }) - }) - }) - - describe('When verifying a registration email', function () { - let registrationId: number - let registrationIdEmail: number - - before(async function () { - const { id } = await server.registrations.requestRegistration({ - username: 'request_1', - email: 'request_1@example.com', - registrationReason: 'tt' - }) - registrationId = id - }) - - it('Should ask to send the verification email', async function () { - await server.registrations.askSendVerifyEmail({ email: 'request_1@example.com' }) - - await waitJobs(server) - expect(emails).to.have.lengthOf(9) - - const email = emails[8] - - expect(email['from'][0]['name']).equal('PeerTube') - expect(email['from'][0]['address']).equal('test-admin@127.0.0.1') - expect(email['to'][0]['address']).equal('request_1@example.com') - expect(email['subject']).contains('Verify') - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString = verificationStringMatches[1] - expect(verificationString).to.not.be.undefined - expect(verificationString).to.have.length.above(2) - - const registrationIdMatches = /registrationId=([0-9]+)/.exec(email['text']) - expect(registrationIdMatches).not.to.be.null - - registrationIdEmail = parseInt(registrationIdMatches[1], 10) - - expect(registrationId).to.equal(registrationIdEmail) - }) - - it('Should not verify the email with an invalid verification string', async function () { - await server.registrations.verifyEmail({ - registrationId: registrationIdEmail, - verificationString: verificationString + 'b', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should verify the email', async function () { - await server.registrations.verifyEmail({ registrationId: registrationIdEmail, verificationString }) - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts deleted file mode 100644 index ff5332858..000000000 --- a/server/tests/api/server/follow-constraints.ts +++ /dev/null @@ -1,321 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test follow constraints', function () { - let servers: PeerTubeServer[] = [] - let video1UUID: string - let video2UUID: string - let userToken: string - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - - { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video server 1' } }) - video1UUID = uuid - } - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video server 2' } }) - video2UUID = uuid - } - - const user = { - username: 'user1', - password: 'super_password' - } - await servers[0].users.create({ username: user.username, password: user.password }) - userToken = await servers[0].login.getAccessToken(user) - - await doubleFollow(servers[0], servers[1]) - }) - - describe('With a followed instance', function () { - - describe('With an unlogged user', function () { - - it('Should get the local video', async function () { - await servers[0].videos.get({ id: video1UUID }) - }) - - it('Should get the remote video', async function () { - await servers[0].videos.get({ id: video2UUID }) - }) - - it('Should list local account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ handle: 'root@' + servers[0].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ handle: 'root@' + servers[1].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list local channel videos', async function () { - const handle = 'root_channel@' + servers[0].host - const { total, data } = await servers[0].videos.listByChannel({ handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote channel videos', async function () { - const handle = 'root_channel@' + servers[1].host - const { total, data } = await servers[0].videos.listByChannel({ handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - }) - - describe('With a logged user', function () { - it('Should get the local video', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video1UUID }) - }) - - it('Should get the remote video', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - - it('Should list local account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ token: userToken, handle: 'root@' + servers[0].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ token: userToken, handle: 'root@' + servers[1].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list local channel videos', async function () { - const handle = 'root_channel@' + servers[0].host - const { total, data } = await servers[0].videos.listByChannel({ token: userToken, handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote channel videos', async function () { - const handle = 'root_channel@' + servers[1].host - const { total, data } = await servers[0].videos.listByChannel({ token: userToken, handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - }) - }) - - describe('With a non followed instance', function () { - - before(async function () { - this.timeout(30000) - - await servers[0].follows.unfollow({ target: servers[1] }) - }) - - describe('With an unlogged user', function () { - - it('Should get the local video', async function () { - await servers[0].videos.get({ id: video1UUID }) - }) - - it('Should not get the remote video', async function () { - const body = await servers[0].videos.get({ id: video2UUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - const error = body as unknown as PeerTubeProblemDocument - - const doc = 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints' - expect(error.type).to.equal(doc) - expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) - - expect(error.detail).to.equal('Cannot get this video regarding follow constraints') - expect(error.error).to.equal(error.detail) - - expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403) - - expect(error.originUrl).to.contains(servers[1].url) - }) - - it('Should list local account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ - token: null, - handle: 'root@' + servers[0].host - }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should not list remote account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ - token: null, - handle: 'root@' + servers[1].host - }) - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - }) - - it('Should list local channel videos', async function () { - const handle = 'root_channel@' + servers[0].host - const { total, data } = await servers[0].videos.listByChannel({ token: null, handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should not list remote channel videos', async function () { - const handle = 'root_channel@' + servers[1].host - const { total, data } = await servers[0].videos.listByChannel({ token: null, handle }) - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - }) - }) - - describe('With a logged user', function () { - - it('Should get the local video', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video1UUID }) - }) - - it('Should get the remote video', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - - it('Should list local account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ token: userToken, handle: 'root@' + servers[0].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote account videos', async function () { - const { total, data } = await servers[0].videos.listByAccount({ token: userToken, handle: 'root@' + servers[1].host }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list local channel videos', async function () { - const handle = 'root_channel@' + servers[0].host - const { total, data } = await servers[0].videos.listByChannel({ token: userToken, handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - it('Should list remote channel videos', async function () { - const handle = 'root_channel@' + servers[1].host - const { total, data } = await servers[0].videos.listByChannel({ token: userToken, handle }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - }) - }) - - describe('When following a remote account', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].follows.follow({ handles: [ 'root@' + servers[1].host ] }) - await waitJobs(servers) - }) - - it('Should get the remote video with an unlogged user', async function () { - await servers[0].videos.get({ id: video2UUID }) - }) - - it('Should get the remote video with a logged in user', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - }) - - describe('When unfollowing a remote account', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].follows.unfollow({ target: 'root@' + servers[1].host }) - await waitJobs(servers) - }) - - it('Should not get the remote video with an unlogged user', async function () { - const body = await servers[0].videos.get({ id: video2UUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - - const error = body as unknown as PeerTubeProblemDocument - expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) - }) - - it('Should get the remote video with a logged in user', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - }) - - describe('When following a remote channel', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].follows.follow({ handles: [ 'root_channel@' + servers[1].host ] }) - await waitJobs(servers) - }) - - it('Should get the remote video with an unlogged user', async function () { - await servers[0].videos.get({ id: video2UUID }) - }) - - it('Should get the remote video with a logged in user', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - }) - - describe('When unfollowing a remote channel', function () { - - before(async function () { - this.timeout(60000) - - await servers[0].follows.unfollow({ target: 'root_channel@' + servers[1].host }) - await waitJobs(servers) - }) - - it('Should not get the remote video with an unlogged user', async function () { - const body = await servers[0].videos.get({ id: video2UUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - - const error = body as unknown as PeerTubeProblemDocument - expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) - }) - - it('Should get the remote video with a logged in user', async function () { - await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts deleted file mode 100644 index d145dd9d2..000000000 --- a/server/tests/api/server/follows-moderation.ts +++ /dev/null @@ -1,364 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectStartWith } from '@server/tests/shared' -import { ActorFollow, FollowState } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - FollowsCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -async function checkServer1And2HasFollowers (servers: PeerTubeServer[], state = 'accepted') { - const fns = [ - servers[0].follows.getFollowings.bind(servers[0].follows), - servers[1].follows.getFollowers.bind(servers[1].follows) - ] - - for (const fn of fns) { - const body = await fn({ start: 0, count: 5, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const follow = body.data[0] - expect(follow.state).to.equal(state) - expect(follow.follower.url).to.equal(servers[0].url + '/accounts/peertube') - expect(follow.following.url).to.equal(servers[1].url + '/accounts/peertube') - } -} - -async function checkFollows (options: { - follower: PeerTubeServer - followerState: FollowState | 'deleted' - - following: PeerTubeServer - followingState: FollowState | 'deleted' -}) { - const { follower, followerState, followingState, following } = options - - const followerUrl = follower.url + '/accounts/peertube' - const followingUrl = following.url + '/accounts/peertube' - const finder = (d: ActorFollow) => d.follower.url === followerUrl && d.following.url === followingUrl - - { - const { data } = await follower.follows.getFollowings() - const follow = data.find(finder) - - if (followerState === 'deleted') { - expect(follow).to.not.exist - } else { - expect(follow.state).to.equal(followerState) - expect(follow.follower.url).to.equal(followerUrl) - expect(follow.following.url).to.equal(followingUrl) - } - } - - { - const { data } = await following.follows.getFollowers() - const follow = data.find(finder) - - if (followingState === 'deleted') { - expect(follow).to.not.exist - } else { - expect(follow.state).to.equal(followingState) - expect(follow.follower.url).to.equal(followerUrl) - expect(follow.following.url).to.equal(followingUrl) - } - } -} - -async function checkNoFollowers (servers: PeerTubeServer[]) { - const fns = [ - servers[0].follows.getFollowings.bind(servers[0].follows), - servers[1].follows.getFollowers.bind(servers[1].follows) - ] - - for (const fn of fns) { - const body = await fn({ start: 0, count: 5, sort: 'createdAt', state: 'accepted' }) - expect(body.total).to.equal(0) - } -} - -describe('Test follows moderation', function () { - let servers: PeerTubeServer[] = [] - let commands: FollowsCommand[] - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - - commands = servers.map(s => s.follows) - }) - - describe('Default behaviour', function () { - - it('Should have server 1 following server 2', async function () { - this.timeout(30000) - - await commands[0].follow({ hosts: [ servers[1].url ] }) - - await waitJobs(servers) - }) - - it('Should have correct follows', async function () { - await checkServer1And2HasFollowers(servers) - }) - - it('Should remove follower on server 2', async function () { - await commands[1].removeFollower({ follower: servers[0] }) - - await waitJobs(servers) - }) - - it('Should not not have follows anymore', async function () { - await checkNoFollowers(servers) - }) - }) - - describe('Disabled/Enabled followers', function () { - - it('Should disable followers on server 2', async function () { - const subConfig = { - followers: { - instance: { - enabled: false, - manualApproval: false - } - } - } - - await servers[1].config.updateCustomSubConfig({ newConfig: subConfig }) - - await commands[0].follow({ hosts: [ servers[1].url ] }) - await waitJobs(servers) - - await checkNoFollowers(servers) - }) - - it('Should re enable followers on server 2', async function () { - const subConfig = { - followers: { - instance: { - enabled: true, - manualApproval: false - } - } - } - - await servers[1].config.updateCustomSubConfig({ newConfig: subConfig }) - - await commands[0].follow({ hosts: [ servers[1].url ] }) - await waitJobs(servers) - - await checkServer1And2HasFollowers(servers) - }) - }) - - describe('Manual approbation', function () { - - it('Should manually approve followers', async function () { - this.timeout(20000) - - await commands[0].unfollow({ target: servers[1] }) - await waitJobs(servers) - - const subConfig = { - followers: { - instance: { - enabled: true, - manualApproval: true - } - } - } - - await servers[1].config.updateCustomSubConfig({ newConfig: subConfig }) - await servers[2].config.updateCustomSubConfig({ newConfig: subConfig }) - - await commands[0].follow({ hosts: [ servers[1].url ] }) - await waitJobs(servers) - - await checkServer1And2HasFollowers(servers, 'pending') - }) - - it('Should accept a follower', async function () { - await commands[1].acceptFollower({ follower: 'peertube@' + servers[0].host }) - await waitJobs(servers) - - await checkServer1And2HasFollowers(servers) - }) - - it('Should reject another follower', async function () { - this.timeout(20000) - - await commands[0].follow({ hosts: [ servers[2].url ] }) - await waitJobs(servers) - - { - const body = await commands[0].getFollowings() - expect(body.total).to.equal(2) - } - - { - const body = await commands[1].getFollowers() - expect(body.total).to.equal(1) - } - - { - const body = await commands[2].getFollowers() - expect(body.total).to.equal(1) - } - - await commands[2].rejectFollower({ follower: 'peertube@' + servers[0].host }) - await waitJobs(servers) - - { // server 1 - { - const { data } = await commands[0].getFollowings({ state: 'accepted' }) - expect(data).to.have.lengthOf(1) - } - - { - const { data } = await commands[0].getFollowings({ state: 'rejected' }) - expect(data).to.have.lengthOf(1) - expectStartWith(data[0].following.url, servers[2].url) - } - } - - { // server 3 - { - const { data } = await commands[2].getFollowers({ state: 'accepted' }) - expect(data).to.have.lengthOf(0) - } - - { - const { data } = await commands[2].getFollowers({ state: 'rejected' }) - expect(data).to.have.lengthOf(1) - expectStartWith(data[0].follower.url, servers[0].url) - } - } - }) - - it('Should still auto accept channel followers', async function () { - await commands[0].follow({ handles: [ 'root_channel@' + servers[1].host ] }) - - await waitJobs(servers) - - const body = await commands[0].getFollowings() - const follow = body.data[0] - expect(follow.following.name).to.equal('root_channel') - expect(follow.state).to.equal('accepted') - }) - }) - - describe('Accept/reject state', function () { - - it('Should not change the follow on refollow with and without auto accept', async function () { - const run = async () => { - await commands[0].follow({ hosts: [ servers[2].url ] }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'rejected', - following: servers[2], - followingState: 'rejected' - }) - } - - await servers[2].config.updateExistingSubConfig({ newConfig: { followers: { instance: { manualApproval: false } } } }) - await run() - - await servers[2].config.updateExistingSubConfig({ newConfig: { followers: { instance: { manualApproval: true } } } }) - await run() - }) - - it('Should not change the rejected status on unfollow', async function () { - await commands[0].unfollow({ target: servers[2] }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'deleted', - following: servers[2], - followingState: 'rejected' - }) - }) - - it('Should delete the follower and add again the follower', async function () { - await commands[2].removeFollower({ follower: servers[0] }) - await waitJobs(servers) - - await commands[0].follow({ hosts: [ servers[2].url ] }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'pending', - following: servers[2], - followingState: 'pending' - }) - }) - - it('Should be able to reject a previously accepted follower', async function () { - await commands[1].rejectFollower({ follower: 'peertube@' + servers[0].host }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'rejected', - following: servers[1], - followingState: 'rejected' - }) - }) - - it('Should be able to re accept a previously rejected follower', async function () { - await commands[1].acceptFollower({ follower: 'peertube@' + servers[0].host }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'accepted', - following: servers[1], - followingState: 'accepted' - }) - }) - }) - - describe('Muted servers', function () { - - it('Should ignore follow requests of muted servers', async function () { - await servers[1].blocklist.addToServerBlocklist({ server: servers[0].host }) - - await commands[0].unfollow({ target: servers[1] }) - - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'deleted', - following: servers[1], - followingState: 'deleted' - }) - - await commands[0].follow({ hosts: [ servers[1].host ] }) - await waitJobs(servers) - - await checkFollows({ - follower: servers[0], - followerState: 'rejected', - following: servers[1], - followingState: 'deleted' - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts deleted file mode 100644 index e3e4605ee..000000000 --- a/server/tests/api/server/follows.ts +++ /dev/null @@ -1,641 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { completeVideoCheck, dateIsValid, expectAccountFollows, expectChannelsFollows, testCaptionFile } from '@server/tests/shared' -import { Video, VideoPrivacy } from '@shared/models' -import { cleanupTests, createMultipleServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' - -describe('Test follows', function () { - - describe('Complex follow', function () { - let servers: PeerTubeServer[] = [] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - }) - - describe('Data propagation after follow', function () { - - it('Should not have followers/followings', async function () { - for (const server of servers) { - const bodies = await Promise.all([ - server.follows.getFollowers({ start: 0, count: 5, sort: 'createdAt' }), - server.follows.getFollowings({ start: 0, count: 5, sort: 'createdAt' }) - ]) - - for (const body of bodies) { - expect(body.total).to.equal(0) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(0) - } - } - }) - - it('Should have server 1 following root account of server 2 and server 3', async function () { - this.timeout(30000) - - await servers[0].follows.follow({ - hosts: [ servers[2].url ], - handles: [ 'root@' + servers[1].host ] - }) - - await waitJobs(servers) - }) - - it('Should have 2 followings on server 1', async function () { - const body = await servers[0].follows.getFollowings({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - let follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(1) - - const body2 = await servers[0].follows.getFollowings({ start: 1, count: 1, sort: 'createdAt' }) - follows = follows.concat(body2.data) - - const server2Follow = follows.find(f => f.following.host === servers[1].host) - const server3Follow = follows.find(f => f.following.host === servers[2].host) - - expect(server2Follow).to.not.be.undefined - expect(server2Follow.following.name).to.equal('root') - expect(server2Follow.state).to.equal('accepted') - - expect(server3Follow).to.not.be.undefined - expect(server3Follow.following.name).to.equal('peertube') - expect(server3Follow.state).to.equal('accepted') - }) - - it('Should have 0 followings on server 2 and 3', async function () { - for (const server of [ servers[1], servers[2] ]) { - const body = await server.follows.getFollowings({ start: 0, count: 5, sort: 'createdAt' }) - expect(body.total).to.equal(0) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(0) - } - }) - - it('Should have 1 followers on server 3', async function () { - const body = await servers[2].follows.getFollowers({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(1) - expect(follows[0].follower.host).to.equal(servers[0].host) - }) - - it('Should have 0 followers on server 1 and 2', async function () { - for (const server of [ servers[0], servers[1] ]) { - const body = await server.follows.getFollowers({ start: 0, count: 5, sort: 'createdAt' }) - expect(body.total).to.equal(0) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(0) - } - }) - - it('Should search/filter followings on server 1', async function () { - const sort = 'createdAt' - const start = 0 - const count = 1 - - { - const search = ':' + servers[1].port - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search }) - expect(body.total).to.equal(1) - - const follows = body.data - expect(follows).to.have.lengthOf(1) - expect(follows[0].following.host).to.equal(servers[1].host) - } - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'accepted' }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'accepted', actorType: 'Person' }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await servers[0].follows.getFollowings({ - start, - count, - sort, - search, - state: 'accepted', - actorType: 'Application' - }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'pending' }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - } - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search: 'root' }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await servers[0].follows.getFollowings({ start, count, sort, search: 'bla' }) - expect(body.total).to.equal(0) - - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should search/filter followers on server 2', async function () { - const start = 0 - const count = 5 - const sort = 'createdAt' - - { - const search = servers[0].port + '' - - { - const body = await servers[2].follows.getFollowers({ start, count, sort, search }) - expect(body.total).to.equal(1) - - const follows = body.data - expect(follows).to.have.lengthOf(1) - expect(follows[0].following.host).to.equal(servers[2].host) - } - - { - const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'accepted' }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'accepted', actorType: 'Person' }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await servers[2].follows.getFollowers({ - start, - count, - sort, - search, - state: 'accepted', - actorType: 'Application' - }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'pending' }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - } - - { - const body = await servers[2].follows.getFollowers({ start, count, sort, search: 'bla' }) - expect(body.total).to.equal(0) - - const follows = body.data - expect(follows).to.have.lengthOf(0) - } - }) - - it('Should have the correct follows counts', async function () { - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 2 }) - await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) - - // Server 2 and 3 does not know server 1 follow another server (there was not a refresh) - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) - - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) - }) - - it('Should unfollow server 3 on server 1', async function () { - this.timeout(15000) - - await servers[0].follows.unfollow({ target: servers[2] }) - - await waitJobs(servers) - }) - - it('Should not follow server 3 on server 1 anymore', async function () { - const body = await servers[0].follows.getFollowings({ start: 0, count: 2, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(1) - - expect(follows[0].following.host).to.equal(servers[1].host) - }) - - it('Should not have server 1 as follower on server 3 anymore', async function () { - const body = await servers[2].follows.getFollowers({ start: 0, count: 1, sort: 'createdAt' }) - expect(body.total).to.equal(0) - - const follows = body.data - expect(follows).to.be.an('array') - expect(follows).to.have.lengthOf(0) - }) - - it('Should have the correct follows counts after the unfollow', async function () { - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 0, following: 0 }) - - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) - - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 0 }) - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 0, following: 0 }) - }) - - it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { - this.timeout(160000) - - await servers[1].videos.upload({ attributes: { name: 'server2' } }) - await servers[2].videos.upload({ attributes: { name: 'server3' } }) - - await waitJobs(servers) - - { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(1) - expect(data[0].name).to.equal('server2') - } - - { - const { total, data } = await servers[1].videos.list() - expect(total).to.equal(1) - expect(data[0].name).to.equal('server2') - } - - { - const { total, data } = await servers[2].videos.list() - expect(total).to.equal(1) - expect(data[0].name).to.equal('server3') - } - }) - - it('Should remove account follow', async function () { - this.timeout(15000) - - await servers[0].follows.unfollow({ target: 'root@' + servers[1].host }) - - await waitJobs(servers) - }) - - it('Should have removed the account follow', async function () { - await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) - await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) - - { - const { total, data } = await servers[0].follows.getFollowings() - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - - { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - }) - - it('Should follow a channel', async function () { - this.timeout(15000) - - await servers[0].follows.follow({ - handles: [ 'root_channel@' + servers[1].host ] - }) - - await waitJobs(servers) - - await expectChannelsFollows({ server: servers[0], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) - await expectChannelsFollows({ server: servers[1], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) - - { - const { total, data } = await servers[0].follows.getFollowings() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - } - - { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - } - }) - }) - - describe('Should propagate data on a new server follow', function () { - let video4: Video - - before(async function () { - this.timeout(240000) - - const video4Attributes = { - name: 'server3-4', - category: 2, - nsfw: true, - licence: 6, - tags: [ 'tag1', 'tag2', 'tag3' ] - } - - await servers[2].videos.upload({ attributes: { name: 'server3-2' } }) - await servers[2].videos.upload({ attributes: { name: 'server3-3' } }) - - const video4CreateResult = await servers[2].videos.upload({ attributes: video4Attributes }) - - await servers[2].videos.upload({ attributes: { name: 'server3-5' } }) - await servers[2].videos.upload({ attributes: { name: 'server3-6' } }) - - { - const userAccessToken = await servers[2].users.generateUserAndToken('captain') - - await servers[2].videos.rate({ id: video4CreateResult.id, rating: 'like' }) - await servers[2].videos.rate({ token: userAccessToken, id: video4CreateResult.id, rating: 'dislike' }) - } - - { - await servers[2].comments.createThread({ videoId: video4CreateResult.id, text: 'my super first comment' }) - - await servers[2].comments.addReplyToLastThread({ text: 'my super answer to thread 1' }) - await servers[2].comments.addReplyToLastReply({ text: 'my super answer to answer of thread 1' }) - await servers[2].comments.addReplyToLastThread({ text: 'my second answer to thread 1' }) - } - - { - const { id: threadId } = await servers[2].comments.createThread({ videoId: video4CreateResult.id, text: 'will be deleted' }) - await servers[2].comments.addReplyToLastThread({ text: 'answer to deleted' }) - - const { id: replyId } = await servers[2].comments.addReplyToLastThread({ text: 'will also be deleted' }) - - await servers[2].comments.addReplyToLastReply({ text: 'my second answer to deleted' }) - - await servers[2].comments.delete({ videoId: video4CreateResult.id, commentId: threadId }) - await servers[2].comments.delete({ videoId: video4CreateResult.id, commentId: replyId }) - } - - await servers[2].captions.add({ - language: 'ar', - videoId: video4CreateResult.id, - fixture: 'subtitle-good2.vtt' - }) - - await waitJobs(servers) - - // Server 1 follows server 3 - await servers[0].follows.follow({ hosts: [ servers[2].url ] }) - - await waitJobs(servers) - }) - - it('Should have the correct follows counts', async function () { - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 2 }) - await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) - await expectChannelsFollows({ server: servers[0], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) - await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) - - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) - await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) - await expectChannelsFollows({ server: servers[1], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) - - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) - await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) - }) - - it('Should have propagated videos', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(7) - - const video2 = data.find(v => v.name === 'server3-2') - video4 = data.find(v => v.name === 'server3-4') - const video6 = data.find(v => v.name === 'server3-6') - - expect(video2).to.not.be.undefined - expect(video4).to.not.be.undefined - expect(video6).to.not.be.undefined - - const isLocal = false - const checkAttributes = { - name: 'server3-4', - category: 2, - licence: 6, - language: 'zh', - nsfw: true, - description: 'my super description', - support: 'my super support text', - account: { - name: 'root', - host: servers[2].host - }, - isLocal, - commentsEnabled: true, - downloadEnabled: true, - duration: 5, - tags: [ 'tag1', 'tag2', 'tag3' ], - privacy: VideoPrivacy.PUBLIC, - likes: 1, - dislikes: 1, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal - }, - fixture: 'video_short.webm', - files: [ - { - resolution: 720, - size: 218910 - } - ] - } - await completeVideoCheck({ - server: servers[0], - originServer: servers[2], - videoUUID: video4.uuid, - attributes: checkAttributes - }) - }) - - it('Should have propagated comments', async function () { - const { total, data } = await servers[0].comments.listThreads({ videoId: video4.id, sort: 'createdAt' }) - - expect(total).to.equal(2) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(2) - - { - const comment = data[0] - expect(comment.inReplyToCommentId).to.be.null - expect(comment.text).equal('my super first comment') - expect(comment.videoId).to.equal(video4.id) - expect(comment.id).to.equal(comment.threadId) - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(servers[2].host) - expect(comment.totalReplies).to.equal(3) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - - const threadId = comment.threadId - - const tree = await servers[0].comments.getThread({ videoId: video4.id, threadId }) - expect(tree.comment.text).equal('my super first comment') - expect(tree.children).to.have.lengthOf(2) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('my super answer to thread 1') - expect(firstChild.children).to.have.lengthOf(1) - - const childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') - expect(childOfFirstChild.children).to.have.lengthOf(0) - - const secondChild = tree.children[1] - expect(secondChild.comment.text).to.equal('my second answer to thread 1') - expect(secondChild.children).to.have.lengthOf(0) - } - - { - const deletedComment = data[1] - expect(deletedComment).to.not.be.undefined - expect(deletedComment.isDeleted).to.be.true - expect(deletedComment.deletedAt).to.not.be.null - expect(deletedComment.text).to.equal('') - expect(deletedComment.inReplyToCommentId).to.be.null - expect(deletedComment.account).to.be.null - expect(deletedComment.totalReplies).to.equal(2) - expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true - - const tree = await servers[0].comments.getThread({ videoId: video4.id, threadId: deletedComment.threadId }) - const [ commentRoot, deletedChildRoot ] = tree.children - - expect(deletedChildRoot).to.not.be.undefined - expect(deletedChildRoot.comment.isDeleted).to.be.true - expect(deletedChildRoot.comment.deletedAt).to.not.be.null - expect(deletedChildRoot.comment.text).to.equal('') - expect(deletedChildRoot.comment.inReplyToCommentId).to.equal(deletedComment.id) - expect(deletedChildRoot.comment.account).to.be.null - expect(deletedChildRoot.children).to.have.lengthOf(1) - - const answerToDeletedChild = deletedChildRoot.children[0] - expect(answerToDeletedChild.comment).to.not.be.undefined - expect(answerToDeletedChild.comment.inReplyToCommentId).to.equal(deletedChildRoot.comment.id) - expect(answerToDeletedChild.comment.text).to.equal('my second answer to deleted') - expect(answerToDeletedChild.comment.account.name).to.equal('root') - - expect(commentRoot.comment).to.not.be.undefined - expect(commentRoot.comment.inReplyToCommentId).to.equal(deletedComment.id) - expect(commentRoot.comment.text).to.equal('answer to deleted') - expect(commentRoot.comment.account.name).to.equal('root') - } - }) - - it('Should have propagated captions', async function () { - const body = await servers[0].captions.list({ videoId: video4.id }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const caption1 = body.data[0] - expect(caption1.language.id).to.equal('ar') - expect(caption1.language.label).to.equal('Arabic') - expect(caption1.captionPath).to.match(new RegExp('^/lazy-static/video-captions/.+-ar.vtt$')) - await testCaptionFile(servers[0].url, caption1.captionPath, 'Subtitle good 2.') - }) - - it('Should unfollow server 3 on server 1 and does not list server 3 videos', async function () { - this.timeout(5000) - - await servers[0].follows.unfollow({ target: servers[2] }) - - await waitJobs(servers) - - const { total } = await servers[0].videos.list() - expect(total).to.equal(1) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - - describe('Simple data propagation propagate data on a new channel follow', function () { - let servers: PeerTubeServer[] = [] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - await setAccessTokensToServers(servers) - - await servers[0].videos.upload({ attributes: { name: 'video to add' } }) - - await waitJobs(servers) - - for (const server of [ servers[1], servers[2] ]) { - const video = await server.videos.find({ name: 'video to add' }) - expect(video).to.not.exist - } - }) - - it('Should have propagated video after new channel follow', async function () { - this.timeout(60000) - - await servers[1].follows.follow({ handles: [ 'root_channel@' + servers[0].host ] }) - - await waitJobs(servers) - - const video = await servers[1].videos.find({ name: 'video to add' }) - expect(video).to.exist - }) - - it('Should have propagated video after new account follow', async function () { - this.timeout(60000) - - await servers[2].follows.follow({ handles: [ 'root@' + servers[0].host ] }) - - await waitJobs(servers) - - const video = await servers[2].videos.find({ name: 'video to add' }) - expect(video).to.exist - }) - - after(async function () { - await cleanupTests(servers) - }) - }) -}) diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts deleted file mode 100644 index 1d524aa93..000000000 --- a/server/tests/api/server/handle-down.ts +++ /dev/null @@ -1,338 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { completeVideoCheck, SQLCommand } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, JobState, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - CommentsCommand, - createMultipleServers, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test handle downs', function () { - let servers: PeerTubeServer[] = [] - let sqlCommands: SQLCommand[] = [] - - let threadIdServer1: number - let threadIdServer2: number - let commentIdServer1: number - let commentIdServer2: number - let missedVideo1: VideoCreateResult - let missedVideo2: VideoCreateResult - let unlistedVideo: VideoCreateResult - - const videoIdsServer1: string[] = [] - - const videoAttributes = { - name: 'my super name for server 1', - category: 5, - licence: 4, - language: 'ja', - nsfw: true, - privacy: VideoPrivacy.PUBLIC, - description: 'my super description for server 1', - support: 'my super support text for server 1', - tags: [ 'tag1p1', 'tag2p1' ], - fixture: 'video_short1.webm' - } - - const unlistedVideoAttributes = { ...videoAttributes, privacy: VideoPrivacy.UNLISTED } - - let checkAttributes: any - let unlistedCheckAttributes: any - - let commentCommands: CommentsCommand[] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - commentCommands = servers.map(s => s.comments) - - checkAttributes = { - name: 'my super name for server 1', - category: 5, - licence: 4, - language: 'ja', - nsfw: true, - description: 'my super description for server 1', - support: 'my super support text for server 1', - account: { - name: 'root', - host: servers[0].host - }, - isLocal: false, - duration: 10, - tags: [ 'tag1p1', 'tag2p1' ], - privacy: VideoPrivacy.PUBLIC, - commentsEnabled: true, - downloadEnabled: true, - channel: { - name: 'root_channel', - displayName: 'Main root channel', - description: '', - isLocal: false - }, - fixture: 'video_short1.webm', - files: [ - { - resolution: 720, - size: 572456 - } - ] - } - unlistedCheckAttributes = { ...checkAttributes, privacy: VideoPrivacy.UNLISTED } - - // Get the access tokens - await setAccessTokensToServers(servers) - - sqlCommands = servers.map(s => new SQLCommand(s)) - }) - - it('Should remove followers that are often down', async function () { - this.timeout(240000) - - // Server 2 and 3 follow server 1 - await servers[1].follows.follow({ hosts: [ servers[0].url ] }) - await servers[2].follows.follow({ hosts: [ servers[0].url ] }) - - await waitJobs(servers) - - // Upload a video to server 1 - await servers[0].videos.upload({ attributes: videoAttributes }) - - await waitJobs(servers) - - // And check all servers have this video - for (const server of servers) { - const { data } = await server.videos.list() - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - } - - // Kill server 2 - await killallServers([ servers[1] ]) - - // Remove server 2 follower - for (let i = 0; i < 10; i++) { - await servers[0].videos.upload({ attributes: videoAttributes }) - } - - await waitJobs([ servers[0], servers[2] ]) - - // Kill server 3 - await killallServers([ servers[2] ]) - - missedVideo1 = await servers[0].videos.upload({ attributes: videoAttributes }) - - missedVideo2 = await servers[0].videos.upload({ attributes: videoAttributes }) - - // Unlisted video - unlistedVideo = await servers[0].videos.upload({ attributes: unlistedVideoAttributes }) - - // Add comments to video 2 - { - const text = 'thread 1' - let comment = await commentCommands[0].createThread({ videoId: missedVideo2.uuid, text }) - threadIdServer1 = comment.id - - comment = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-1' }) - - const created = await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: comment.id, text: 'comment 1-2' }) - commentIdServer1 = created.id - } - - await waitJobs(servers[0]) - // Wait scheduler - await wait(11000) - - // Only server 3 is still a follower of server 1 - const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' }) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].follower.host).to.equal(servers[2].host) - }) - - it('Should not have pending/processing jobs anymore', async function () { - const states: JobState[] = [ 'waiting', 'active' ] - - for (const state of states) { - const body = await servers[0].jobs.list({ - state, - start: 0, - count: 50, - sort: '-createdAt' - }) - expect(body.data).to.have.length(0) - } - }) - - it('Should re-follow server 1', async function () { - this.timeout(70000) - - await servers[1].run() - await servers[2].run() - - await servers[1].follows.unfollow({ target: servers[0] }) - await waitJobs(servers) - - await servers[1].follows.follow({ hosts: [ servers[0].url ] }) - - await waitJobs(servers) - - const body = await servers[0].follows.getFollowers({ start: 0, count: 2, sort: 'createdAt' }) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - }) - - it('Should send an update to server 3, and automatically fetch the video', async function () { - this.timeout(15000) - - { - const { data } = await servers[2].videos.list() - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(11) - } - - await servers[0].videos.update({ id: missedVideo1.uuid }) - await servers[0].videos.update({ id: unlistedVideo.uuid }) - - await waitJobs(servers) - - { - const { data } = await servers[2].videos.list() - expect(data).to.be.an('array') - // 1 video is unlisted - expect(data).to.have.lengthOf(12) - } - - // Check unlisted video - const video = await servers[2].videos.get({ id: unlistedVideo.uuid }) - await completeVideoCheck({ server: servers[2], originServer: servers[0], videoUUID: video.uuid, attributes: unlistedCheckAttributes }) - }) - - it('Should send comments on a video to server 3, and automatically fetch the video', async function () { - this.timeout(25000) - - await commentCommands[0].addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer1, text: 'comment 1-3' }) - - await waitJobs(servers) - - await servers[2].videos.get({ id: missedVideo2.uuid }) - - { - const { data } = await servers[2].comments.listThreads({ videoId: missedVideo2.uuid }) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - - threadIdServer2 = data[0].id - - const tree = await servers[2].comments.getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer2 }) - expect(tree.comment.text).equal('thread 1') - expect(tree.children).to.have.lengthOf(1) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('comment 1-1') - expect(firstChild.children).to.have.lengthOf(1) - - const childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('comment 1-2') - expect(childOfFirstChild.children).to.have.lengthOf(1) - - const childOfChildFirstChild = childOfFirstChild.children[0] - expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3') - expect(childOfChildFirstChild.children).to.have.lengthOf(0) - - commentIdServer2 = childOfChildFirstChild.comment.id - } - }) - - it('Should correctly reply to the comment', async function () { - this.timeout(15000) - - await servers[2].comments.addReply({ videoId: missedVideo2.uuid, toCommentId: commentIdServer2, text: 'comment 1-4' }) - - await waitJobs(servers) - - const tree = await commentCommands[0].getThread({ videoId: missedVideo2.uuid, threadId: threadIdServer1 }) - - expect(tree.comment.text).equal('thread 1') - expect(tree.children).to.have.lengthOf(1) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('comment 1-1') - expect(firstChild.children).to.have.lengthOf(1) - - const childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('comment 1-2') - expect(childOfFirstChild.children).to.have.lengthOf(1) - - const childOfChildFirstChild = childOfFirstChild.children[0] - expect(childOfChildFirstChild.comment.text).to.equal('comment 1-3') - expect(childOfChildFirstChild.children).to.have.lengthOf(1) - - const childOfChildOfChildOfFirstChild = childOfChildFirstChild.children[0] - expect(childOfChildOfChildOfFirstChild.comment.text).to.equal('comment 1-4') - expect(childOfChildOfChildOfFirstChild.children).to.have.lengthOf(0) - }) - - it('Should upload many videos on server 1', async function () { - this.timeout(240000) - - for (let i = 0; i < 10; i++) { - const uuid = (await servers[0].videos.quickUpload({ name: 'video ' + i })).uuid - videoIdsServer1.push(uuid) - } - - await waitJobs(servers) - - for (const id of videoIdsServer1) { - await servers[1].videos.get({ id }) - } - - await waitJobs(servers) - await sqlCommands[1].setActorFollowScores(20) - - // Wait video expiration - await wait(11000) - - // Refresh video -> score + 10 = 30 - await servers[1].videos.get({ id: videoIdsServer1[0] }) - - await waitJobs(servers) - }) - - it('Should remove followings that are down', async function () { - this.timeout(120000) - - await killallServers([ servers[0] ]) - - // Wait video expiration - await wait(11000) - - for (let i = 0; i < 5; i++) { - try { - await servers[1].videos.get({ id: videoIdsServer1[i] }) - await waitJobs([ servers[1] ]) - await wait(1500) - } catch {} - } - - for (const id of videoIdsServer1) { - await servers[1].videos.get({ id, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - } - }) - - after(async function () { - for (const sqlCommand of sqlCommands) { - await sqlCommand.cleanup() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/homepage.ts b/server/tests/api/server/homepage.ts deleted file mode 100644 index 9c45800f2..000000000 --- a/server/tests/api/server/homepage.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - CustomPagesCommand, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar -} from '../../../../shared/server-commands/index' - -async function getHomepageState (server: PeerTubeServer) { - const config = await server.config.getConfig() - - return config.homepage.enabled -} - -describe('Test instance homepage actions', function () { - let server: PeerTubeServer - let command: CustomPagesCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(server) - - command = server.customPage - }) - - it('Should not have a homepage', async function () { - const state = await getHomepageState(server) - expect(state).to.be.false - - await command.getInstanceHomepage({ expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should set a homepage', async function () { - await command.updateInstanceHomepage({ content: '' }) - - const page = await command.getInstanceHomepage() - expect(page.content).to.equal('') - - const state = await getHomepageState(server) - expect(state).to.be.true - }) - - it('Should have the same homepage after a restart', async function () { - this.timeout(30000) - - await killallServers([ server ]) - - await server.run() - - const page = await command.getInstanceHomepage() - expect(page.content).to.equal('') - - const state = await getHomepageState(server) - expect(state).to.be.true - }) - - it('Should empty the homepage', async function () { - await command.updateInstanceHomepage({ content: '' }) - - const page = await command.getInstanceHomepage() - expect(page.content).to.be.empty - - const state = await getHomepageState(server) - expect(state).to.be.false - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts deleted file mode 100644 index 78522c246..000000000 --- a/server/tests/api/server/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import './auto-follows' -import './bulk' -import './config-defaults' -import './config' -import './contact-form' -import './email' -import './follow-constraints' -import './follows' -import './follows-moderation' -import './homepage' -import './handle-down' -import './jobs' -import './logs' -import './reverse-proxy' -import './services' -import './slow-follows' -import './stats' -import './tracker' -import './no-client' -import './open-telemetry' -import './plugins' -import './proxy' diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts deleted file mode 100644 index d0e6df719..000000000 --- a/server/tests/api/server/jobs.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { dateIsValid } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test jobs', function () { - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - it('Should create some jobs', async function () { - this.timeout(240000) - - await servers[1].videos.upload({ attributes: { name: 'video1' } }) - await servers[1].videos.upload({ attributes: { name: 'video2' } }) - - await waitJobs(servers) - }) - - it('Should list jobs', async function () { - const body = await servers[1].jobs.list({ state: 'completed' }) - expect(body.total).to.be.above(2) - expect(body.data).to.have.length.above(2) - }) - - it('Should list jobs with sort, pagination and job type', async function () { - { - const body = await servers[1].jobs.list({ - state: 'completed', - start: 1, - count: 2, - sort: 'createdAt' - }) - expect(body.total).to.be.above(2) - expect(body.data).to.have.lengthOf(2) - - let job = body.data[0] - // Skip repeat jobs - if (job.type === 'videos-views-stats') job = body.data[1] - - expect(job.state).to.equal('completed') - expect(dateIsValid(job.createdAt as string)).to.be.true - expect(dateIsValid(job.processedOn as string)).to.be.true - expect(dateIsValid(job.finishedOn as string)).to.be.true - } - - { - const body = await servers[1].jobs.list({ - state: 'completed', - start: 0, - count: 100, - sort: 'createdAt', - jobType: 'activitypub-http-broadcast' - }) - expect(body.total).to.be.above(2) - - for (const j of body.data) { - expect(j.type).to.equal('activitypub-http-broadcast') - } - } - }) - - it('Should list all jobs', async function () { - const body = await servers[1].jobs.list() - expect(body.total).to.be.above(2) - - const jobs = body.data - expect(jobs).to.have.length.above(2) - - expect(jobs.find(j => j.state === 'completed')).to.not.be.undefined - }) - - it('Should pause the job queue', async function () { - this.timeout(120000) - - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video2' } }) - await waitJobs(servers) - - await servers[1].jobs.pauseJobQueue() - await servers[1].videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' }) - - await wait(5000) - - { - const body = await servers[1].jobs.list({ state: 'waiting', jobType: 'video-transcoding' }) - // waiting includes waiting-children - expect(body.data).to.have.lengthOf(4) - } - - { - const body = await servers[1].jobs.list({ state: 'waiting-children', jobType: 'video-transcoding' }) - expect(body.data).to.have.lengthOf(1) - } - }) - - it('Should resume the job queue', async function () { - this.timeout(120000) - - await servers[1].jobs.resumeJobQueue() - - await waitJobs(servers) - - const body = await servers[1].jobs.list({ state: 'waiting', jobType: 'video-transcoding' }) - expect(body.data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts deleted file mode 100644 index 9cf04c501..000000000 --- a/server/tests/api/server/logs.ts +++ /dev/null @@ -1,265 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - killallServers, - LogsCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test logs', function () { - let server: PeerTubeServer - let logsCommand: LogsCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - logsCommand = server.logs - }) - - describe('With the standard log file', function () { - - it('Should get logs with a start date', async function () { - this.timeout(60000) - - await server.videos.upload({ attributes: { name: 'video 1' } }) - await waitJobs([ server ]) - - const now = new Date() - - await server.videos.upload({ attributes: { name: 'video 2' } }) - await waitJobs([ server ]) - - const body = await logsCommand.getLogs({ startDate: now }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('Video with name video 1')).to.be.false - expect(logsString.includes('Video with name video 2')).to.be.true - }) - - it('Should get logs with an end date', async function () { - this.timeout(60000) - - await server.videos.upload({ attributes: { name: 'video 3' } }) - await waitJobs([ server ]) - - const now1 = new Date() - - await server.videos.upload({ attributes: { name: 'video 4' } }) - await waitJobs([ server ]) - - const now2 = new Date() - - await server.videos.upload({ attributes: { name: 'video 5' } }) - await waitJobs([ server ]) - - const body = await logsCommand.getLogs({ startDate: now1, endDate: now2 }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('Video with name video 3')).to.be.false - expect(logsString.includes('Video with name video 4')).to.be.true - expect(logsString.includes('Video with name video 5')).to.be.false - }) - - it('Should filter by level', async function () { - this.timeout(60000) - - const now = new Date() - - await server.videos.upload({ attributes: { name: 'video 6' } }) - await waitJobs([ server ]) - - { - const body = await logsCommand.getLogs({ startDate: now, level: 'info' }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('Video with name video 6')).to.be.true - } - - { - const body = await logsCommand.getLogs({ startDate: now, level: 'warn' }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('Video with name video 6')).to.be.false - } - }) - - it('Should filter by tag', async function () { - const now = new Date() - - const { uuid } = await server.videos.upload({ attributes: { name: 'video 6' } }) - await waitJobs([ server ]) - - { - const body = await logsCommand.getLogs({ startDate: now, level: 'debug', tagsOneOf: [ 'toto' ] }) - expect(body).to.have.lengthOf(0) - } - - { - const body = await logsCommand.getLogs({ startDate: now, level: 'debug', tagsOneOf: [ uuid ] }) - expect(body).to.not.have.lengthOf(0) - - for (const line of body) { - expect(line.tags).to.contain(uuid) - } - } - }) - - it('Should log ping requests', async function () { - const now = new Date() - - await server.servers.ping() - - const body = await logsCommand.getLogs({ startDate: now, level: 'info' }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('/api/v1/ping')).to.be.true - }) - - it('Should not log ping requests', async function () { - this.timeout(60000) - - await killallServers([ server ]) - - await server.run({ log: { log_ping_requests: false } }) - - const now = new Date() - - await server.servers.ping() - - const body = await logsCommand.getLogs({ startDate: now, level: 'info' }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('/api/v1/ping')).to.be.false - }) - }) - - describe('With the audit log', function () { - - it('Should get logs with a start date', async function () { - this.timeout(60000) - - await server.videos.upload({ attributes: { name: 'video 7' } }) - await waitJobs([ server ]) - - const now = new Date() - - await server.videos.upload({ attributes: { name: 'video 8' } }) - await waitJobs([ server ]) - - const body = await logsCommand.getAuditLogs({ startDate: now }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('video 7')).to.be.false - expect(logsString.includes('video 8')).to.be.true - - expect(body).to.have.lengthOf(1) - - const item = body[0] - - const message = JSON.parse(item.message) - expect(message.domain).to.equal('videos') - expect(message.action).to.equal('create') - }) - - it('Should get logs with an end date', async function () { - this.timeout(60000) - - await server.videos.upload({ attributes: { name: 'video 9' } }) - await waitJobs([ server ]) - - const now1 = new Date() - - await server.videos.upload({ attributes: { name: 'video 10' } }) - await waitJobs([ server ]) - - const now2 = new Date() - - await server.videos.upload({ attributes: { name: 'video 11' } }) - await waitJobs([ server ]) - - const body = await logsCommand.getAuditLogs({ startDate: now1, endDate: now2 }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('video 9')).to.be.false - expect(logsString.includes('video 10')).to.be.true - expect(logsString.includes('video 11')).to.be.false - }) - }) - - describe('When creating log from the client', function () { - - it('Should create a warn client log', async function () { - const now = new Date() - - await server.logs.createLogClient({ - payload: { - level: 'warn', - url: 'http://example.com', - message: 'my super client message' - }, - token: null - }) - - const body = await logsCommand.getLogs({ startDate: now }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('my super client message')).to.be.true - }) - - it('Should create an error authenticated client log', async function () { - const now = new Date() - - await server.logs.createLogClient({ - payload: { - url: 'https://example.com/page1', - level: 'error', - message: 'my super client message 2', - userAgent: 'super user agent', - meta: '{hello}', - stackTrace: 'super stack trace' - } - }) - - const body = await logsCommand.getLogs({ startDate: now }) - const logsString = JSON.stringify(body) - - expect(logsString.includes('my super client message 2')).to.be.true - expect(logsString.includes('super user agent')).to.be.true - expect(logsString.includes('super stack trace')).to.be.true - expect(logsString.includes('{hello}')).to.be.true - expect(logsString.includes('https://example.com/page1')).to.be.true - }) - - it('Should refuse to create client logs', async function () { - await server.kill() - - await server.run({ - log: { - accept_client_log: false - } - }) - - await server.logs.createLogClient({ - payload: { - level: 'warn', - url: 'http://example.com', - message: 'my super client message' - }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts deleted file mode 100644 index 193f6c987..000000000 --- a/server/tests/api/server/no-client.ts +++ /dev/null @@ -1,24 +0,0 @@ -import request from 'supertest' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' - -describe('Start and stop server without web client routes', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, {}, { peertubeArgs: [ '--no-client' ] }) - }) - - it('Should fail getting the client', function () { - const req = request(server.url) - .get('/') - - return req.expect(HttpStatusCode.NOT_FOUND_404) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts deleted file mode 100644 index 508e9d649..000000000 --- a/server/tests/api/server/open-telemetry.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectLogContain, expectLogDoesNotContain, MockHTTP } from '@server/tests/shared' -import { HttpStatusCode, PlaybackMetricCreate, VideoPrivacy, VideoResolution } from '@shared/models' -import { cleanupTests, createSingleServer, makeRawRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Open Telemetry', function () { - let server: PeerTubeServer - - describe('Metrics', function () { - const metricsUrl = 'http://127.0.0.1:9092/metrics' - - it('Should not enable open telemetry metrics', async function () { - this.timeout(60000) - - server = await createSingleServer(1) - - let hasError = false - try { - await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } catch (err) { - hasError = err.message.includes('ECONNREFUSED') - } - - expect(hasError).to.be.true - - await server.kill() - }) - - it('Should enable open telemetry metrics', async function () { - this.timeout(120000) - - await server.run({ - open_telemetry: { - metrics: { - enabled: true - } - } - }) - - // Simulate a HTTP request - await server.videos.list() - - const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).to.contain('peertube_job_queue_total{') - expect(res.text).to.contain('http_request_duration_ms_bucket{') - }) - - it('Should have playback metrics', async function () { - await setAccessTokensToServers([ server ]) - - const video = await server.videos.quickUpload({ name: 'video' }) - - await server.metrics.addPlaybackMetric({ - metrics: { - playerMode: 'p2p-media-loader', - resolution: VideoResolution.H_1080P, - fps: 30, - resolutionChanges: 1, - errors: 2, - downloadedBytesP2P: 0, - downloadedBytesHTTP: 0, - uploadedBytesP2P: 5, - p2pPeers: 1, - p2pEnabled: false, - videoId: video.uuid - } - }) - - const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) - - expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') - expect(res.text).to.contain('peertube_playback_p2p_peers{') - expect(res.text).to.contain('p2pEnabled="false"') - }) - - it('Should take the last playback metric', async function () { - await setAccessTokensToServers([ server ]) - - const video = await server.videos.quickUpload({ name: 'video' }) - - const metrics = { - playerMode: 'p2p-media-loader', - resolution: VideoResolution.H_1080P, - fps: 30, - resolutionChanges: 1, - errors: 2, - downloadedBytesP2P: 0, - downloadedBytesHTTP: 0, - uploadedBytesP2P: 5, - p2pPeers: 7, - p2pEnabled: false, - videoId: video.uuid - } as PlaybackMetricCreate - - await server.metrics.addPlaybackMetric({ metrics }) - - metrics.p2pPeers = 42 - await server.metrics.addPlaybackMetric({ metrics }) - - const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) - - // eslint-disable-next-line max-len - const label = `{videoOrigin="local",playerMode="p2p-media-loader",resolution="1080",fps="30",p2pEnabled="false",videoUUID="${video.uuid}"}` - expect(res.text).to.contain(`peertube_playback_p2p_peers${label} 42`) - expect(res.text).to.not.contain(`peertube_playback_p2p_peers${label} 7`) - }) - - it('Should disable http request duration metrics', async function () { - await server.kill() - - await server.run({ - open_telemetry: { - metrics: { - enabled: true, - http_request_duration: { - enabled: false - } - } - } - }) - - // Simulate a HTTP request - await server.videos.list() - - const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).to.not.contain('http_request_duration_ms_bucket{') - }) - - after(async function () { - await server.kill() - }) - }) - - describe('Tracing', function () { - let mockHTTP: MockHTTP - let mockPort: number - - before(async function () { - mockHTTP = new MockHTTP() - mockPort = await mockHTTP.initialize() - }) - - it('Should enable open telemetry tracing', async function () { - server = await createSingleServer(1) - - await expectLogDoesNotContain(server, 'Registering Open Telemetry tracing') - - await server.kill() - }) - - it('Should enable open telemetry metrics', async function () { - await server.run({ - open_telemetry: { - tracing: { - enabled: true, - jaeger_exporter: { - endpoint: 'http://127.0.0.1:' + mockPort - } - } - } - }) - - await expectLogContain(server, 'Registering Open Telemetry tracing') - }) - - it('Should upload a video and correctly works', async function () { - await setAccessTokensToServers([ server ]) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PUBLIC }) - - const video = await server.videos.get({ id: uuid }) - - expect(video.name).to.equal('video') - }) - - after(async function () { - await mockHTTP.terminate() - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts deleted file mode 100644 index a0e9db1d3..000000000 --- a/server/tests/api/server/plugins.ts +++ /dev/null @@ -1,409 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, remove } from 'fs-extra' -import { join } from 'path' -import { SQLCommand, testHelloWorldRegisteredSettings } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, PluginType } from '@shared/models' -import { - cleanupTests, - createSingleServer, - killallServers, - makeGetRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test plugins', function () { - let server: PeerTubeServer - let sqlCommand: SQLCommand - let command: PluginsCommand - - before(async function () { - this.timeout(30000) - - const configOverride = { - plugins: { - index: { check_latest_versions_interval: '5 seconds' } - } - } - server = await createSingleServer(1, configOverride) - await setAccessTokensToServers([ server ]) - - command = server.plugins - - sqlCommand = new SQLCommand(server) - }) - - it('Should list and search available plugins and themes', async function () { - this.timeout(30000) - - { - const body = await command.listAvailable({ - count: 1, - start: 0, - pluginType: PluginType.THEME, - search: 'background-red' - }) - - expect(body.total).to.be.at.least(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body1 = await command.listAvailable({ - count: 2, - start: 0, - sort: 'npmName' - }) - expect(body1.total).to.be.at.least(2) - - const data1 = body1.data - expect(data1).to.have.lengthOf(2) - - const body2 = await command.listAvailable({ - count: 2, - start: 0, - sort: '-npmName' - }) - expect(body2.total).to.be.at.least(2) - - const data2 = body2.data - expect(data2).to.have.lengthOf(2) - - expect(data1[0].npmName).to.not.equal(data2[0].npmName) - } - - { - const body = await command.listAvailable({ - count: 10, - start: 0, - pluginType: PluginType.THEME, - search: 'background-red', - currentPeerTubeEngine: '1.0.0' - }) - - const p = body.data.find(p => p.npmName === 'peertube-theme-background-red') - expect(p).to.be.undefined - } - }) - - it('Should install a plugin and a theme', async function () { - this.timeout(30000) - - await command.install({ npmName: 'peertube-plugin-hello-world' }) - await command.install({ npmName: 'peertube-theme-background-red' }) - }) - - it('Should have the plugin loaded in the configuration', async function () { - for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) { - const theme = config.theme.registered.find(r => r.name === 'background-red') - expect(theme).to.not.be.undefined - expect(theme.npmName).to.equal('peertube-theme-background-red') - - const plugin = config.plugin.registered.find(r => r.name === 'hello-world') - expect(plugin).to.not.be.undefined - expect(plugin.npmName).to.equal('peertube-plugin-hello-world') - } - }) - - it('Should update the default theme in the configuration', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - theme: { default: 'background-red' } - } - }) - - for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) { - expect(config.theme.default).to.equal('background-red') - } - }) - - it('Should update my default theme', async function () { - await server.users.updateMe({ theme: 'background-red' }) - - const user = await server.users.getMyInfo() - expect(user.theme).to.equal('background-red') - }) - - it('Should list plugins and themes', async function () { - { - const body = await command.list({ - count: 1, - start: 0, - pluginType: PluginType.THEME - }) - expect(body.total).to.be.at.least(1) - - const data = body.data - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('background-red') - } - - { - const { data } = await command.list({ - count: 2, - start: 0, - sort: 'name' - }) - - expect(data[0].name).to.equal('background-red') - expect(data[1].name).to.equal('hello-world') - } - - { - const body = await command.list({ - count: 2, - start: 1, - sort: 'name' - }) - - expect(body.data[0].name).to.equal('hello-world') - } - }) - - it('Should get registered settings', async function () { - await testHelloWorldRegisteredSettings(server) - }) - - it('Should get public settings', async function () { - const body = await command.getPublicSettings({ npmName: 'peertube-plugin-hello-world' }) - const publicSettings = body.publicSettings - - expect(Object.keys(publicSettings)).to.have.lengthOf(1) - expect(Object.keys(publicSettings)).to.deep.equal([ 'user-name' ]) - expect(publicSettings['user-name']).to.be.null - }) - - it('Should update the settings', async function () { - const settings = { - 'admin-name': 'Cid' - } - - await command.updateSettings({ - npmName: 'peertube-plugin-hello-world', - settings - }) - }) - - it('Should have watched settings changes', async function () { - await server.servers.waitUntilLog('Settings changed!') - }) - - it('Should get a plugin and a theme', async function () { - { - const plugin = await command.get({ npmName: 'peertube-plugin-hello-world' }) - - expect(plugin.type).to.equal(PluginType.PLUGIN) - expect(plugin.name).to.equal('hello-world') - expect(plugin.description).to.exist - expect(plugin.homepage).to.exist - expect(plugin.uninstalled).to.be.false - expect(plugin.enabled).to.be.true - expect(plugin.description).to.exist - expect(plugin.version).to.exist - expect(plugin.peertubeEngine).to.exist - expect(plugin.createdAt).to.exist - - expect(plugin.settings).to.not.be.undefined - expect(plugin.settings['admin-name']).to.equal('Cid') - } - - { - const plugin = await command.get({ npmName: 'peertube-theme-background-red' }) - - expect(plugin.type).to.equal(PluginType.THEME) - expect(plugin.name).to.equal('background-red') - expect(plugin.description).to.exist - expect(plugin.homepage).to.exist - expect(plugin.uninstalled).to.be.false - expect(plugin.enabled).to.be.true - expect(plugin.description).to.exist - expect(plugin.version).to.exist - expect(plugin.peertubeEngine).to.exist - expect(plugin.createdAt).to.exist - - expect(plugin.settings).to.be.null - } - }) - - it('Should update the plugin and the theme', async function () { - this.timeout(180000) - - // Wait the scheduler that get the latest plugins versions - await wait(6000) - - async function testUpdate (type: 'plugin' | 'theme', name: string) { - // Fake update our plugin version - await sqlCommand.setPluginVersion(name, '0.0.1') - - // Fake update package.json - const packageJSON = await command.getPackageJSON(`peertube-${type}-${name}`) - const oldVersion = packageJSON.version - - packageJSON.version = '0.0.1' - await command.updatePackageJSON(`peertube-${type}-${name}`, packageJSON) - - // Restart the server to take into account this change - await killallServers([ server ]) - await server.run() - - const checkConfig = async (version: string) => { - for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) { - expect(config[type].registered.find(r => r.name === name).version).to.equal(version) - } - } - - const getPluginFromAPI = async () => { - const body = await command.list({ pluginType: type === 'plugin' ? PluginType.PLUGIN : PluginType.THEME }) - - return body.data.find(p => p.name === name) - } - - { - const plugin = await getPluginFromAPI() - expect(plugin.version).to.equal('0.0.1') - expect(plugin.latestVersion).to.exist - expect(plugin.latestVersion).to.not.equal('0.0.1') - - await checkConfig('0.0.1') - } - - { - await command.update({ npmName: `peertube-${type}-${name}` }) - - const plugin = await getPluginFromAPI() - expect(plugin.version).to.equal(oldVersion) - - const updatedPackageJSON = await command.getPackageJSON(`peertube-${type}-${name}`) - expect(updatedPackageJSON.version).to.equal(oldVersion) - - await checkConfig(oldVersion) - } - } - - await testUpdate('theme', 'background-red') - await testUpdate('plugin', 'hello-world') - }) - - it('Should uninstall the plugin', async function () { - await command.uninstall({ npmName: 'peertube-plugin-hello-world' }) - - const body = await command.list({ pluginType: PluginType.PLUGIN }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should list uninstalled plugins', async function () { - const body = await command.list({ pluginType: PluginType.PLUGIN, uninstalled: true }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const plugin = body.data[0] - expect(plugin.name).to.equal('hello-world') - expect(plugin.enabled).to.be.false - expect(plugin.uninstalled).to.be.true - }) - - it('Should uninstall the theme', async function () { - await command.uninstall({ npmName: 'peertube-theme-background-red' }) - }) - - it('Should have updated the configuration', async function () { - for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) { - expect(config.theme.default).to.equal('default') - - const theme = config.theme.registered.find(r => r.name === 'background-red') - expect(theme).to.be.undefined - - const plugin = config.plugin.registered.find(r => r.name === 'hello-world') - expect(plugin).to.be.undefined - } - }) - - it('Should have updated the user theme', async function () { - const user = await server.users.getMyInfo() - expect(user.theme).to.equal('instance-default') - }) - - it('Should not install a broken plugin', async function () { - this.timeout(60000) - - async function check () { - const body = await command.list({ pluginType: PluginType.PLUGIN }) - const plugins = body.data - expect(plugins.find(p => p.name === 'test-broken')).to.not.exist - } - - await command.install({ - path: PluginsCommand.getPluginTestPath('-broken'), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await check() - - await killallServers([ server ]) - await server.run() - - await check() - }) - - it('Should rebuild native modules on Node ABI change', async function () { - this.timeout(60000) - - const removeNativeModule = async () => { - await remove(join(baseNativeModule, 'build')) - await remove(join(baseNativeModule, 'prebuilds')) - } - - await command.install({ path: PluginsCommand.getPluginTestPath('-native') }) - - await makeGetRequest({ - url: server.url, - path: '/plugins/test-native/router', - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - - const query = `UPDATE "application" SET "nodeABIVersion" = 1` - await sqlCommand.updateQuery(query) - - const baseNativeModule = server.servers.buildDirectory(join('plugins', 'node_modules', 'a-native-example')) - - await removeNativeModule() - await server.kill() - await server.run() - - await wait(3000) - - expect(await pathExists(join(baseNativeModule, 'build'))).to.be.true - expect(await pathExists(join(baseNativeModule, 'prebuilds'))).to.be.true - - await makeGetRequest({ - url: server.url, - path: '/plugins/test-native/router', - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - - await removeNativeModule() - - await server.kill() - await server.run() - - expect(await pathExists(join(baseNativeModule, 'build'))).to.be.false - expect(await pathExists(join(baseNativeModule, 'prebuilds'))).to.be.false - - await makeGetRequest({ - url: server.url, - path: '/plugins/test-native/router', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - after(async function () { - await sqlCommand.cleanup() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/proxy.ts b/server/tests/api/server/proxy.ts deleted file mode 100644 index 9337468d5..000000000 --- a/server/tests/api/server/proxy.ts +++ /dev/null @@ -1,171 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectNotStartWith, expectStartWith, FIXTURE_URLS, MockProxy } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test proxy', function () { - let servers: PeerTubeServer[] = [] - let proxy: MockProxy - - const goodEnv = { HTTP_PROXY: '' } - const badEnv = { HTTP_PROXY: 'http://127.0.0.1:9000' } - - before(async function () { - this.timeout(120000) - - proxy = new MockProxy() - - const proxyPort = await proxy.initialize() - servers = await createMultipleServers(2) - - goodEnv.HTTP_PROXY = 'http://127.0.0.1:' + proxyPort - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await doubleFollow(servers[0], servers[1]) - }) - - describe('Federation', function () { - - it('Should succeed federation with the appropriate proxy config', async function () { - this.timeout(40000) - - await servers[0].kill() - await servers[0].run({}, { env: goodEnv }) - - await servers[0].videos.quickUpload({ name: 'video 1' }) - - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - } - }) - - it('Should fail federation with a wrong proxy config', async function () { - this.timeout(40000) - - await servers[0].kill() - await servers[0].run({}, { env: badEnv }) - - await servers[0].videos.quickUpload({ name: 'video 2' }) - - await waitJobs(servers) - - { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - } - - { - const { total, data } = await servers[1].videos.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - } - }) - }) - - describe('Videos import', async function () { - - function quickImport (expectedStatus: HttpStatusCode = HttpStatusCode.OK_200) { - return servers[0].imports.importVideo({ - attributes: { - name: 'video import', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - targetUrl: FIXTURE_URLS.peertube_long - }, - expectedStatus - }) - } - - it('Should succeed import with the appropriate proxy config', async function () { - this.timeout(240000) - - await servers[0].kill() - await servers[0].run({}, { env: goodEnv }) - - await quickImport() - - await waitJobs(servers) - - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - }) - - it('Should fail import with a wrong proxy config', async function () { - this.timeout(120000) - - await servers[0].kill() - await servers[0].run({}, { env: badEnv }) - - await quickImport(HttpStatusCode.BAD_REQUEST_400) - }) - }) - - describe('Object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(30000) - - await objectStorage.prepareDefaultMockBuckets() - }) - - it('Should succeed to upload to object storage with the appropriate proxy config', async function () { - this.timeout(120000) - - await servers[0].kill() - await servers[0].run(objectStorage.getDefaultMockConfig(), { env: goodEnv }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - - expectStartWith(video.files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) - }) - - it('Should fail to upload to object storage with a wrong proxy config', async function () { - this.timeout(120000) - - await servers[0].kill() - await servers[0].run(objectStorage.getDefaultMockConfig(), { env: badEnv }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - await waitJobs(servers, { skipDelayed: true }) - - const video = await servers[0].videos.get({ id: uuid }) - - expectNotStartWith(video.files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) - }) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - after(async function () { - await proxy.terminate() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts deleted file mode 100644 index 11c96c4b5..000000000 --- a/server/tests/api/server/reverse-proxy.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test application behind a reverse proxy', function () { - let server: PeerTubeServer - let userAccessToken: string - let videoId: string - - before(async function () { - this.timeout(60000) - - const config = { - rates_limit: { - api: { - max: 50, - window: 5000 - }, - signup: { - max: 3, - window: 5000 - }, - login: { - max: 20 - } - }, - signup: { - limit: 20 - } - } - - server = await createSingleServer(1, config) - await setAccessTokensToServers([ server ]) - - userAccessToken = await server.users.generateUserAndToken('user') - - const { uuid } = await server.videos.upload() - videoId = uuid - }) - - it('Should view a video only once with the same IP by default', async function () { - this.timeout(40000) - - await server.views.simulateView({ id: videoId }) - await server.views.simulateView({ id: videoId }) - - // Wait the repeatable job - await wait(8000) - - const video = await server.videos.get({ id: videoId }) - expect(video.views).to.equal(1) - }) - - it('Should view a video 2 times with the X-Forwarded-For header set', async function () { - this.timeout(20000) - - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.1,127.0.0.1' }) - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.2,127.0.0.1' }) - - // Wait the repeatable job - await wait(8000) - - const video = await server.videos.get({ id: videoId }) - expect(video.views).to.equal(3) - }) - - it('Should view a video only once with the same client IP in the X-Forwarded-For header', async function () { - this.timeout(20000) - - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.4,0.0.0.3,::ffff:127.0.0.1' }) - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.5,0.0.0.3,127.0.0.1' }) - - // Wait the repeatable job - await wait(8000) - - const video = await server.videos.get({ id: videoId }) - expect(video.views).to.equal(4) - }) - - it('Should view a video two times with a different client IP in the X-Forwarded-For header', async function () { - this.timeout(20000) - - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.8,0.0.0.6,127.0.0.1' }) - await server.views.simulateView({ id: videoId, xForwardedFor: '0.0.0.8,0.0.0.7,127.0.0.1' }) - - // Wait the repeatable job - await wait(8000) - - const video = await server.videos.get({ id: videoId }) - expect(video.views).to.equal(6) - }) - - it('Should rate limit logins', async function () { - const user = { username: 'root', password: 'fail' } - - for (let i = 0; i < 18; i++) { - await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - - await server.login.login({ user, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - }) - - it('Should rate limit signup', async function () { - for (let i = 0; i < 10; i++) { - try { - await server.registrations.register({ username: 'test' + i }) - } catch { - // empty - } - } - - await server.registrations.register({ username: 'test42', expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - }) - - it('Should not rate limit failed signup', async function () { - this.timeout(30000) - - await wait(7000) - - for (let i = 0; i < 3; i++) { - await server.registrations.register({ username: 'test' + i, expectedStatus: HttpStatusCode.CONFLICT_409 }) - } - - await server.registrations.register({ username: 'test43', expectedStatus: HttpStatusCode.NO_CONTENT_204 }) - - }) - - it('Should rate limit API calls', async function () { - this.timeout(30000) - - await wait(7000) - - for (let i = 0; i < 100; i++) { - try { - await server.videos.get({ id: videoId }) - } catch { - // don't care if it fails - } - } - - await server.videos.get({ id: videoId, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - }) - - it('Should rate limit API calls with a user but not with an admin', async function () { - await server.videos.get({ id: videoId, token: userAccessToken, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 }) - - await server.videos.get({ id: videoId, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/services.ts b/server/tests/api/server/services.ts deleted file mode 100644 index a10e9baed..000000000 --- a/server/tests/api/server/services.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' -import { Video, VideoPlaylistPrivacy } from '@shared/models' - -describe('Test services', function () { - let server: PeerTubeServer = null - let playlistUUID: string - let playlistDisplayName: string - let video: Video - - const urlSuffixes = [ - { - input: '', - output: '' - }, - { - input: '?param=1', - output: '' - }, - { - input: '?muted=1&warningTitle=0&toto=1', - output: '?muted=1&warningTitle=0' - } - ] - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - { - const attributes = { name: 'my super name' } - await server.videos.upload({ attributes }) - - const { data } = await server.videos.list() - video = data[0] - } - - { - const created = await server.playlists.create({ - attributes: { - displayName: 'The Life and Times of Scrooge McDuck', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id - } - }) - - playlistUUID = created.uuid - playlistDisplayName = 'The Life and Times of Scrooge McDuck' - - await server.playlists.addElement({ - playlistId: created.id, - attributes: { - videoId: video.id - } - }) - } - }) - - it('Should have a valid oEmbed video response', async function () { - for (const basePath of [ '/videos/watch/', '/w/' ]) { - for (const suffix of urlSuffixes) { - const oembedUrl = server.url + basePath + video.uuid + suffix.input - - const res = await server.services.getOEmbed({ oembedUrl }) - const expectedHtml = '' - - const expectedThumbnailUrl = 'http://' + server.host + video.previewPath - - expect(res.body.html).to.equal(expectedHtml) - expect(res.body.title).to.equal(video.name) - expect(res.body.author_name).to.equal(server.store.channel.displayName) - expect(res.body.width).to.equal(560) - expect(res.body.height).to.equal(315) - expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) - expect(res.body.thumbnail_width).to.equal(850) - expect(res.body.thumbnail_height).to.equal(480) - } - } - }) - - it('Should have a valid playlist oEmbed response', async function () { - for (const basePath of [ '/videos/watch/playlist/', '/w/p/' ]) { - for (const suffix of urlSuffixes) { - const oembedUrl = server.url + basePath + playlistUUID + suffix.input - - const res = await server.services.getOEmbed({ oembedUrl }) - const expectedHtml = '' - - expect(res.body.html).to.equal(expectedHtml) - expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck') - expect(res.body.author_name).to.equal(server.store.channel.displayName) - expect(res.body.width).to.equal(560) - expect(res.body.height).to.equal(315) - expect(res.body.thumbnail_url).exist - expect(res.body.thumbnail_width).to.equal(280) - expect(res.body.thumbnail_height).to.equal(157) - } - } - }) - - it('Should have a valid oEmbed response with small max height query', async function () { - for (const basePath of [ '/videos/watch/', '/w/' ]) { - const oembedUrl = 'http://' + server.host + basePath + video.uuid - const format = 'json' - const maxHeight = 50 - const maxWidth = 50 - - const res = await server.services.getOEmbed({ oembedUrl, format, maxHeight, maxWidth }) - const expectedHtml = '' - - expect(res.body.html).to.equal(expectedHtml) - expect(res.body.title).to.equal(video.name) - expect(res.body.author_name).to.equal(server.store.channel.displayName) - expect(res.body.height).to.equal(50) - expect(res.body.width).to.equal(50) - expect(res.body).to.not.have.property('thumbnail_url') - expect(res.body).to.not.have.property('thumbnail_width') - expect(res.body).to.not.have.property('thumbnail_height') - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/server/slow-follows.ts b/server/tests/api/server/slow-follows.ts deleted file mode 100644 index a967fa724..000000000 --- a/server/tests/api/server/slow-follows.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { Job } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test slow follows', function () { - let servers: PeerTubeServer[] = [] - - let afterFollows: Date - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - await doubleFollow(servers[0], servers[2]) - - afterFollows = new Date() - - for (let i = 0; i < 5; i++) { - await servers[0].videos.quickUpload({ name: 'video ' + i }) - } - - await waitJobs(servers) - }) - - it('Should only have broadcast jobs', async function () { - const { data } = await servers[0].jobs.list({ jobType: 'activitypub-http-unicast', sort: '-createdAt' }) - - for (const job of data) { - expect(new Date(job.createdAt)).below(afterFollows) - } - }) - - it('Should process bad follower', async function () { - this.timeout(30000) - - await servers[1].kill() - - // Set server 2 as bad follower - await servers[0].videos.quickUpload({ name: 'video 6' }) - await waitJobs(servers[0]) - - afterFollows = new Date() - const filter = (job: Job) => new Date(job.createdAt) > afterFollows - - // Resend another broadcast job - await servers[0].videos.quickUpload({ name: 'video 7' }) - await waitJobs(servers[0]) - - const resBroadcast = await servers[0].jobs.list({ jobType: 'activitypub-http-broadcast', sort: '-createdAt' }) - const resUnicast = await servers[0].jobs.list({ jobType: 'activitypub-http-unicast', sort: '-createdAt' }) - - const broadcast = resBroadcast.data.filter(filter) - const unicast = resUnicast.data.filter(filter) - - expect(unicast).to.have.lengthOf(2) - expect(broadcast).to.have.lengthOf(2) - - for (const u of unicast) { - expect(u.data.uri).to.equal(servers[1].url + '/inbox') - } - - for (const b of broadcast) { - expect(b.data.uris).to.have.lengthOf(1) - expect(b.data.uris[0]).to.equal(servers[2].url + '/inbox') - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts deleted file mode 100644 index a1bf189fa..000000000 --- a/server/tests/api/server/stats.ts +++ /dev/null @@ -1,279 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { ActivityType, VideoPlaylistPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test stats (excluding redundancy)', function () { - let servers: PeerTubeServer[] = [] - let channelId - const user = { - username: 'user1', - password: 'super_password' - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - - await setAccessTokensToServers(servers) - await setDefaultChannelAvatar(servers) - await setDefaultAccountAvatar(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].users.create({ username: user.username, password: user.password }) - - const { uuid } = await servers[0].videos.upload({ attributes: { fixture: 'video_short.webm' } }) - - await servers[0].comments.createThread({ videoId: uuid, text: 'comment' }) - - await servers[0].views.simulateView({ id: uuid }) - - // Wait the video views repeatable job - await wait(8000) - - await servers[2].follows.follow({ hosts: [ servers[0].url ] }) - await waitJobs(servers) - }) - - it('Should have the correct stats on instance 1', async function () { - const data = await servers[0].stats.get() - - expect(data.totalLocalVideoComments).to.equal(1) - expect(data.totalLocalVideos).to.equal(1) - expect(data.totalLocalVideoViews).to.equal(1) - expect(data.totalLocalVideoFilesSize).to.equal(218910) - expect(data.totalUsers).to.equal(2) - expect(data.totalVideoComments).to.equal(1) - expect(data.totalVideos).to.equal(1) - expect(data.totalInstanceFollowers).to.equal(2) - expect(data.totalInstanceFollowing).to.equal(1) - expect(data.totalLocalPlaylists).to.equal(0) - }) - - it('Should have the correct stats on instance 2', async function () { - const data = await servers[1].stats.get() - - expect(data.totalLocalVideoComments).to.equal(0) - expect(data.totalLocalVideos).to.equal(0) - expect(data.totalLocalVideoViews).to.equal(0) - expect(data.totalLocalVideoFilesSize).to.equal(0) - expect(data.totalUsers).to.equal(1) - expect(data.totalVideoComments).to.equal(1) - expect(data.totalVideos).to.equal(1) - expect(data.totalInstanceFollowers).to.equal(1) - expect(data.totalInstanceFollowing).to.equal(1) - expect(data.totalLocalPlaylists).to.equal(0) - }) - - it('Should have the correct stats on instance 3', async function () { - const data = await servers[2].stats.get() - - expect(data.totalLocalVideoComments).to.equal(0) - expect(data.totalLocalVideos).to.equal(0) - expect(data.totalLocalVideoViews).to.equal(0) - expect(data.totalUsers).to.equal(1) - expect(data.totalVideoComments).to.equal(1) - expect(data.totalVideos).to.equal(1) - expect(data.totalInstanceFollowing).to.equal(1) - expect(data.totalInstanceFollowers).to.equal(0) - expect(data.totalLocalPlaylists).to.equal(0) - }) - - it('Should have the correct total videos stats after an unfollow', async function () { - this.timeout(15000) - - await servers[2].follows.unfollow({ target: servers[0] }) - await waitJobs(servers) - - const data = await servers[2].stats.get() - - expect(data.totalVideos).to.equal(0) - }) - - it('Should have the correct active user stats', async function () { - const server = servers[0] - - { - const data = await server.stats.get() - - expect(data.totalDailyActiveUsers).to.equal(1) - expect(data.totalWeeklyActiveUsers).to.equal(1) - expect(data.totalMonthlyActiveUsers).to.equal(1) - } - - { - await server.login.getAccessToken(user) - - const data = await server.stats.get() - - expect(data.totalDailyActiveUsers).to.equal(2) - expect(data.totalWeeklyActiveUsers).to.equal(2) - expect(data.totalMonthlyActiveUsers).to.equal(2) - } - }) - - it('Should have the correct active channel stats', async function () { - const server = servers[0] - - { - const data = await server.stats.get() - - expect(data.totalLocalVideoChannels).to.equal(2) - expect(data.totalLocalDailyActiveVideoChannels).to.equal(1) - expect(data.totalLocalWeeklyActiveVideoChannels).to.equal(1) - expect(data.totalLocalMonthlyActiveVideoChannels).to.equal(1) - } - - { - const attributes = { - name: 'stats_channel', - displayName: 'My stats channel' - } - const created = await server.channels.create({ attributes }) - channelId = created.id - - const data = await server.stats.get() - - expect(data.totalLocalVideoChannels).to.equal(3) - expect(data.totalLocalDailyActiveVideoChannels).to.equal(1) - expect(data.totalLocalWeeklyActiveVideoChannels).to.equal(1) - expect(data.totalLocalMonthlyActiveVideoChannels).to.equal(1) - } - - { - await server.videos.upload({ attributes: { fixture: 'video_short.webm', channelId } }) - - const data = await server.stats.get() - - expect(data.totalLocalVideoChannels).to.equal(3) - expect(data.totalLocalDailyActiveVideoChannels).to.equal(2) - expect(data.totalLocalWeeklyActiveVideoChannels).to.equal(2) - expect(data.totalLocalMonthlyActiveVideoChannels).to.equal(2) - } - }) - - it('Should have the correct playlist stats', async function () { - const server = servers[0] - - { - const data = await server.stats.get() - expect(data.totalLocalPlaylists).to.equal(0) - } - - { - await server.playlists.create({ - attributes: { - displayName: 'playlist for count', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: channelId - } - }) - - const data = await server.stats.get() - expect(data.totalLocalPlaylists).to.equal(1) - } - }) - - it('Should correctly count video file sizes if transcoding is enabled', async function () { - this.timeout(120000) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: true, - webVideos: { - enabled: true - }, - hls: { - enabled: true - }, - resolutions: { - '0p': false, - '144p': false, - '240p': false, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - } - } - } - }) - - await servers[0].videos.upload({ attributes: { name: 'video', fixture: 'video_short.webm' } }) - - await waitJobs(servers) - - { - const data = await servers[1].stats.get() - expect(data.totalLocalVideoFilesSize).to.equal(0) - } - - { - const data = await servers[0].stats.get() - expect(data.totalLocalVideoFilesSize).to.be.greaterThan(500000) - expect(data.totalLocalVideoFilesSize).to.be.lessThan(600000) - } - }) - - it('Should have the correct AP stats', async function () { - this.timeout(120000) - - await servers[0].config.disableTranscoding() - - const first = await servers[1].stats.get() - - for (let i = 0; i < 10; i++) { - await servers[0].videos.upload({ attributes: { name: 'video' } }) - } - - await waitJobs(servers) - - await wait(6000) - - const second = await servers[1].stats.get() - expect(second.totalActivityPubMessagesProcessed).to.be.greaterThan(first.totalActivityPubMessagesProcessed) - - const apTypes: ActivityType[] = [ - 'Create', 'Update', 'Delete', 'Follow', 'Accept', 'Announce', 'Undo', 'Like', 'Reject', 'View', 'Dislike', 'Flag' - ] - - const processed = apTypes.reduce( - (previous, type) => previous + second['totalActivityPub' + type + 'MessagesSuccesses'], - 0 - ) - expect(second.totalActivityPubMessagesProcessed).to.equal(processed) - expect(second.totalActivityPubMessagesSuccesses).to.equal(processed) - - expect(second.totalActivityPubMessagesErrors).to.equal(0) - - for (const apType of apTypes) { - expect(second['totalActivityPub' + apType + 'MessagesErrors']).to.equal(0) - } - - await wait(6000) - - const third = await servers[1].stats.get() - expect(third.totalActivityPubMessagesWaiting).to.equal(0) - expect(third.activityPubMessagesProcessedPerSecond).to.be.lessThan(second.activityPubMessagesProcessedPerSecond) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/server/tracker.ts b/server/tests/api/server/tracker.ts deleted file mode 100644 index a0ce2ca35..000000000 --- a/server/tests/api/server/tracker.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */ - -import { decode as magnetUriDecode, encode as magnetUriEncode } from 'magnet-uri' -import WebTorrent from 'webtorrent' -import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test tracker', function () { - let server: PeerTubeServer - let badMagnet: string - let goodMagnet: string - - before(async function () { - this.timeout(60000) - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - { - const { uuid } = await server.videos.upload() - const video = await server.videos.get({ id: uuid }) - goodMagnet = video.files[0].magnetUri - - const parsed = magnetUriDecode(goodMagnet) - parsed.infoHash = '010597bb88b1968a5693a4fa8267c592ca65f2e9' - - badMagnet = magnetUriEncode(parsed) - } - }) - - it('Should succeed with the correct infohash', function (done) { - const webtorrent = new WebTorrent() - - const torrent = webtorrent.add(goodMagnet) - - torrent.on('error', done) - torrent.on('warning', warn => { - const message = typeof warn === 'string' ? warn : warn.message - if (message.includes('Unknown infoHash ')) return done(new Error('Error on infohash')) - }) - - torrent.on('done', done) - }) - - it('Should disable the tracker', function (done) { - this.timeout(20000) - - const errCb = () => done(new Error('Tracker is enabled')) - - killallServers([ server ]) - .then(() => server.run({ tracker: { enabled: false } })) - .then(() => { - const webtorrent = new WebTorrent() - - const torrent = webtorrent.add(goodMagnet) - - torrent.on('error', done) - torrent.on('warning', warn => { - const message = typeof warn === 'string' ? warn : warn.message - if (message.includes('disabled ')) { - torrent.off('done', errCb) - - return done() - } - }) - - torrent.on('done', errCb) - }) - }) - - it('Should return an error when adding an incorrect infohash', function (done) { - this.timeout(20000) - - killallServers([ server ]) - .then(() => server.run()) - .then(() => { - const webtorrent = new WebTorrent() - - const torrent = webtorrent.add(badMagnet) - - torrent.on('error', done) - torrent.on('warning', warn => { - const message = typeof warn === 'string' ? warn : warn.message - if (message.includes('Unknown infoHash ')) return done() - }) - - torrent.on('done', () => done(new Error('No error on infohash'))) - }) - }) - - it('Should block the IP after the failed infohash', function (done) { - const webtorrent = new WebTorrent() - - const torrent = webtorrent.add(goodMagnet) - - torrent.on('error', done) - torrent.on('warning', warn => { - const message = typeof warn === 'string' ? warn : warn.message - if (message.includes('Unsupported tracker protocol')) return done() - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/transcoding/audio-only.ts b/server/tests/api/transcoding/audio-only.ts deleted file mode 100644 index f4cc012ef..000000000 --- a/server/tests/api/transcoding/audio-only.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { getAudioStream, getVideoStreamDimensionsInfo } from '@shared/ffmpeg' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test audio only video transcoding', function () { - let servers: PeerTubeServer[] = [] - let videoUUID: string - let webVideoAudioFileUrl: string - let fragmentedAudioFileUrl: string - - before(async function () { - this.timeout(120000) - - const configOverride = { - transcoding: { - enabled: true, - resolutions: { - '0p': true, - '144p': false, - '240p': true, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - hls: { - enabled: true - }, - web_videos: { - enabled: true - } - } - } - servers = await createMultipleServers(2, configOverride) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - it('Should upload a video and transcode it', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'audio only' } }) - videoUUID = uuid - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - for (const files of [ video.files, video.streamingPlaylists[0].files ]) { - expect(files).to.have.lengthOf(3) - expect(files[0].resolution.id).to.equal(720) - expect(files[1].resolution.id).to.equal(240) - expect(files[2].resolution.id).to.equal(0) - } - - if (server.serverNumber === 1) { - webVideoAudioFileUrl = video.files[2].fileUrl - fragmentedAudioFileUrl = video.streamingPlaylists[0].files[2].fileUrl - } - } - }) - - it('0p transcoded video should not have video', async function () { - const paths = [ - servers[0].servers.buildWebVideoFilePath(webVideoAudioFileUrl), - servers[0].servers.buildFragmentedFilePath(videoUUID, fragmentedAudioFileUrl) - ] - - for (const path of paths) { - const { audioStream } = await getAudioStream(path) - expect(audioStream['codec_name']).to.be.equal('aac') - expect(audioStream['bit_rate']).to.be.at.most(384 * 8000) - - const size = await getVideoStreamDimensionsInfo(path) - - expect(size.height).to.equal(0) - expect(size.width).to.equal(0) - expect(size.isPortraitMode).to.be.false - expect(size.ratio).to.equal(0) - expect(size.resolution).to.equal(0) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/transcoding/create-transcoding.ts b/server/tests/api/transcoding/create-transcoding.ts deleted file mode 100644 index 9a891043c..000000000 --- a/server/tests/api/transcoding/create-transcoding.ts +++ /dev/null @@ -1,266 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkResolutionsInMasterPlaylist, expectStartWith } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoDetails } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createMultipleServers, - doubleFollow, - expectNoFailedTranscodingJob, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -async function checkFilesInObjectStorage (objectStorage: ObjectStorageCommand, video: VideoDetails) { - for (const file of video.files) { - expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - if (video.streamingPlaylists.length === 0) return - - const hlsPlaylist = video.streamingPlaylists[0] - for (const file of hlsPlaylist.files) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - expectStartWith(hlsPlaylist.playlistUrl, objectStorage.getMockPlaylistBaseUrl()) - await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - - expectStartWith(hlsPlaylist.segmentsSha256Url, objectStorage.getMockPlaylistBaseUrl()) - await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) -} - -function runTests (enableObjectStorage: boolean) { - let servers: PeerTubeServer[] = [] - let videoUUID: string - let publishedAt: string - - let shouldBeDeleted: string[] - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - const config = enableObjectStorage - ? objectStorage.getDefaultMockConfig() - : {} - - // Run server 2 to have transcoding enabled - servers = await createMultipleServers(2, config) - await setAccessTokensToServers(servers) - - await servers[0].config.disableTranscoding() - - await doubleFollow(servers[0], servers[1]) - - if (enableObjectStorage) await objectStorage.prepareDefaultMockBuckets() - - const { shortUUID } = await servers[0].videos.quickUpload({ name: 'video' }) - videoUUID = shortUUID - - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: videoUUID }) - publishedAt = video.publishedAt as string - - await servers[0].config.enableTranscoding() - }) - - it('Should generate HLS', async function () { - this.timeout(60000) - - await servers[0].videos.runTranscoding({ - videoId: videoUUID, - transcodingType: 'hls' - }) - - await waitJobs(servers) - await expectNoFailedTranscodingJob(servers[0]) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - expect(videoDetails.files).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5) - - if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) - } - }) - - it('Should generate Web Video', async function () { - this.timeout(60000) - - await servers[0].videos.runTranscoding({ - videoId: videoUUID, - transcodingType: 'web-video' - }) - - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - expect(videoDetails.files).to.have.lengthOf(5) - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5) - - if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) - } - }) - - it('Should generate Web Video from HLS only video', async function () { - this.timeout(60000) - - await servers[0].videos.removeAllWebVideoFiles({ videoId: videoUUID }) - await waitJobs(servers) - - await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' }) - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - expect(videoDetails.files).to.have.lengthOf(5) - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5) - - if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) - } - }) - - it('Should only generate Web Video', async function () { - this.timeout(60000) - - await servers[0].videos.removeHLSPlaylist({ videoId: videoUUID }) - await waitJobs(servers) - - await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' }) - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - expect(videoDetails.files).to.have.lengthOf(5) - expect(videoDetails.streamingPlaylists).to.have.lengthOf(0) - - if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) - } - }) - - it('Should correctly update HLS playlist on resolution change', async function () { - this.timeout(120000) - - await servers[0].config.updateExistingSubConfig({ - newConfig: { - transcoding: { - enabled: true, - resolutions: ConfigCommand.getCustomConfigResolutions(false), - - webVideos: { - enabled: true - }, - hls: { - enabled: true - } - } - } - }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'quick' }) - - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: uuid }) - - expect(videoDetails.files).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(1) - - if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) - - shouldBeDeleted = [ - videoDetails.streamingPlaylists[0].files[0].fileUrl, - videoDetails.streamingPlaylists[0].playlistUrl, - videoDetails.streamingPlaylists[0].segmentsSha256Url - ] - } - - await servers[0].config.updateExistingSubConfig({ - newConfig: { - transcoding: { - enabled: true, - resolutions: ConfigCommand.getCustomConfigResolutions(true), - - webVideos: { - enabled: true - }, - hls: { - enabled: true - } - } - } - }) - - await servers[0].videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' }) - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: uuid }) - - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5) - - if (enableObjectStorage) { - await checkFilesInObjectStorage(objectStorage, videoDetails) - - const hlsPlaylist = videoDetails.streamingPlaylists[0] - const resolutions = hlsPlaylist.files.map(f => f.resolution.id) - await checkResolutionsInMasterPlaylist({ server: servers[0], playlistUrl: hlsPlaylist.playlistUrl, resolutions }) - - const shaBody = await servers[0].streamingPlaylists.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, withRetry: true }) - expect(Object.keys(shaBody)).to.have.lengthOf(5) - } - } - }) - - it('Should have correctly deleted previous files', async function () { - for (const fileUrl of shouldBeDeleted) { - await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - - it('Should not have updated published at attributes', async function () { - const video = await servers[0].videos.get({ id: videoUUID }) - - expect(video.publishedAt).to.equal(publishedAt) - }) - - after(async function () { - if (objectStorage) await objectStorage.cleanupMock() - - await cleanupTests(servers) - }) -} - -describe('Test create transcoding jobs from API', function () { - - describe('On filesystem', function () { - runTests(false) - }) - - describe('On object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - runTests(true) - }) -}) diff --git a/server/tests/api/transcoding/hls.ts b/server/tests/api/transcoding/hls.ts deleted file mode 100644 index d67043c2a..000000000 --- a/server/tests/api/transcoding/hls.ts +++ /dev/null @@ -1,175 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { join } from 'path' -import { checkDirectoryIsEmpty, checkTmpIsEmpty, completeCheckHlsPlaylist } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' - -describe('Test HLS videos', function () { - let servers: PeerTubeServer[] = [] - - function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { - const videoUUIDs: string[] = [] - - it('Should upload a video and transcode it to HLS', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) - videoUUIDs.push(uuid) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) - }) - - it('Should upload an audio file and transcode it to HLS', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) - videoUUIDs.push(uuid) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ - servers, - videoUUID: uuid, - hlsOnly, - resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], - objectStorageBaseUrl - }) - }) - - it('Should update the video', async function () { - this.timeout(30000) - - await servers[0].videos.update({ id: videoUUIDs[0], attributes: { name: 'video 1 updated' } }) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ servers, videoUUID: videoUUIDs[0], hlsOnly, objectStorageBaseUrl }) - }) - - it('Should delete videos', async function () { - for (const uuid of videoUUIDs) { - await servers[0].videos.remove({ id: uuid }) - } - - await waitJobs(servers) - - for (const server of servers) { - for (const uuid of videoUUIDs) { - await server.videos.get({ id: uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - } - }) - - it('Should have the playlists/segment deleted from the disk', async function () { - for (const server of servers) { - await checkDirectoryIsEmpty(server, 'web-videos', [ 'private' ]) - await checkDirectoryIsEmpty(server, join('web-videos', 'private')) - - await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls'), [ 'private' ]) - await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls', 'private')) - } - }) - - it('Should have an empty tmp directory', async function () { - for (const server of servers) { - await checkTmpIsEmpty(server) - } - }) - } - - before(async function () { - this.timeout(120000) - - const configOverride = { - transcoding: { - enabled: true, - allow_audio_files: true, - hls: { - enabled: true - } - } - } - servers = await createMultipleServers(2, configOverride) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - describe('With Web Video & HLS enabled', function () { - runTestSuite(false) - }) - - describe('With only HLS enabled', function () { - - before(async function () { - await servers[0].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: true, - allowAudioFiles: true, - resolutions: { - '144p': false, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - }, - hls: { - enabled: true - }, - webVideos: { - enabled: false - } - } - } - }) - }) - - runTestSuite(true) - }) - - describe('With object storage enabled', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - const configOverride = objectStorage.getDefaultMockConfig() - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - await servers[0].run(configOverride) - }) - - runTestSuite(true, objectStorage.getMockPlaylistBaseUrl()) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/transcoding/index.ts b/server/tests/api/transcoding/index.ts deleted file mode 100644 index 9866418d6..000000000 --- a/server/tests/api/transcoding/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './audio-only' -export * from './create-transcoding' -export * from './hls' -export * from './transcoder' -export * from './update-while-transcoding' -export * from './video-studio' diff --git a/server/tests/api/transcoding/transcoder.ts b/server/tests/api/transcoding/transcoder.ts deleted file mode 100644 index 5386d236f..000000000 --- a/server/tests/api/transcoding/transcoder.ts +++ /dev/null @@ -1,800 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { canDoQuickTranscode } from '@server/lib/transcoding/transcoding-quick-transcode' -import { checkWebTorrentWorks, generateHighBitrateVideo, generateVideoWithFramerate } from '@server/tests/shared' -import { buildAbsoluteFixturePath, getAllFiles, getMaxTheoreticalBitrate, getMinTheoreticalBitrate, omit } from '@shared/core-utils' -import { - ffprobePromise, - getAudioStream, - getVideoStreamBitrate, - getVideoStreamDimensionsInfo, - getVideoStreamFPS, - hasAudioStream -} from '@shared/ffmpeg' -import { HttpStatusCode, VideoFileMetadata, VideoState } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -function updateConfigForTranscoding (server: PeerTubeServer) { - return server.config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: true, - allowAdditionalExtensions: true, - allowAudioFiles: true, - hls: { enabled: true }, - webVideos: { enabled: true }, - resolutions: { - '0p': false, - '144p': true, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - } - } - } - }) -} - -describe('Test video transcoding', function () { - let servers: PeerTubeServer[] = [] - let video4k: string - - before(async function () { - this.timeout(30_000) - - // Run servers - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - await updateConfigForTranscoding(servers[1]) - }) - - describe('Basic transcoding (or not)', function () { - - it('Should not transcode video on server 1', async function () { - this.timeout(60_000) - - const attributes = { - name: 'my super name for server 1', - description: 'my super description for server 1', - fixture: 'video_short.webm' - } - await servers[0].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - const video = data[0] - - const videoDetails = await server.videos.get({ id: video.id }) - expect(videoDetails.files).to.have.lengthOf(1) - - const magnetUri = videoDetails.files[0].magnetUri - expect(magnetUri).to.match(/\.webm/) - - await checkWebTorrentWorks(magnetUri, /\.webm$/) - } - }) - - it('Should transcode video on server 2', async function () { - this.timeout(120_000) - - const attributes = { - name: 'my super name for server 2', - description: 'my super description for server 2', - fixture: 'video_short.webm' - } - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(5) - - const magnetUri = videoDetails.files[0].magnetUri - expect(magnetUri).to.match(/\.mp4/) - - await checkWebTorrentWorks(magnetUri, /\.mp4$/) - } - }) - - it('Should wait for transcoding before publishing the video', async function () { - this.timeout(160_000) - - { - // Upload the video, but wait transcoding - const attributes = { - name: 'waiting video', - fixture: 'video_short1.webm', - waitTranscoding: true - } - const { uuid } = await servers[1].videos.upload({ attributes }) - const videoId = uuid - - // Should be in transcode state - const body = await servers[1].videos.get({ id: videoId }) - expect(body.name).to.equal('waiting video') - expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) - expect(body.state.label).to.equal('To transcode') - expect(body.waitTranscoding).to.be.true - - { - // Should have my video - const { data } = await servers[1].videos.listMyVideos() - const videoToFindInMine = data.find(v => v.name === attributes.name) - expect(videoToFindInMine).not.to.be.undefined - expect(videoToFindInMine.state.id).to.equal(VideoState.TO_TRANSCODE) - expect(videoToFindInMine.state.label).to.equal('To transcode') - expect(videoToFindInMine.waitTranscoding).to.be.true - } - - { - // Should not list this video - const { data } = await servers[1].videos.list() - const videoToFindInList = data.find(v => v.name === attributes.name) - expect(videoToFindInList).to.be.undefined - } - - // Server 1 should not have the video yet - await servers[0].videos.get({ id: videoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - const videoToFind = data.find(v => v.name === 'waiting video') - expect(videoToFind).not.to.be.undefined - - const videoDetails = await server.videos.get({ id: videoToFind.id }) - - expect(videoDetails.state.id).to.equal(VideoState.PUBLISHED) - expect(videoDetails.state.label).to.equal('Published') - expect(videoDetails.waitTranscoding).to.be.true - } - }) - - it('Should accept and transcode additional extensions', async function () { - this.timeout(300_000) - - for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) { - const attributes = { - name: fixture, - fixture - } - - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - expect(videoDetails.files).to.have.lengthOf(5) - - const magnetUri = videoDetails.files[0].magnetUri - expect(magnetUri).to.contain('.mp4') - } - } - }) - - it('Should transcode a 4k video', async function () { - this.timeout(200_000) - - const attributes = { - name: '4k video', - fixture: 'video_short_4k.mp4' - } - - const { uuid } = await servers[1].videos.upload({ attributes }) - video4k = uuid - - await waitJobs(servers) - - const resolutions = [ 144, 240, 360, 480, 720, 1080, 1440, 2160 ] - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: video4k }) - expect(videoDetails.files).to.have.lengthOf(resolutions.length) - - for (const r of resolutions) { - expect(videoDetails.files.find(f => f.resolution.id === r)).to.not.be.undefined - expect(videoDetails.streamingPlaylists[0].files.find(f => f.resolution.id === r)).to.not.be.undefined - } - } - }) - }) - - describe('Audio transcoding', function () { - - it('Should transcode high bit rate mp3 to proper bit rate', async function () { - this.timeout(60_000) - - const attributes = { - name: 'mp3_256k', - fixture: 'video_short_mp3_256k.mp4' - } - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(5) - - const file = videoDetails.files.find(f => f.resolution.id === 240) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const probe = await getAudioStream(path) - - if (probe.audioStream) { - expect(probe.audioStream['codec_name']).to.be.equal('aac') - expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000) - } else { - this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) - } - } - }) - - it('Should transcode video with no audio and have no audio itself', async function () { - this.timeout(60_000) - - const attributes = { - name: 'no_audio', - fixture: 'video_short_no_audio.mp4' - } - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - - const file = videoDetails.files.find(f => f.resolution.id === 240) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - - expect(await hasAudioStream(path)).to.be.false - } - }) - - it('Should leave the audio untouched, but properly transcode the video', async function () { - this.timeout(60_000) - - const attributes = { - name: 'untouched_audio', - fixture: 'video_short.mp4' - } - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(5) - - const fixturePath = buildAbsoluteFixturePath(attributes.fixture) - const fixtureVideoProbe = await getAudioStream(fixturePath) - - const file = videoDetails.files.find(f => f.resolution.id === 240) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - - const videoProbe = await getAudioStream(path) - - if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { - const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] - expect(omit(videoProbe.audioStream, toOmit)).to.be.deep.equal(omit(fixtureVideoProbe.audioStream, toOmit)) - } else { - this.fail('Could not retrieve the audio stream on ' + videoProbe.absolutePath) - } - } - }) - }) - - describe('Audio upload', function () { - - function runSuite (mode: 'legacy' | 'resumable') { - - before(async function () { - await servers[1].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - hls: { enabled: true }, - webVideos: { enabled: true }, - resolutions: { - '0p': false, - '144p': false, - '240p': false, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - } - } - } - }) - }) - - it('Should merge an audio file with the preview file', async function () { - this.timeout(60_000) - - const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' } - await servers[1].videos.upload({ attributes, mode }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === 'audio_with_preview') - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(1) - - await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: videoDetails.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - - const magnetUri = videoDetails.files[0].magnetUri - expect(magnetUri).to.contain('.mp4') - } - }) - - it('Should upload an audio file and choose a default background image', async function () { - this.timeout(60_000) - - const attributes = { name: 'audio_without_preview', fixture: 'sample.ogg' } - await servers[1].videos.upload({ attributes, mode }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === 'audio_without_preview') - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(1) - - await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: videoDetails.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - - const magnetUri = videoDetails.files[0].magnetUri - expect(magnetUri).to.contain('.mp4') - } - }) - - it('Should upload an audio file and create an audio version only', async function () { - this.timeout(60_000) - - await servers[1].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - hls: { enabled: true }, - webVideos: { enabled: true }, - resolutions: { - '0p': true, - '144p': false, - '240p': false, - '360p': false - } - } - } - }) - - const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' } - const { id } = await servers[1].videos.upload({ attributes, mode }) - - await waitJobs(servers) - - for (const server of servers) { - const videoDetails = await server.videos.get({ id }) - - for (const files of [ videoDetails.files, videoDetails.streamingPlaylists[0].files ]) { - expect(files).to.have.lengthOf(2) - expect(files.find(f => f.resolution.id === 0)).to.not.be.undefined - } - } - - await updateConfigForTranscoding(servers[1]) - }) - } - - describe('Legacy upload', function () { - runSuite('legacy') - }) - - describe('Resumable upload', function () { - runSuite('resumable') - }) - }) - - describe('Framerate', function () { - - it('Should transcode a 60 FPS video', async function () { - this.timeout(60_000) - - const attributes = { - name: 'my super 30fps name for server 2', - description: 'my super 30fps description for server 2', - fixture: '60fps_720p_small.mp4' - } - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video = data.find(v => v.name === attributes.name) - const videoDetails = await server.videos.get({ id: video.id }) - - expect(videoDetails.files).to.have.lengthOf(5) - expect(videoDetails.files[0].fps).to.be.above(58).and.below(62) - expect(videoDetails.files[1].fps).to.be.below(31) - expect(videoDetails.files[2].fps).to.be.below(31) - expect(videoDetails.files[3].fps).to.be.below(31) - expect(videoDetails.files[4].fps).to.be.below(31) - - for (const resolution of [ 144, 240, 360, 480 ]) { - const file = videoDetails.files.find(f => f.resolution.id === resolution) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const fps = await getVideoStreamFPS(path) - - expect(fps).to.be.below(31) - } - - const file = videoDetails.files.find(f => f.resolution.id === 720) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const fps = await getVideoStreamFPS(path) - - expect(fps).to.be.above(58).and.below(62) - } - }) - - it('Should downscale to the closest divisor standard framerate', async function () { - this.timeout(200_000) - - let tempFixturePath: string - - { - tempFixturePath = await generateVideoWithFramerate(59) - - const fps = await getVideoStreamFPS(tempFixturePath) - expect(fps).to.be.equal(59) - } - - const attributes = { - name: '59fps video', - description: '59fps video', - fixture: tempFixturePath - } - - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const { id } = data.find(v => v.name === attributes.name) - const video = await server.videos.get({ id }) - - { - const file = video.files.find(f => f.resolution.id === 240) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const fps = await getVideoStreamFPS(path) - expect(fps).to.be.equal(25) - } - - { - const file = video.files.find(f => f.resolution.id === 720) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const fps = await getVideoStreamFPS(path) - expect(fps).to.be.equal(59) - } - } - }) - }) - - describe('Bitrate control', function () { - - it('Should respect maximum bitrate values', async function () { - this.timeout(160_000) - - const tempFixturePath = await generateHighBitrateVideo() - - const attributes = { - name: 'high bitrate video', - description: 'high bitrate video', - fixture: tempFixturePath - } - - await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const { id } = data.find(v => v.name === attributes.name) - const video = await server.videos.get({ id }) - - for (const resolution of [ 240, 360, 480, 720, 1080 ]) { - const file = video.files.find(f => f.resolution.id === resolution) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - - const bitrate = await getVideoStreamBitrate(path) - const fps = await getVideoStreamFPS(path) - const dataResolution = await getVideoStreamDimensionsInfo(path) - - expect(resolution).to.equal(resolution) - - const maxBitrate = getMaxTheoreticalBitrate({ ...dataResolution, fps }) - expect(bitrate).to.be.below(maxBitrate) - } - } - }) - - it('Should not transcode to an higher bitrate than the original file but above our low limit', async function () { - this.timeout(160_000) - - const newConfig = { - transcoding: { - enabled: true, - resolutions: { - '144p': true, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - }, - webVideos: { enabled: true }, - hls: { enabled: true } - } - } - await servers[1].config.updateCustomSubConfig({ newConfig }) - - const attributes = { - name: 'low bitrate', - fixture: 'low-bitrate.mp4' - } - - const { id } = await servers[1].videos.upload({ attributes }) - - await waitJobs(servers) - - const video = await servers[1].videos.get({ id }) - - const resolutions = [ 240, 360, 480, 720, 1080 ] - for (const r of resolutions) { - const file = video.files.find(f => f.resolution.id === r) - - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - const bitrate = await getVideoStreamBitrate(path) - - const inputBitrate = 60_000 - const limit = getMinTheoreticalBitrate({ fps: 10, ratio: 1, resolution: r }) - let belowValue = Math.max(inputBitrate, limit) - belowValue += belowValue * 0.20 // Apply 20% margin because bitrate control is not very precise - - expect(bitrate, `${path} not below ${limit}`).to.be.below(belowValue) - } - }) - }) - - describe('FFprobe', function () { - - it('Should provide valid ffprobe data', async function () { - this.timeout(160_000) - - const videoUUID = (await servers[1].videos.quickUpload({ name: 'ffprobe data' })).uuid - await waitJobs(servers) - - { - const video = await servers[1].videos.get({ id: videoUUID }) - const file = video.files.find(f => f.resolution.id === 240) - const path = servers[1].servers.buildWebVideoFilePath(file.fileUrl) - - const probe = await ffprobePromise(path) - const metadata = new VideoFileMetadata(probe) - - // expected format properties - for (const p of [ - 'tags.encoder', - 'format_long_name', - 'size', - 'bit_rate' - ]) { - expect(metadata.format).to.have.nested.property(p) - } - - // expected stream properties - for (const p of [ - 'codec_long_name', - 'profile', - 'width', - 'height', - 'display_aspect_ratio', - 'avg_frame_rate', - 'pix_fmt' - ]) { - expect(metadata.streams[0]).to.have.nested.property(p) - } - - expect(metadata).to.not.have.nested.property('format.filename') - } - - for (const server of servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - - const videoFiles = getAllFiles(videoDetails) - expect(videoFiles).to.have.lengthOf(10) - - for (const file of videoFiles) { - expect(file.metadata).to.be.undefined - expect(file.metadataUrl).to.exist - expect(file.metadataUrl).to.contain(servers[1].url) - expect(file.metadataUrl).to.contain(videoUUID) - - const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) - expect(metadata).to.have.nested.property('format.size') - } - } - }) - - it('Should correctly detect if quick transcode is possible', async function () { - this.timeout(10_000) - - expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.mp4'))).to.be.true - expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.webm'))).to.be.false - }) - }) - - describe('Transcoding job queue', function () { - - it('Should have the appropriate priorities for transcoding jobs', async function () { - const body = await servers[1].jobs.list({ - start: 0, - count: 100, - sort: 'createdAt', - jobType: 'video-transcoding' - }) - - const jobs = body.data - const transcodingJobs = jobs.filter(j => j.data.videoUUID === video4k) - - expect(transcodingJobs).to.have.lengthOf(16) - - const hlsJobs = transcodingJobs.filter(j => j.data.type === 'new-resolution-to-hls') - const webVideoJobs = transcodingJobs.filter(j => j.data.type === 'new-resolution-to-web-video') - const optimizeJobs = transcodingJobs.filter(j => j.data.type === 'optimize-to-web-video') - - expect(hlsJobs).to.have.lengthOf(8) - expect(webVideoJobs).to.have.lengthOf(7) - expect(optimizeJobs).to.have.lengthOf(1) - - for (const j of optimizeJobs.concat(hlsJobs.concat(webVideoJobs))) { - expect(j.priority).to.be.greaterThan(100) - expect(j.priority).to.be.lessThan(150) - } - }) - }) - - describe('Bounded transcoding', function () { - - it('Should not generate an upper resolution than original file', async function () { - this.timeout(120_000) - - await servers[0].config.updateExistingSubConfig({ - newConfig: { - transcoding: { - enabled: true, - hls: { enabled: true }, - webVideos: { enabled: true }, - resolutions: { - '0p': false, - '144p': false, - '240p': true, - '360p': false, - '480p': true, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - alwaysTranscodeOriginalResolution: false - } - } - }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video', fixture: 'video_short.webm' }) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - const hlsFiles = video.streamingPlaylists[0].files - - expect(video.files).to.have.lengthOf(2) - expect(hlsFiles).to.have.lengthOf(2) - - // eslint-disable-next-line @typescript-eslint/require-array-sort-compare - const resolutions = getAllFiles(video).map(f => f.resolution.id).sort() - expect(resolutions).to.deep.equal([ 240, 240, 480, 480 ]) - }) - - it('Should only keep the original resolution if all resolutions are disabled', async function () { - this.timeout(120_000) - - await servers[0].config.updateExistingSubConfig({ - newConfig: { - transcoding: { - resolutions: { - '0p': false, - '144p': false, - '240p': false, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - } - } - } - }) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video', fixture: 'video_short.webm' }) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - const hlsFiles = video.streamingPlaylists[0].files - - expect(video.files).to.have.lengthOf(1) - expect(hlsFiles).to.have.lengthOf(1) - - expect(video.files[0].resolution.id).to.equal(720) - expect(hlsFiles[0].resolution.id).to.equal(720) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/transcoding/update-while-transcoding.ts b/server/tests/api/transcoding/update-while-transcoding.ts deleted file mode 100644 index cfb4fa0cc..000000000 --- a/server/tests/api/transcoding/update-while-transcoding.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { completeCheckHlsPlaylist } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled, wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test update video privacy while transcoding', function () { - let servers: PeerTubeServer[] = [] - - const videoUUIDs: string[] = [] - - function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { - - it('Should not have an error while quickly updating a private video to public after upload #1', async function () { - this.timeout(360_000) - - const attributes = { - name: 'quick update', - privacy: VideoPrivacy.PRIVATE - } - - const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: false }) - await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - videoUUIDs.push(uuid) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) - }) - - it('Should not have an error while quickly updating a private video to public after upload #2', async function () { - this.timeout(60000) - - { - const attributes = { - name: 'quick update 2', - privacy: VideoPrivacy.PRIVATE - } - - const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) - await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - videoUUIDs.push(uuid) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) - } - }) - - it('Should not have an error while quickly updating a private video to public after upload #3', async function () { - this.timeout(60000) - - const attributes = { - name: 'quick update 3', - privacy: VideoPrivacy.PRIVATE - } - - const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) - await wait(1000) - await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - videoUUIDs.push(uuid) - - await waitJobs(servers) - - await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) - }) - } - - before(async function () { - this.timeout(120000) - - const configOverride = { - transcoding: { - enabled: true, - allow_audio_files: true, - hls: { - enabled: true - } - } - } - servers = await createMultipleServers(2, configOverride) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - describe('With Web Video & HLS enabled', function () { - runTestSuite(false) - }) - - describe('With only HLS enabled', function () { - - before(async function () { - await servers[0].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: true, - allowAudioFiles: true, - resolutions: { - '144p': false, - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - }, - hls: { - enabled: true - }, - webVideos: { - enabled: false - } - } - } - }) - }) - - runTestSuite(true) - }) - - describe('With object storage enabled', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - const configOverride = objectStorage.getDefaultMockConfig() - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - await servers[0].run(configOverride) - }) - - runTestSuite(true, objectStorage.getMockPlaylistBaseUrl()) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/transcoding/video-studio.ts b/server/tests/api/transcoding/video-studio.ts deleted file mode 100644 index ba68f8e24..000000000 --- a/server/tests/api/transcoding/video-studio.ts +++ /dev/null @@ -1,377 +0,0 @@ -import { expect } from 'chai' -import { checkPersistentTmpIsEmpty, checkVideoDuration, expectStartWith } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils' -import { VideoStudioTask } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - VideoStudioCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test video studio', function () { - let servers: PeerTubeServer[] = [] - let videoUUID: string - - async function renewVideo (fixture = 'video_short.webm') { - const video = await servers[0].videos.quickUpload({ name: 'video', fixture }) - videoUUID = video.uuid - - await waitJobs(servers) - } - - async function createTasks (tasks: VideoStudioTask[]) { - await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks }) - await waitJobs(servers) - } - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableMinimumTranscoding() - - await servers[0].config.enableStudio() - }) - - describe('Cutting', function () { - - it('Should cut the beginning of the video', async function () { - this.timeout(120_000) - - await renewVideo() - await waitJobs(servers) - - const beforeTasks = new Date() - - await createTasks([ - { - name: 'cut', - options: { - start: 2 - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 3) - - const video = await server.videos.get({ id: videoUUID }) - expect(new Date(video.publishedAt)).to.be.below(beforeTasks) - } - }) - - it('Should cut the end of the video', async function () { - this.timeout(120_000) - await renewVideo() - - await createTasks([ - { - name: 'cut', - options: { - end: 2 - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 2) - } - }) - - it('Should cut start/end of the video', async function () { - this.timeout(120_000) - await renewVideo('video_short1.webm') // 10 seconds video duration - - await createTasks([ - { - name: 'cut', - options: { - start: 2, - end: 6 - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 4) - } - }) - }) - - describe('Intro/Outro', function () { - - it('Should add an intro', async function () { - this.timeout(120_000) - await renewVideo() - - await createTasks([ - { - name: 'add-intro', - options: { - file: 'video_short.webm' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 10) - } - }) - - it('Should add an outro', async function () { - this.timeout(120_000) - await renewVideo() - - await createTasks([ - { - name: 'add-outro', - options: { - file: 'video_very_short_240p.mp4' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 7) - } - }) - - it('Should add an intro/outro', async function () { - this.timeout(120_000) - await renewVideo() - - await createTasks([ - { - name: 'add-intro', - options: { - file: 'video_very_short_240p.mp4' - } - }, - { - name: 'add-outro', - options: { - // Different frame rate - file: 'video_short2.webm' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 12) - } - }) - - it('Should add an intro to a video without audio', async function () { - this.timeout(120_000) - await renewVideo('video_short_no_audio.mp4') - - await createTasks([ - { - name: 'add-intro', - options: { - file: 'video_very_short_240p.mp4' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 7) - } - }) - - it('Should add an outro without audio to a video with audio', async function () { - this.timeout(120_000) - await renewVideo() - - await createTasks([ - { - name: 'add-outro', - options: { - file: 'video_short_no_audio.mp4' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 10) - } - }) - - it('Should add an outro without audio to a video with audio', async function () { - this.timeout(120_000) - await renewVideo('video_short_no_audio.mp4') - - await createTasks([ - { - name: 'add-outro', - options: { - file: 'video_short_no_audio.mp4' - } - } - ]) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 10) - } - }) - }) - - describe('Watermark', function () { - - it('Should add a watermark to the video', async function () { - this.timeout(120_000) - await renewVideo() - - const video = await servers[0].videos.get({ id: videoUUID }) - const oldFileUrls = getAllFiles(video).map(f => f.fileUrl) - - await createTasks([ - { - name: 'add-watermark', - options: { - file: 'custom-thumbnail.png' - } - } - ]) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - const fileUrls = getAllFiles(video).map(f => f.fileUrl) - - for (const oldUrl of oldFileUrls) { - expect(fileUrls).to.not.include(oldUrl) - } - } - }) - }) - - describe('Complex tasks', function () { - it('Should run a complex task', async function () { - this.timeout(240_000) - await renewVideo() - - await createTasks(VideoStudioCommand.getComplexTask()) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 9) - } - }) - }) - - describe('HLS only studio edition', function () { - - before(async function () { - // Disable Web Videos - await servers[0].config.updateExistingSubConfig({ - newConfig: { - transcoding: { - webVideos: { - enabled: false - } - } - } - }) - }) - - it('Should run a complex task on HLS only video', async function () { - this.timeout(240_000) - await renewVideo() - - await createTasks(VideoStudioCommand.getComplexTask()) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.files).to.have.lengthOf(0) - - await checkVideoDuration(server, videoUUID, 9) - } - }) - }) - - describe('Server restart', function () { - - it('Should still be able to run video edition after a server restart', async function () { - this.timeout(240_000) - - await renewVideo() - await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks: VideoStudioCommand.getComplexTask() }) - - await servers[0].kill() - await servers[0].run() - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoDuration(server, videoUUID, 9) - } - }) - - it('Should have an empty persistent tmp directory', async function () { - await checkPersistentTmpIsEmpty(servers[0]) - }) - }) - - describe('Object storage studio edition', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - await servers[0].run(objectStorage.getDefaultMockConfig()) - - await servers[0].config.enableMinimumTranscoding() - }) - - it('Should run a complex task on a video in object storage', async function () { - this.timeout(240_000) - await renewVideo() - - const video = await servers[0].videos.get({ id: videoUUID }) - const oldFileUrls = getAllFiles(video).map(f => f.fileUrl) - - await createTasks(VideoStudioCommand.getComplexTask()) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - const files = getAllFiles(video) - - for (const f of files) { - expect(oldFileUrls).to.not.include(f.fileUrl) - } - - for (const webVideoFile of video.files) { - expectStartWith(webVideoFile.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - - for (const hlsFile of video.streamingPlaylists[0].files) { - expectStartWith(hlsFile.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - } - - await checkVideoDuration(server, videoUUID, 9) - } - }) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/users/index.ts b/server/tests/api/users/index.ts deleted file mode 100644 index a4443a8ec..000000000 --- a/server/tests/api/users/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './oauth' -import './registrations`' -import './two-factor' -import './user-subscriptions' -import './user-videos' -import './users' -import './users-multiple-servers' -import './users-email-verification' diff --git a/server/tests/api/users/oauth.ts b/server/tests/api/users/oauth.ts deleted file mode 100644 index 153615875..000000000 --- a/server/tests/api/users/oauth.ts +++ /dev/null @@ -1,197 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { SQLCommand } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, OAuth2ErrorCode, PeerTubeProblemDocument } from '@shared/models' -import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test oauth', function () { - let server: PeerTubeServer - let sqlCommand: SQLCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { - rates_limit: { - login: { - max: 30 - } - } - }) - - await setAccessTokensToServers([ server ]) - - sqlCommand = new SQLCommand(server) - }) - - describe('OAuth client', function () { - - function expectInvalidClient (body: PeerTubeProblemDocument) { - expect(body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT) - expect(body.error).to.contain('client is invalid') - expect(body.type.startsWith('https://')).to.be.true - expect(body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT) - } - - it('Should create a new client') - - it('Should return the first client') - - it('Should remove the last client') - - it('Should not login with an invalid client id', async function () { - const client = { id: 'client', secret: server.store.client.secret } - const body = await server.login.login({ client, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - expectInvalidClient(body) - }) - - it('Should not login with an invalid client secret', async function () { - const client = { id: server.store.client.id, secret: 'coucou' } - const body = await server.login.login({ client, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - expectInvalidClient(body) - }) - }) - - describe('Login', function () { - - function expectInvalidCredentials (body: PeerTubeProblemDocument) { - expect(body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT) - expect(body.error).to.contain('credentials are invalid') - expect(body.type.startsWith('https://')).to.be.true - expect(body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT) - } - - it('Should not login with an invalid username', async function () { - const user = { username: 'captain crochet', password: server.store.user.password } - const body = await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - expectInvalidCredentials(body) - }) - - it('Should not login with an invalid password', async function () { - const user = { username: server.store.user.username, password: 'mew_three' } - const body = await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - expectInvalidCredentials(body) - }) - - it('Should be able to login', async function () { - await server.login.login({ expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should be able to login with an insensitive username', async function () { - const user = { username: 'RoOt', password: server.store.user.password } - await server.login.login({ user, expectedStatus: HttpStatusCode.OK_200 }) - - const user2 = { username: 'rOoT', password: server.store.user.password } - await server.login.login({ user: user2, expectedStatus: HttpStatusCode.OK_200 }) - - const user3 = { username: 'ROOt', password: server.store.user.password } - await server.login.login({ user: user3, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('Logout', function () { - - it('Should logout (revoke token)', async function () { - await server.login.logout({ token: server.accessToken }) - }) - - it('Should not be able to get the user information', async function () { - await server.users.getMyInfo({ expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not be able to upload a video', async function () { - await server.videos.upload({ attributes: { name: 'video' }, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should be able to login again', async function () { - const body = await server.login.login() - server.accessToken = body.access_token - server.refreshToken = body.refresh_token - }) - - it('Should be able to get my user information again', async function () { - await server.users.getMyInfo() - }) - - it('Should have an expired access token', async function () { - this.timeout(60000) - - await sqlCommand.setTokenField(server.accessToken, 'accessTokenExpiresAt', new Date().toISOString()) - await sqlCommand.setTokenField(server.accessToken, 'refreshTokenExpiresAt', new Date().toISOString()) - - await killallServers([ server ]) - await server.run() - - await server.users.getMyInfo({ expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not be able to refresh an access token with an expired refresh token', async function () { - await server.login.refreshToken({ refreshToken: server.refreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should refresh the token', async function () { - this.timeout(50000) - - const futureDate = new Date(new Date().getTime() + 1000 * 60).toISOString() - await sqlCommand.setTokenField(server.accessToken, 'refreshTokenExpiresAt', futureDate) - - await killallServers([ server ]) - await server.run() - - const res = await server.login.refreshToken({ refreshToken: server.refreshToken }) - server.accessToken = res.body.access_token - server.refreshToken = res.body.refresh_token - }) - - it('Should be able to get my user information again', async function () { - await server.users.getMyInfo() - }) - }) - - describe('Custom token lifetime', function () { - before(async function () { - this.timeout(120_000) - - await server.kill() - await server.run({ - oauth2: { - token_lifetime: { - access_token: '2 seconds', - refresh_token: '2 seconds' - } - } - }) - }) - - it('Should have a very short access token lifetime', async function () { - this.timeout(50000) - - const { access_token: accessToken } = await server.login.login() - await server.users.getMyInfo({ token: accessToken }) - - await wait(3000) - await server.users.getMyInfo({ token: accessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should have a very short refresh token lifetime', async function () { - this.timeout(50000) - - const { refresh_token: refreshToken } = await server.login.login() - await server.login.refreshToken({ refreshToken }) - - await wait(3000) - await server.login.refreshToken({ refreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - }) - - after(async function () { - await sqlCommand.cleanup() - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/registrations.ts b/server/tests/api/users/registrations.ts deleted file mode 100644 index e6524f07d..000000000 --- a/server/tests/api/users/registrations.ts +++ /dev/null @@ -1,415 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockSmtpServer } from '@server/tests/shared' -import { UserRegistrationState, UserRole } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test registrations', function () { - let server: PeerTubeServer - - const emails: object[] = [] - let emailPort: number - - before(async function () { - this.timeout(30000) - - emailPort = await MockSmtpServer.Instance.collectEmails(emails) - - server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(emailPort)) - - await setAccessTokensToServers([ server ]) - await server.config.enableSignup(false) - }) - - describe('Direct registrations of a new user', function () { - let user1Token: string - - it('Should register a new user', async function () { - const user = { displayName: 'super user 1', username: 'user_1', password: 'my super password' } - const channel = { name: 'my_user_1_channel', displayName: 'my channel rocks' } - - await server.registrations.register({ ...user, channel }) - }) - - it('Should be able to login with this registered user', async function () { - const user1 = { username: 'user_1', password: 'my super password' } - - user1Token = await server.login.getAccessToken(user1) - }) - - it('Should have the correct display name', async function () { - const user = await server.users.getMyInfo({ token: user1Token }) - expect(user.account.displayName).to.equal('super user 1') - }) - - it('Should have the correct video quota', async function () { - const user = await server.users.getMyInfo({ token: user1Token }) - expect(user.videoQuota).to.equal(5 * 1024 * 1024) - }) - - it('Should have created the channel', async function () { - const { displayName } = await server.channels.get({ channelName: 'my_user_1_channel' }) - - expect(displayName).to.equal('my channel rocks') - }) - - it('Should remove me', async function () { - { - const { data } = await server.users.list() - expect(data.find(u => u.username === 'user_1')).to.not.be.undefined - } - - await server.users.deleteMe({ token: user1Token }) - - { - const { data } = await server.users.list() - expect(data.find(u => u.username === 'user_1')).to.be.undefined - } - }) - }) - - describe('Registration requests', function () { - let id2: number - let id3: number - let id4: number - - let user2Token: string - let user3Token: string - - before(async function () { - this.timeout(60000) - - await server.config.enableSignup(true) - - { - const { id } = await server.registrations.requestRegistration({ - username: 'user4', - registrationReason: 'registration reason 4' - }) - - id4 = id - } - }) - - it('Should request a registration without a channel', async function () { - { - const { id } = await server.registrations.requestRegistration({ - username: 'user2', - displayName: 'my super user 2', - email: 'user2@example.com', - password: 'user2password', - registrationReason: 'registration reason 2' - }) - - id2 = id - } - }) - - it('Should request a registration with a channel', async function () { - const { id } = await server.registrations.requestRegistration({ - username: 'user3', - displayName: 'my super user 3', - channel: { - displayName: 'my user 3 channel', - name: 'super_user3_channel' - }, - email: 'user3@example.com', - password: 'user3password', - registrationReason: 'registration reason 3' - }) - - id3 = id - }) - - it('Should list these registration requests', async function () { - { - const { total, data } = await server.registrations.list({ sort: '-createdAt' }) - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - - { - expect(data[0].id).to.equal(id3) - expect(data[0].username).to.equal('user3') - expect(data[0].accountDisplayName).to.equal('my super user 3') - - expect(data[0].channelDisplayName).to.equal('my user 3 channel') - expect(data[0].channelHandle).to.equal('super_user3_channel') - - expect(data[0].createdAt).to.exist - expect(data[0].updatedAt).to.exist - - expect(data[0].email).to.equal('user3@example.com') - expect(data[0].emailVerified).to.be.null - - expect(data[0].moderationResponse).to.be.null - expect(data[0].registrationReason).to.equal('registration reason 3') - expect(data[0].state.id).to.equal(UserRegistrationState.PENDING) - expect(data[0].state.label).to.equal('Pending') - expect(data[0].user).to.be.null - } - - { - expect(data[1].id).to.equal(id2) - expect(data[1].username).to.equal('user2') - expect(data[1].accountDisplayName).to.equal('my super user 2') - - expect(data[1].channelDisplayName).to.be.null - expect(data[1].channelHandle).to.be.null - - expect(data[1].createdAt).to.exist - expect(data[1].updatedAt).to.exist - - expect(data[1].email).to.equal('user2@example.com') - expect(data[1].emailVerified).to.be.null - - expect(data[1].moderationResponse).to.be.null - expect(data[1].registrationReason).to.equal('registration reason 2') - expect(data[1].state.id).to.equal(UserRegistrationState.PENDING) - expect(data[1].state.label).to.equal('Pending') - expect(data[1].user).to.be.null - } - - { - expect(data[2].username).to.equal('user4') - } - } - - { - const { total, data } = await server.registrations.list({ count: 1, start: 1, sort: 'createdAt' }) - - expect(total).to.equal(3) - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(id2) - } - - { - const { total, data } = await server.registrations.list({ search: 'user3' }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(id3) - } - }) - - it('Should reject a registration request', async function () { - await server.registrations.reject({ id: id4, moderationResponse: 'I do not want id 4 on this instance' }) - }) - - it('Should have sent an email to the user explanining the registration has been rejected', async function () { - this.timeout(50000) - - await waitJobs([ server ]) - - const email = emails.find(e => e['to'][0]['address'] === 'user4@example.com') - expect(email).to.exist - - expect(email['subject']).to.contain('been rejected') - expect(email['text']).to.contain('been rejected') - expect(email['text']).to.contain('I do not want id 4 on this instance') - }) - - it('Should accept registration requests', async function () { - await server.registrations.accept({ id: id2, moderationResponse: 'Welcome id 2' }) - await server.registrations.accept({ id: id3, moderationResponse: 'Welcome id 3' }) - }) - - it('Should have sent an email to the user explanining the registration has been accepted', async function () { - this.timeout(50000) - - await waitJobs([ server ]) - - { - const email = emails.find(e => e['to'][0]['address'] === 'user2@example.com') - expect(email).to.exist - - expect(email['subject']).to.contain('been accepted') - expect(email['text']).to.contain('been accepted') - expect(email['text']).to.contain('Welcome id 2') - } - - { - const email = emails.find(e => e['to'][0]['address'] === 'user3@example.com') - expect(email).to.exist - - expect(email['subject']).to.contain('been accepted') - expect(email['text']).to.contain('been accepted') - expect(email['text']).to.contain('Welcome id 3') - } - }) - - it('Should login with these users', async function () { - user2Token = await server.login.getAccessToken({ username: 'user2', password: 'user2password' }) - user3Token = await server.login.getAccessToken({ username: 'user3', password: 'user3password' }) - }) - - it('Should have created the appropriate attributes for user 2', async function () { - const me = await server.users.getMyInfo({ token: user2Token }) - - expect(me.username).to.equal('user2') - expect(me.account.displayName).to.equal('my super user 2') - expect(me.videoQuota).to.equal(5 * 1024 * 1024) - expect(me.videoChannels[0].name).to.equal('user2_channel') - expect(me.videoChannels[0].displayName).to.equal('Main user2 channel') - expect(me.role.id).to.equal(UserRole.USER) - expect(me.email).to.equal('user2@example.com') - }) - - it('Should have created the appropriate attributes for user 3', async function () { - const me = await server.users.getMyInfo({ token: user3Token }) - - expect(me.username).to.equal('user3') - expect(me.account.displayName).to.equal('my super user 3') - expect(me.videoQuota).to.equal(5 * 1024 * 1024) - expect(me.videoChannels[0].name).to.equal('super_user3_channel') - expect(me.videoChannels[0].displayName).to.equal('my user 3 channel') - expect(me.role.id).to.equal(UserRole.USER) - expect(me.email).to.equal('user3@example.com') - }) - - it('Should list these accepted/rejected registration requests', async function () { - const { data } = await server.registrations.list({ sort: 'createdAt' }) - const { data: users } = await server.users.list() - - { - expect(data[0].id).to.equal(id4) - expect(data[0].state.id).to.equal(UserRegistrationState.REJECTED) - expect(data[0].state.label).to.equal('Rejected') - - expect(data[0].moderationResponse).to.equal('I do not want id 4 on this instance') - expect(data[0].user).to.be.null - - expect(users.find(u => u.username === 'user4')).to.not.exist - } - - { - expect(data[1].id).to.equal(id2) - expect(data[1].state.id).to.equal(UserRegistrationState.ACCEPTED) - expect(data[1].state.label).to.equal('Accepted') - - expect(data[1].moderationResponse).to.equal('Welcome id 2') - expect(data[1].user).to.exist - - const user2 = users.find(u => u.username === 'user2') - expect(data[1].user.id).to.equal(user2.id) - } - - { - expect(data[2].id).to.equal(id3) - expect(data[2].state.id).to.equal(UserRegistrationState.ACCEPTED) - expect(data[2].state.label).to.equal('Accepted') - - expect(data[2].moderationResponse).to.equal('Welcome id 3') - expect(data[2].user).to.exist - - const user3 = users.find(u => u.username === 'user3') - expect(data[2].user.id).to.equal(user3.id) - } - }) - - it('Shoulde delete a registration', async function () { - await server.registrations.delete({ id: id2 }) - await server.registrations.delete({ id: id3 }) - - const { total, data } = await server.registrations.list() - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(id4) - - const { data: users } = await server.users.list() - - for (const username of [ 'user2', 'user3' ]) { - expect(users.find(u => u.username === username)).to.exist - } - }) - - it('Should be able to prevent email delivery on accept/reject', async function () { - this.timeout(50000) - - let id1: number - let id2: number - - { - const { id } = await server.registrations.requestRegistration({ - username: 'user7', - email: 'user7@example.com', - registrationReason: 'tt' - }) - id1 = id - } - { - const { id } = await server.registrations.requestRegistration({ - username: 'user8', - email: 'user8@example.com', - registrationReason: 'tt' - }) - id2 = id - } - - await server.registrations.accept({ id: id1, moderationResponse: 'tt', preventEmailDelivery: true }) - await server.registrations.reject({ id: id2, moderationResponse: 'tt', preventEmailDelivery: true }) - - await waitJobs([ server ]) - - const filtered = emails.filter(e => { - const address = e['to'][0]['address'] - return address === 'user7@example.com' || address === 'user8@example.com' - }) - - expect(filtered).to.have.lengthOf(0) - }) - - it('Should request a registration without a channel, that will conflict with an already existing channel', async function () { - let id1: number - let id2: number - - { - const { id } = await server.registrations.requestRegistration({ - registrationReason: 'tt', - username: 'user5', - password: 'user5password', - channel: { - displayName: 'channel 6', - name: 'user6_channel' - } - }) - - id1 = id - } - - { - const { id } = await server.registrations.requestRegistration({ - registrationReason: 'tt', - username: 'user6', - password: 'user6password' - }) - - id2 = id - } - - await server.registrations.accept({ id: id1, moderationResponse: 'tt' }) - await server.registrations.accept({ id: id2, moderationResponse: 'tt' }) - - const user5Token = await server.login.getAccessToken('user5', 'user5password') - const user6Token = await server.login.getAccessToken('user6', 'user6password') - - const user5 = await server.users.getMyInfo({ token: user5Token }) - const user6 = await server.users.getMyInfo({ token: user6Token }) - - expect(user5.videoChannels[0].name).to.equal('user6_channel') - expect(user6.videoChannels[0].name).to.equal('user6_channel-1') - }) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/two-factor.ts b/server/tests/api/users/two-factor.ts deleted file mode 100644 index 0dcab9e17..000000000 --- a/server/tests/api/users/two-factor.ts +++ /dev/null @@ -1,200 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { expectStartWith } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands' - -async function login (options: { - server: PeerTubeServer - username: string - password: string - otpToken?: string - expectedStatus?: HttpStatusCode -}) { - const { server, username, password, otpToken, expectedStatus } = options - - const user = { username, password } - const { res, body: { access_token: token } } = await server.login.loginAndGetResponse({ user, otpToken, expectedStatus }) - - return { res, token } -} - -describe('Test users', function () { - let server: PeerTubeServer - let otpSecret: string - let requestToken: string - - const userUsername = 'user1' - let userId: number - let userPassword: string - let userToken: string - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - const res = await server.users.generate(userUsername) - userId = res.userId - userPassword = res.password - userToken = res.token - }) - - it('Should not add the header on login if two factor is not enabled', async function () { - const { res, token } = await login({ server, username: userUsername, password: userPassword }) - - expect(res.header['x-peertube-otp']).to.not.exist - - await server.users.getMyInfo({ token }) - }) - - it('Should request two factor and get the secret and uri', async function () { - const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword }) - - expect(otpRequest.requestToken).to.exist - - expect(otpRequest.secret).to.exist - expect(otpRequest.secret).to.have.lengthOf(32) - - expect(otpRequest.uri).to.exist - expectStartWith(otpRequest.uri, 'otpauth://') - expect(otpRequest.uri).to.include(otpRequest.secret) - - requestToken = otpRequest.requestToken - otpSecret = otpRequest.secret - }) - - it('Should not have two factor confirmed yet', async function () { - const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(twoFactorEnabled).to.be.false - }) - - it('Should confirm two factor', async function () { - await server.twoFactor.confirmRequest({ - userId, - token: userToken, - otpToken: TwoFactorCommand.buildOTP({ secret: otpSecret }).generate(), - requestToken - }) - }) - - it('Should not add the header on login if two factor is enabled and password is incorrect', async function () { - const { res, token } = await login({ server, username: userUsername, password: 'fake', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - expect(res.header['x-peertube-otp']).to.not.exist - expect(token).to.not.exist - }) - - it('Should add the header on login if two factor is enabled and password is correct', async function () { - const { res, token } = await login({ - server, - username: userUsername, - password: userPassword, - expectedStatus: HttpStatusCode.UNAUTHORIZED_401 - }) - - expect(res.header['x-peertube-otp']).to.exist - expect(token).to.not.exist - - await server.users.getMyInfo({ token }) - }) - - it('Should not login with correct password and incorrect otp secret', async function () { - const otp = TwoFactorCommand.buildOTP({ secret: 'a'.repeat(32) }) - - const { res, token } = await login({ - server, - username: userUsername, - password: userPassword, - otpToken: otp.generate(), - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - expect(res.header['x-peertube-otp']).to.not.exist - expect(token).to.not.exist - }) - - it('Should not login with correct password and incorrect otp code', async function () { - const { res, token } = await login({ - server, - username: userUsername, - password: userPassword, - otpToken: '123456', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - expect(res.header['x-peertube-otp']).to.not.exist - expect(token).to.not.exist - }) - - it('Should not login with incorrect password and correct otp code', async function () { - const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() - - const { res, token } = await login({ - server, - username: userUsername, - password: 'fake', - otpToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - expect(res.header['x-peertube-otp']).to.not.exist - expect(token).to.not.exist - }) - - it('Should correctly login with correct password and otp code', async function () { - const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() - - const { res, token } = await login({ server, username: userUsername, password: userPassword, otpToken }) - - expect(res.header['x-peertube-otp']).to.not.exist - expect(token).to.exist - - await server.users.getMyInfo({ token }) - }) - - it('Should have two factor enabled when getting my info', async function () { - const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(twoFactorEnabled).to.be.true - }) - - it('Should disable two factor and be able to login without otp token', async function () { - await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword }) - - const { res, token } = await login({ server, username: userUsername, password: userPassword }) - expect(res.header['x-peertube-otp']).to.not.exist - - await server.users.getMyInfo({ token }) - }) - - it('Should have two factor disabled when getting my info', async function () { - const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(twoFactorEnabled).to.be.false - }) - - it('Should enable two factor auth without password from an admin', async function () { - const { otpRequest } = await server.twoFactor.request({ userId }) - - await server.twoFactor.confirmRequest({ - userId, - otpToken: TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate(), - requestToken: otpRequest.requestToken - }) - - const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(twoFactorEnabled).to.be.true - }) - - it('Should disable two factor auth without password from an admin', async function () { - await server.twoFactor.disable({ userId }) - - const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) - expect(twoFactorEnabled).to.be.false - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts deleted file mode 100644 index ad2b82a4a..000000000 --- a/server/tests/api/users/user-subscriptions.ts +++ /dev/null @@ -1,614 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - SubscriptionsCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test users subscriptions', function () { - let servers: PeerTubeServer[] = [] - const users: { accessToken: string }[] = [] - let video3UUID: string - - let command: SubscriptionsCommand - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultChannelAvatar(servers) - await setDefaultAccountAvatar(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - for (const server of servers) { - const user = { username: 'user' + server.serverNumber, password: 'password' } - await server.users.create({ username: user.username, password: user.password }) - - const accessToken = await server.login.getAccessToken(user) - users.push({ accessToken }) - - const videoName1 = 'video 1-' + server.serverNumber - await server.videos.upload({ token: accessToken, attributes: { name: videoName1 } }) - - const videoName2 = 'video 2-' + server.serverNumber - await server.videos.upload({ token: accessToken, attributes: { name: videoName2 } }) - } - - await waitJobs(servers) - - command = servers[0].subscriptions - }) - - describe('Destinction between server videos and user videos', function () { - it('Should display videos of server 2 on server 1', async function () { - const { total } = await servers[0].videos.list() - - expect(total).to.equal(4) - }) - - it('User of server 1 should follow user of server 3 and root of server 1', async function () { - this.timeout(60000) - - await command.add({ token: users[0].accessToken, targetUri: 'user3_channel@' + servers[2].host }) - await command.add({ token: users[0].accessToken, targetUri: 'root_channel@' + servers[0].host }) - - await waitJobs(servers) - - const attributes = { name: 'video server 3 added after follow' } - const { uuid } = await servers[2].videos.upload({ token: users[2].accessToken, attributes }) - video3UUID = uuid - - await waitJobs(servers) - }) - - it('Should not display videos of server 3 on server 1', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(4) - - for (const video of data) { - expect(video.name).to.not.contain('1-3') - expect(video.name).to.not.contain('2-3') - expect(video.name).to.not.contain('video server 3 added after follow') - } - }) - }) - - describe('Subscription endpoints', function () { - - it('Should list subscriptions', async function () { - { - const body = await command.list() - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await command.list({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const subscriptions = body.data - expect(subscriptions).to.be.an('array') - expect(subscriptions).to.have.lengthOf(2) - - expect(subscriptions[0].name).to.equal('user3_channel') - expect(subscriptions[1].name).to.equal('root_channel') - } - }) - - it('Should get subscription', async function () { - { - const videoChannel = await command.get({ token: users[0].accessToken, uri: 'user3_channel@' + servers[2].host }) - - expect(videoChannel.name).to.equal('user3_channel') - expect(videoChannel.host).to.equal(servers[2].host) - expect(videoChannel.displayName).to.equal('Main user3 channel') - expect(videoChannel.followingCount).to.equal(0) - expect(videoChannel.followersCount).to.equal(1) - } - - { - const videoChannel = await command.get({ token: users[0].accessToken, uri: 'root_channel@' + servers[0].host }) - - expect(videoChannel.name).to.equal('root_channel') - expect(videoChannel.host).to.equal(servers[0].host) - expect(videoChannel.displayName).to.equal('Main root channel') - expect(videoChannel.followingCount).to.equal(0) - expect(videoChannel.followersCount).to.equal(1) - } - }) - - it('Should return the existing subscriptions', async function () { - const uris = [ - 'user3_channel@' + servers[2].host, - 'root2_channel@' + servers[0].host, - 'root_channel@' + servers[0].host, - 'user3_channel@' + servers[0].host - ] - - const body = await command.exist({ token: users[0].accessToken, uris }) - - expect(body['user3_channel@' + servers[2].host]).to.be.true - expect(body['root2_channel@' + servers[0].host]).to.be.false - expect(body['root_channel@' + servers[0].host]).to.be.true - expect(body['user3_channel@' + servers[0].host]).to.be.false - }) - - it('Should search among subscriptions', async function () { - { - const body = await command.list({ token: users[0].accessToken, sort: '-createdAt', search: 'user3_channel' }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - } - - { - const body = await command.list({ token: users[0].accessToken, sort: '-createdAt', search: 'toto' }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - }) - - describe('Subscription videos', function () { - - it('Should list subscription videos', async function () { - { - const body = await servers[0].videos.listMySubscriptionVideos() - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(3) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(3) - - expect(videos[0].name).to.equal('video 1-3') - expect(videos[1].name).to.equal('video 2-3') - expect(videos[2].name).to.equal('video server 3 added after follow') - } - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, count: 1, start: 1 }) - expect(body.total).to.equal(3) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(1) - - expect(videos[0].name).to.equal('video 2-3') - } - }) - - it('Should upload a video by root on server 1 and see it in the subscription videos', async function () { - this.timeout(60000) - - const videoName = 'video server 1 added after follow' - await servers[0].videos.upload({ attributes: { name: videoName } }) - - await waitJobs(servers) - - { - const body = await servers[0].videos.listMySubscriptionVideos() - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(4) - - expect(videos[0].name).to.equal('video 1-3') - expect(videos[1].name).to.equal('video 2-3') - expect(videos[2].name).to.equal('video server 3 added after follow') - expect(videos[3].name).to.equal('video server 1 added after follow') - } - - { - const { data, total } = await servers[0].videos.list() - expect(total).to.equal(5) - - for (const video of data) { - expect(video.name).to.not.contain('1-3') - expect(video.name).to.not.contain('2-3') - expect(video.name).to.not.contain('video server 3 added after follow') - } - } - }) - - it('Should have server 1 following server 3 and display server 3 videos', async function () { - this.timeout(60000) - - await servers[0].follows.follow({ hosts: [ servers[2].url ] }) - - await waitJobs(servers) - - const { data, total } = await servers[0].videos.list() - expect(total).to.equal(8) - - const names = [ '1-3', '2-3', 'video server 3 added after follow' ] - for (const name of names) { - const video = data.find(v => v.name.includes(name)) - expect(video).to.not.be.undefined - } - }) - - it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () { - this.timeout(60000) - - await servers[0].follows.unfollow({ target: servers[2] }) - - await waitJobs(servers) - - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(5) - - for (const video of data) { - expect(video.name).to.not.contain('1-3') - expect(video.name).to.not.contain('2-3') - expect(video.name).to.not.contain('video server 3 added after follow') - } - }) - - it('Should still list subscription videos', async function () { - { - const body = await servers[0].videos.listMySubscriptionVideos() - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - } - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(4) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(4) - - expect(videos[0].name).to.equal('video 1-3') - expect(videos[1].name).to.equal('video 2-3') - expect(videos[2].name).to.equal('video server 3 added after follow') - expect(videos[3].name).to.equal('video server 1 added after follow') - } - }) - }) - - describe('Existing subscription video update', function () { - - it('Should update a video of server 3 and see the updated video on server 1', async function () { - this.timeout(30000) - - await servers[2].videos.update({ id: video3UUID, attributes: { name: 'video server 3 added after follow updated' } }) - - await waitJobs(servers) - - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.data[2].name).to.equal('video server 3 added after follow updated') - }) - }) - - describe('Subscription removal', function () { - - it('Should remove user of server 3 subscription', async function () { - this.timeout(30000) - - await command.remove({ token: users[0].accessToken, uri: 'user3_channel@' + servers[2].host }) - - await waitJobs(servers) - }) - - it('Should not display its videos anymore', async function () { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(1) - - expect(videos[0].name).to.equal('video server 1 added after follow') - }) - - it('Should remove the root subscription and not display the videos anymore', async function () { - this.timeout(30000) - - await command.remove({ token: users[0].accessToken, uri: 'root_channel@' + servers[0].host }) - - await waitJobs(servers) - - { - const body = await command.list({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(0) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(0) - } - }) - - it('Should correctly display public videos on server 1', async function () { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(5) - - for (const video of data) { - expect(video.name).to.not.contain('1-3') - expect(video.name).to.not.contain('2-3') - expect(video.name).to.not.contain('video server 3 added after follow updated') - } - }) - }) - - describe('Re-follow', function () { - - it('Should follow user of server 3 again', async function () { - this.timeout(60000) - - await command.add({ token: users[0].accessToken, targetUri: 'user3_channel@' + servers[2].host }) - - await waitJobs(servers) - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken, sort: 'createdAt' }) - expect(body.total).to.equal(3) - - const videos = body.data - expect(videos).to.be.an('array') - expect(videos).to.have.lengthOf(3) - - expect(videos[0].name).to.equal('video 1-3') - expect(videos[1].name).to.equal('video 2-3') - expect(videos[2].name).to.equal('video server 3 added after follow updated') - } - - { - const { total, data } = await servers[0].videos.list() - expect(total).to.equal(5) - - for (const video of data) { - expect(video.name).to.not.contain('1-3') - expect(video.name).to.not.contain('2-3') - expect(video.name).to.not.contain('video server 3 added after follow updated') - } - } - }) - - it('Should follow user channels of server 3 by root of server 3', async function () { - this.timeout(60000) - - await servers[2].channels.create({ token: users[2].accessToken, attributes: { name: 'user3_channel2' } }) - - await servers[2].subscriptions.add({ token: servers[2].accessToken, targetUri: 'user3_channel@' + servers[2].host }) - await servers[2].subscriptions.add({ token: servers[2].accessToken, targetUri: 'user3_channel2@' + servers[2].host }) - - await waitJobs(servers) - }) - }) - - describe('Followers listing', function () { - - it('Should list user 3 followers', async function () { - { - const { total, data } = await servers[2].accounts.listFollowers({ - token: users[2].accessToken, - accountName: 'user3', - start: 0, - count: 5, - sort: 'createdAt' - }) - - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[0].host) - expect(data[0].follower.name).to.equal('user1') - - expect(data[1].following.host).to.equal(servers[2].host) - expect(data[1].following.name).to.equal('user3_channel') - expect(data[1].follower.host).to.equal(servers[2].host) - expect(data[1].follower.name).to.equal('root') - - expect(data[2].following.host).to.equal(servers[2].host) - expect(data[2].following.name).to.equal('user3_channel2') - expect(data[2].follower.host).to.equal(servers[2].host) - expect(data[2].follower.name).to.equal('root') - } - - { - const { total, data } = await servers[2].accounts.listFollowers({ - token: users[2].accessToken, - accountName: 'user3', - start: 0, - count: 1, - sort: '-createdAt' - }) - - expect(total).to.equal(3) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel2') - expect(data[0].follower.host).to.equal(servers[2].host) - expect(data[0].follower.name).to.equal('root') - } - - { - const { total, data } = await servers[2].accounts.listFollowers({ - token: users[2].accessToken, - accountName: 'user3', - start: 1, - count: 1, - sort: '-createdAt' - }) - - expect(total).to.equal(3) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[2].host) - expect(data[0].follower.name).to.equal('root') - } - - { - const { total, data } = await servers[2].accounts.listFollowers({ - token: users[2].accessToken, - accountName: 'user3', - search: 'user1', - sort: '-createdAt' - }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[0].host) - expect(data[0].follower.name).to.equal('user1') - } - }) - - it('Should list user3_channel followers', async function () { - { - const { total, data } = await servers[2].channels.listFollowers({ - token: users[2].accessToken, - channelName: 'user3_channel', - start: 0, - count: 5, - sort: 'createdAt' - }) - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[0].host) - expect(data[0].follower.name).to.equal('user1') - - expect(data[1].following.host).to.equal(servers[2].host) - expect(data[1].following.name).to.equal('user3_channel') - expect(data[1].follower.host).to.equal(servers[2].host) - expect(data[1].follower.name).to.equal('root') - } - - { - const { total, data } = await servers[2].channels.listFollowers({ - token: users[2].accessToken, - channelName: 'user3_channel', - start: 0, - count: 1, - sort: '-createdAt' - }) - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[2].host) - expect(data[0].follower.name).to.equal('root') - } - - { - const { total, data } = await servers[2].channels.listFollowers({ - token: users[2].accessToken, - channelName: 'user3_channel', - start: 1, - count: 1, - sort: '-createdAt' - }) - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[0].host) - expect(data[0].follower.name).to.equal('user1') - } - - { - const { total, data } = await servers[2].channels.listFollowers({ - token: users[2].accessToken, - channelName: 'user3_channel', - search: 'user1', - sort: '-createdAt' - }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - expect(data[0].following.host).to.equal(servers[2].host) - expect(data[0].following.name).to.equal('user3_channel') - expect(data[0].follower.host).to.equal(servers[0].host) - expect(data[0].follower.name).to.equal('user1') - } - }) - }) - - describe('Subscription videos privacy', function () { - - it('Should update video as internal and not see from remote server', async function () { - this.timeout(30000) - - await servers[2].videos.update({ id: video3UUID, attributes: { name: 'internal', privacy: VideoPrivacy.INTERNAL } }) - await waitJobs(servers) - - { - const { data } = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken }) - expect(data.find(v => v.name === 'internal')).to.not.exist - } - }) - - it('Should see internal from local user', async function () { - const { data } = await servers[2].videos.listMySubscriptionVideos({ token: servers[2].accessToken }) - expect(data.find(v => v.name === 'internal')).to.exist - }) - - it('Should update video as private and not see from anyone server', async function () { - this.timeout(30000) - - await servers[2].videos.update({ id: video3UUID, attributes: { name: 'private', privacy: VideoPrivacy.PRIVATE } }) - await waitJobs(servers) - - { - const { data } = await servers[0].videos.listMySubscriptionVideos({ token: users[0].accessToken }) - expect(data.find(v => v.name === 'private')).to.not.exist - } - - { - const { data } = await servers[2].videos.listMySubscriptionVideos({ token: servers[2].accessToken }) - expect(data.find(v => v.name === 'private')).to.not.exist - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/users/user-videos.ts b/server/tests/api/users/user-videos.ts deleted file mode 100644 index 77226e48e..000000000 --- a/server/tests/api/users/user-videos.ts +++ /dev/null @@ -1,219 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test user videos', function () { - let server: PeerTubeServer - let videoId: number - let videoId2: number - let token: string - let anotherUserToken: string - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultChannelAvatar([ server ]) - await setDefaultAccountAvatar([ server ]) - - await server.videos.quickUpload({ name: 'root video' }) - await server.videos.quickUpload({ name: 'root video 2' }) - - token = await server.users.generateUserAndToken('user') - anotherUserToken = await server.users.generateUserAndToken('user2') - }) - - describe('List my videos', function () { - - it('Should list my videos', async function () { - const { data, total } = await server.videos.listMyVideos() - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - }) - }) - - describe('Upload', function () { - - it('Should upload the video with the correct token', async function () { - await server.videos.upload({ token }) - const { data } = await server.videos.list() - const video = data[0] - - expect(video.account.name).to.equal('user') - videoId = video.id - }) - - it('Should upload the video again with the correct token', async function () { - const { id } = await server.videos.upload({ token }) - videoId2 = id - }) - }) - - describe('Ratings', function () { - - it('Should retrieve a video rating', async function () { - await server.videos.rate({ id: videoId, token, rating: 'like' }) - const rating = await server.users.getMyRating({ token, videoId }) - - expect(rating.videoId).to.equal(videoId) - expect(rating.rating).to.equal('like') - }) - - it('Should retrieve ratings list', async function () { - await server.videos.rate({ id: videoId, token, rating: 'like' }) - - const body = await server.accounts.listRatings({ accountName: 'user', token }) - - expect(body.total).to.equal(1) - expect(body.data[0].video.id).to.equal(videoId) - expect(body.data[0].rating).to.equal('like') - }) - - it('Should retrieve ratings list by rating type', async function () { - { - const body = await server.accounts.listRatings({ accountName: 'user', token, rating: 'like' }) - expect(body.data.length).to.equal(1) - } - - { - const body = await server.accounts.listRatings({ accountName: 'user', token, rating: 'dislike' }) - expect(body.data.length).to.equal(0) - } - }) - }) - - describe('Remove video', function () { - - it('Should not be able to remove the video with an incorrect token', async function () { - await server.videos.remove({ token: 'bad_token', id: videoId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not be able to remove the video with the token of another account', async function () { - await server.videos.remove({ token: anotherUserToken, id: videoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should be able to remove the video with the correct token', async function () { - await server.videos.remove({ token, id: videoId }) - await server.videos.remove({ token, id: videoId2 }) - }) - }) - - describe('My videos & quotas', function () { - - it('Should be able to upload a video with a user', async function () { - this.timeout(30000) - - const attributes = { - name: 'super user video', - fixture: 'video_short.webm' - } - await server.videos.upload({ token, attributes }) - - await server.channels.create({ token, attributes: { name: 'other_channel' } }) - }) - - it('Should have video quota updated', async function () { - const quota = await server.users.getMyQuotaUsed({ token }) - expect(quota.videoQuotaUsed).to.equal(218910) - expect(quota.videoQuotaUsedDaily).to.equal(218910) - - const { data } = await server.users.list() - const tmpUser = data.find(u => u.username === 'user') - expect(tmpUser.videoQuotaUsed).to.equal(218910) - expect(tmpUser.videoQuotaUsedDaily).to.equal(218910) - }) - - it('Should be able to list my videos', async function () { - const { total, data } = await server.videos.listMyVideos({ token }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const video = data[0] - expect(video.name).to.equal('super user video') - expect(video.thumbnailPath).to.not.be.null - expect(video.previewPath).to.not.be.null - }) - - it('Should be able to filter by channel in my videos', async function () { - const myInfo = await server.users.getMyInfo({ token }) - const mainChannel = myInfo.videoChannels.find(c => c.name !== 'other_channel') - const otherChannel = myInfo.videoChannels.find(c => c.name === 'other_channel') - - { - const { total, data } = await server.videos.listMyVideos({ token, channelId: mainChannel.id }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - const video = data[0] - expect(video.name).to.equal('super user video') - expect(video.thumbnailPath).to.not.be.null - expect(video.previewPath).to.not.be.null - } - - { - const { total, data } = await server.videos.listMyVideos({ token, channelId: otherChannel.id }) - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - }) - - it('Should be able to search in my videos', async function () { - { - const { total, data } = await server.videos.listMyVideos({ token, sort: '-createdAt', search: 'user video' }) - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - } - - { - const { total, data } = await server.videos.listMyVideos({ token, sort: '-createdAt', search: 'toto' }) - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - }) - - it('Should disable web videos, enable HLS, and update my quota', async function () { - this.timeout(160000) - - { - const config = await server.config.getCustomConfig() - config.transcoding.webVideos.enabled = false - config.transcoding.hls.enabled = true - config.transcoding.enabled = true - await server.config.updateCustomSubConfig({ newConfig: config }) - } - - { - const attributes = { - name: 'super user video 2', - fixture: 'video_short.webm' - } - await server.videos.upload({ token, attributes }) - - await waitJobs([ server ]) - } - - { - const data = await server.users.getMyQuotaUsed({ token }) - expect(data.videoQuotaUsed).to.be.greaterThan(220000) - expect(data.videoQuotaUsedDaily).to.be.greaterThan(220000) - } - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/users-email-verification.ts b/server/tests/api/users/users-email-verification.ts deleted file mode 100644 index 909226311..000000000 --- a/server/tests/api/users/users-email-verification.ts +++ /dev/null @@ -1,165 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockSmtpServer } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - ConfigCommand, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test users email verification', function () { - let server: PeerTubeServer - let userId: number - let userAccessToken: string - let verificationString: string - let expectedEmailsLength = 0 - const user1 = { - username: 'user_1', - password: 'super password' - } - const user2 = { - username: 'user_2', - password: 'super password' - } - const emails: object[] = [] - - before(async function () { - this.timeout(30000) - - const port = await MockSmtpServer.Instance.collectEmails(emails) - server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(port)) - - await setAccessTokensToServers([ server ]) - }) - - it('Should register user and send verification email if verification required', async function () { - this.timeout(30000) - - await server.config.updateExistingSubConfig({ - newConfig: { - signup: { - enabled: true, - requiresApproval: false, - requiresEmailVerification: true, - limit: 10 - } - } - }) - - await server.registrations.register(user1) - - await waitJobs(server) - expectedEmailsLength++ - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const email = emails[expectedEmailsLength - 1] - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString = verificationStringMatches[1] - expect(verificationString).to.have.length.above(2) - - const userIdMatches = /userId=([0-9]+)/.exec(email['text']) - expect(userIdMatches).not.to.be.null - - userId = parseInt(userIdMatches[1], 10) - - const body = await server.users.get({ userId }) - expect(body.emailVerified).to.be.false - }) - - it('Should not allow login for user with unverified email', async function () { - const { detail } = await server.login.login({ user: user1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - expect(detail).to.contain('User email is not verified.') - }) - - it('Should verify the user via email and allow login', async function () { - await server.users.verifyEmail({ userId, verificationString }) - - const body = await server.login.login({ user: user1 }) - userAccessToken = body.access_token - - const user = await server.users.get({ userId }) - expect(user.emailVerified).to.be.true - }) - - it('Should be able to change the user email', async function () { - let updateVerificationString: string - - { - await server.users.updateMe({ - token: userAccessToken, - email: 'updated@example.com', - currentPassword: user1.password - }) - - await waitJobs(server) - expectedEmailsLength++ - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const email = emails[expectedEmailsLength - 1] - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - updateVerificationString = verificationStringMatches[1] - } - - { - const me = await server.users.getMyInfo({ token: userAccessToken }) - expect(me.email).to.equal('user_1@example.com') - expect(me.pendingEmail).to.equal('updated@example.com') - } - - { - await server.users.verifyEmail({ userId, verificationString: updateVerificationString, isPendingEmail: true }) - - const me = await server.users.getMyInfo({ token: userAccessToken }) - expect(me.email).to.equal('updated@example.com') - expect(me.pendingEmail).to.be.null - } - }) - - it('Should register user not requiring email verification if setting not enabled', async function () { - this.timeout(5000) - await server.config.updateExistingSubConfig({ - newConfig: { - signup: { - requiresEmailVerification: false - } - } - }) - - await server.registrations.register(user2) - - await waitJobs(server) - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const accessToken = await server.login.getAccessToken(user2) - - const user = await server.users.getMyInfo({ token: accessToken }) - expect(user.emailVerified).to.be.null - }) - - it('Should allow login for user with unverified email when setting later enabled', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - signup: { - requiresEmailVerification: true - } - } - }) - - await server.login.getAccessToken(user2) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts deleted file mode 100644 index 3823b74ef..000000000 --- a/server/tests/api/users/users-multiple-servers.ts +++ /dev/null @@ -1,216 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - checkActorFilesWereRemoved, - checkTmpIsEmpty, - checkVideoFilesWereRemoved, - saveVideoInServers, - testImage -} from '@server/tests/shared' -import { MyUser } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test users with multiple servers', function () { - let servers: PeerTubeServer[] = [] - - let user: MyUser - let userId: number - - let videoUUID: string - let userAccessToken: string - let userAvatarFilenames: string[] - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultChannelAvatar(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - // Server 1 and server 3 follow each other - await doubleFollow(servers[0], servers[2]) - // Server 2 and server 3 follow each other - await doubleFollow(servers[1], servers[2]) - - // The root user of server 1 is propagated to servers 2 and 3 - await servers[0].videos.upload() - - { - const username = 'user1' - const created = await servers[0].users.create({ username }) - userId = created.id - userAccessToken = await servers[0].login.getAccessToken(username) - } - - { - const { uuid } = await servers[0].videos.upload({ token: userAccessToken }) - videoUUID = uuid - - await waitJobs(servers) - - await saveVideoInServers(servers, videoUUID) - } - }) - - it('Should be able to update my display name', async function () { - await servers[0].users.updateMe({ displayName: 'my super display name' }) - - user = await servers[0].users.getMyInfo() - expect(user.account.displayName).to.equal('my super display name') - - await waitJobs(servers) - }) - - it('Should be able to update my description', async function () { - this.timeout(10_000) - - await servers[0].users.updateMe({ description: 'my super description updated' }) - - user = await servers[0].users.getMyInfo() - expect(user.account.displayName).to.equal('my super display name') - expect(user.account.description).to.equal('my super description updated') - - await waitJobs(servers) - }) - - it('Should be able to update my avatar', async function () { - this.timeout(10_000) - - const fixture = 'avatar2.png' - - await servers[0].users.updateMyAvatar({ fixture }) - - user = await servers[0].users.getMyInfo() - userAvatarFilenames = user.account.avatars.map(({ path }) => path) - - for (const avatar of user.account.avatars) { - await testImage(servers[0].url, `avatar2-resized-${avatar.width}x${avatar.width}`, avatar.path, '.png') - } - - await waitJobs(servers) - }) - - it('Should have updated my profile on other servers too', async function () { - let createdAt: string | Date - - for (const server of servers) { - const body = await server.accounts.list({ sort: '-createdAt' }) - - const resList = body.data.find(a => a.name === 'root' && a.host === servers[0].host) - expect(resList).not.to.be.undefined - - const account = await server.accounts.get({ accountName: resList.name + '@' + resList.host }) - - if (!createdAt) createdAt = account.createdAt - - expect(account.name).to.equal('root') - expect(account.host).to.equal(servers[0].host) - expect(account.displayName).to.equal('my super display name') - expect(account.description).to.equal('my super description updated') - expect(createdAt).to.equal(account.createdAt) - - if (server.serverNumber === 1) { - expect(account.userId).to.be.a('number') - } else { - expect(account.userId).to.be.undefined - } - - for (const avatar of account.avatars) { - await testImage(server.url, `avatar2-resized-${avatar.width}x${avatar.width}`, avatar.path, '.png') - } - } - }) - - it('Should list account videos', async function () { - for (const server of servers) { - const { total, data } = await server.videos.listByAccount({ handle: 'user1@' + servers[0].host }) - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - expect(data[0].uuid).to.equal(videoUUID) - } - }) - - it('Should search through account videos', async function () { - const created = await servers[0].videos.upload({ token: userAccessToken, attributes: { name: 'Kami no chikara' } }) - - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.listByAccount({ handle: 'user1@' + servers[0].host, search: 'Kami' }) - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - expect(data[0].uuid).to.equal(created.uuid) - } - }) - - it('Should remove the user', async function () { - this.timeout(10_000) - - for (const server of servers) { - const body = await server.accounts.list({ sort: '-createdAt' }) - - const accountDeleted = body.data.find(a => a.name === 'user1' && a.host === servers[0].host) - expect(accountDeleted).not.to.be.undefined - - const { data } = await server.channels.list() - const videoChannelDeleted = data.find(a => a.displayName === 'Main user1 channel' && a.host === servers[0].host) - expect(videoChannelDeleted).not.to.be.undefined - } - - await servers[0].users.remove({ userId }) - - await waitJobs(servers) - - for (const server of servers) { - const body = await server.accounts.list({ sort: '-createdAt' }) - - const accountDeleted = body.data.find(a => a.name === 'user1' && a.host === servers[0].host) - expect(accountDeleted).to.be.undefined - - const { data } = await server.channels.list() - const videoChannelDeleted = data.find(a => a.name === 'Main user1 channel' && a.host === servers[0].host) - expect(videoChannelDeleted).to.be.undefined - } - }) - - it('Should not have actor files', async () => { - for (const server of servers) { - for (const userAvatarFilename of userAvatarFilenames) { - await checkActorFilesWereRemoved(userAvatarFilename, server) - } - } - }) - - it('Should not have video files', async () => { - for (const server of servers) { - await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails }) - } - }) - - it('Should have an empty tmp directory', async function () { - for (const server of servers) { - await checkTmpIsEmpty(server) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts deleted file mode 100644 index 67ade1d0d..000000000 --- a/server/tests/api/users/users.ts +++ /dev/null @@ -1,529 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { testImageSize } from '@server/tests/shared' -import { AbuseState, HttpStatusCode, UserAdminFlag, UserRole, VideoPlaylistType } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test users', function () { - let server: PeerTubeServer - let token: string - let userToken: string - let videoId: number - let userId: number - const user = { - username: 'user_1', - password: 'super password' - } - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { - rates_limit: { - login: { - max: 30 - } - } - }) - - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ npmName: 'peertube-theme-background-red' }) - }) - - describe('Creating a user', function () { - - it('Should be able to create a new user', async function () { - await server.users.create({ ...user, videoQuota: 2 * 1024 * 1024, adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST }) - }) - - it('Should be able to login with this user', async function () { - userToken = await server.login.getAccessToken(user) - }) - - it('Should be able to get user information', async function () { - const userMe = await server.users.getMyInfo({ token: userToken }) - - const userGet = await server.users.get({ userId: userMe.id, withStats: true }) - - for (const user of [ userMe, userGet ]) { - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('user_1@example.com') - expect(user.nsfwPolicy).to.equal('display') - expect(user.videoQuota).to.equal(2 * 1024 * 1024) - expect(user.role.label).to.equal('User') - expect(user.id).to.be.a('number') - expect(user.account.displayName).to.equal('user_1') - expect(user.account.description).to.be.null - } - - expect(userMe.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST) - expect(userGet.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST) - - expect(userMe.specialPlaylists).to.have.lengthOf(1) - expect(userMe.specialPlaylists[0].type).to.equal(VideoPlaylistType.WATCH_LATER) - - // Check stats are included with withStats - expect(userGet.videosCount).to.be.a('number') - expect(userGet.videosCount).to.equal(0) - expect(userGet.videoCommentsCount).to.be.a('number') - expect(userGet.videoCommentsCount).to.equal(0) - expect(userGet.abusesCount).to.be.a('number') - expect(userGet.abusesCount).to.equal(0) - expect(userGet.abusesAcceptedCount).to.be.a('number') - expect(userGet.abusesAcceptedCount).to.equal(0) - }) - }) - - describe('Users listing', function () { - - it('Should list all the users', async function () { - const { data, total } = await server.users.list() - - expect(total).to.equal(2) - expect(data).to.be.an('array') - expect(data.length).to.equal(2) - - const user = data[0] - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('user_1@example.com') - expect(user.nsfwPolicy).to.equal('display') - - const rootUser = data[1] - expect(rootUser.username).to.equal('root') - expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') - expect(user.nsfwPolicy).to.equal('display') - - expect(rootUser.lastLoginDate).to.exist - expect(user.lastLoginDate).to.exist - - userId = user.id - }) - - it('Should list only the first user by username asc', async function () { - const { total, data } = await server.users.list({ start: 0, count: 1, sort: 'username' }) - - expect(total).to.equal(2) - expect(data.length).to.equal(1) - - const user = data[0] - expect(user.username).to.equal('root') - expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') - expect(user.role.label).to.equal('Administrator') - expect(user.nsfwPolicy).to.equal('display') - }) - - it('Should list only the first user by username desc', async function () { - const { total, data } = await server.users.list({ start: 0, count: 1, sort: '-username' }) - - expect(total).to.equal(2) - expect(data.length).to.equal(1) - - const user = data[0] - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('user_1@example.com') - expect(user.nsfwPolicy).to.equal('display') - }) - - it('Should list only the second user by createdAt desc', async function () { - const { data, total } = await server.users.list({ start: 0, count: 1, sort: '-createdAt' }) - expect(total).to.equal(2) - - expect(data.length).to.equal(1) - - const user = data[0] - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('user_1@example.com') - expect(user.nsfwPolicy).to.equal('display') - }) - - it('Should list all the users by createdAt asc', async function () { - const { data, total } = await server.users.list({ start: 0, count: 2, sort: 'createdAt' }) - - expect(total).to.equal(2) - expect(data.length).to.equal(2) - - expect(data[0].username).to.equal('root') - expect(data[0].email).to.equal('admin' + server.internalServerNumber + '@example.com') - expect(data[0].nsfwPolicy).to.equal('display') - - expect(data[1].username).to.equal('user_1') - expect(data[1].email).to.equal('user_1@example.com') - expect(data[1].nsfwPolicy).to.equal('display') - }) - - it('Should search user by username', async function () { - const { data, total } = await server.users.list({ start: 0, count: 2, sort: 'createdAt', search: 'oot' }) - expect(total).to.equal(1) - expect(data.length).to.equal(1) - expect(data[0].username).to.equal('root') - }) - - it('Should search user by email', async function () { - { - const { total, data } = await server.users.list({ start: 0, count: 2, sort: 'createdAt', search: 'r_1@exam' }) - expect(total).to.equal(1) - expect(data.length).to.equal(1) - expect(data[0].username).to.equal('user_1') - expect(data[0].email).to.equal('user_1@example.com') - } - - { - const { total, data } = await server.users.list({ start: 0, count: 2, sort: 'createdAt', search: 'example' }) - expect(total).to.equal(2) - expect(data.length).to.equal(2) - expect(data[0].username).to.equal('root') - expect(data[1].username).to.equal('user_1') - } - }) - }) - - describe('Update my account', function () { - - it('Should update my password', async function () { - await server.users.updateMe({ - token: userToken, - currentPassword: 'super password', - password: 'new password' - }) - user.password = 'new password' - - await server.login.login({ user }) - }) - - it('Should be able to change the NSFW display attribute', async function () { - await server.users.updateMe({ - token: userToken, - nsfwPolicy: 'do_not_list' - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('user_1@example.com') - expect(user.nsfwPolicy).to.equal('do_not_list') - expect(user.videoQuota).to.equal(2 * 1024 * 1024) - expect(user.id).to.be.a('number') - expect(user.account.displayName).to.equal('user_1') - expect(user.account.description).to.be.null - }) - - it('Should be able to change the autoPlayVideo attribute', async function () { - await server.users.updateMe({ - token: userToken, - autoPlayVideo: false - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.autoPlayVideo).to.be.false - }) - - it('Should be able to change the autoPlayNextVideo attribute', async function () { - await server.users.updateMe({ - token: userToken, - autoPlayNextVideo: true - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.autoPlayNextVideo).to.be.true - }) - - it('Should be able to change the p2p attribute', async function () { - await server.users.updateMe({ - token: userToken, - p2pEnabled: true - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.p2pEnabled).to.be.true - }) - - it('Should be able to change the email attribute', async function () { - await server.users.updateMe({ - token: userToken, - currentPassword: 'new password', - email: 'updated@example.com' - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('updated@example.com') - expect(user.nsfwPolicy).to.equal('do_not_list') - expect(user.videoQuota).to.equal(2 * 1024 * 1024) - expect(user.id).to.be.a('number') - expect(user.account.displayName).to.equal('user_1') - expect(user.account.description).to.be.null - }) - - it('Should be able to update my avatar with a gif', async function () { - const fixture = 'avatar.gif' - - await server.users.updateMyAvatar({ token: userToken, fixture }) - - const user = await server.users.getMyInfo({ token: userToken }) - for (const avatar of user.account.avatars) { - await testImageSize(server.url, `avatar-resized-${avatar.width}x${avatar.width}`, avatar.path, '.gif') - } - }) - - it('Should be able to update my avatar with a gif, and then a png', async function () { - for (const extension of [ '.png', '.gif' ]) { - const fixture = 'avatar' + extension - - await server.users.updateMyAvatar({ token: userToken, fixture }) - - const user = await server.users.getMyInfo({ token: userToken }) - for (const avatar of user.account.avatars) { - await testImageSize(server.url, `avatar-resized-${avatar.width}x${avatar.width}`, avatar.path, extension) - } - } - }) - - it('Should be able to update my display name', async function () { - await server.users.updateMe({ token: userToken, displayName: 'new display name' }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('updated@example.com') - expect(user.nsfwPolicy).to.equal('do_not_list') - expect(user.videoQuota).to.equal(2 * 1024 * 1024) - expect(user.id).to.be.a('number') - expect(user.account.displayName).to.equal('new display name') - expect(user.account.description).to.be.null - }) - - it('Should be able to update my description', async function () { - await server.users.updateMe({ token: userToken, description: 'my super description updated' }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('updated@example.com') - expect(user.nsfwPolicy).to.equal('do_not_list') - expect(user.videoQuota).to.equal(2 * 1024 * 1024) - expect(user.id).to.be.a('number') - expect(user.account.displayName).to.equal('new display name') - expect(user.account.description).to.equal('my super description updated') - expect(user.noWelcomeModal).to.be.false - expect(user.noInstanceConfigWarningModal).to.be.false - expect(user.noAccountSetupWarningModal).to.be.false - }) - - it('Should be able to update my theme', async function () { - for (const theme of [ 'background-red', 'default', 'instance-default' ]) { - await server.users.updateMe({ token: userToken, theme }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.theme).to.equal(theme) - } - }) - - it('Should be able to update my modal preferences', async function () { - await server.users.updateMe({ - token: userToken, - noInstanceConfigWarningModal: true, - noWelcomeModal: true, - noAccountSetupWarningModal: true - }) - - const user = await server.users.getMyInfo({ token: userToken }) - expect(user.noWelcomeModal).to.be.true - expect(user.noInstanceConfigWarningModal).to.be.true - expect(user.noAccountSetupWarningModal).to.be.true - }) - }) - - describe('Updating another user', function () { - - it('Should be able to update another user', async function () { - await server.users.update({ - userId, - token, - email: 'updated2@example.com', - emailVerified: true, - videoQuota: 42, - role: UserRole.MODERATOR, - adminFlags: UserAdminFlag.NONE, - pluginAuth: 'toto' - }) - - const user = await server.users.get({ token, userId }) - - expect(user.username).to.equal('user_1') - expect(user.email).to.equal('updated2@example.com') - expect(user.emailVerified).to.be.true - expect(user.nsfwPolicy).to.equal('do_not_list') - expect(user.videoQuota).to.equal(42) - expect(user.role.label).to.equal('Moderator') - expect(user.id).to.be.a('number') - expect(user.adminFlags).to.equal(UserAdminFlag.NONE) - expect(user.pluginAuth).to.equal('toto') - }) - - it('Should reset the auth plugin', async function () { - await server.users.update({ userId, token, pluginAuth: null }) - - const user = await server.users.get({ token, userId }) - expect(user.pluginAuth).to.be.null - }) - - it('Should have removed the user token', async function () { - await server.users.getMyQuotaUsed({ token: userToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - - userToken = await server.login.getAccessToken(user) - }) - - it('Should be able to update another user password', async function () { - await server.users.update({ userId, token, password: 'password updated' }) - - await server.users.getMyQuotaUsed({ token: userToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - - await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - user.password = 'password updated' - userToken = await server.login.getAccessToken(user) - }) - }) - - describe('Remove a user', function () { - - before(async function () { - await server.users.update({ - userId, - token, - videoQuota: 2 * 1024 * 1024 - }) - - await server.videos.quickUpload({ name: 'user video', token: userToken, fixture: 'video_short.webm' }) - await server.videos.quickUpload({ name: 'root video' }) - - const { total } = await server.videos.list() - expect(total).to.equal(2) - }) - - it('Should be able to remove this user', async function () { - await server.users.remove({ userId, token }) - }) - - it('Should not be able to login with this user', async function () { - await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not have videos of this user', async function () { - const { data, total } = await server.videos.list() - expect(total).to.equal(1) - - const video = data[0] - expect(video.account.name).to.equal('root') - }) - }) - - describe('User blocking', function () { - let user16Id: number - let user16AccessToken: string - - const user16 = { - username: 'user_16', - password: 'my super password' - } - - it('Should block a user', async function () { - const user = await server.users.create({ ...user16 }) - user16Id = user.id - - user16AccessToken = await server.login.getAccessToken(user16) - - await server.users.getMyInfo({ token: user16AccessToken, expectedStatus: HttpStatusCode.OK_200 }) - await server.users.banUser({ userId: user16Id }) - - await server.users.getMyInfo({ token: user16AccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await server.login.login({ user: user16, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should search user by banned status', async function () { - { - const { data, total } = await server.users.list({ start: 0, count: 2, sort: 'createdAt', blocked: true }) - expect(total).to.equal(1) - expect(data.length).to.equal(1) - - expect(data[0].username).to.equal(user16.username) - } - - { - const { data, total } = await server.users.list({ start: 0, count: 2, sort: 'createdAt', blocked: false }) - expect(total).to.equal(1) - expect(data.length).to.equal(1) - - expect(data[0].username).to.not.equal(user16.username) - } - }) - - it('Should unblock a user', async function () { - await server.users.unbanUser({ userId: user16Id }) - user16AccessToken = await server.login.getAccessToken(user16) - await server.users.getMyInfo({ token: user16AccessToken, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('User stats', function () { - let user17Id: number - let user17AccessToken: string - - it('Should report correct initial statistics about a user', async function () { - const user17 = { - username: 'user_17', - password: 'my super password' - } - const created = await server.users.create({ ...user17 }) - - user17Id = created.id - user17AccessToken = await server.login.getAccessToken(user17) - - const user = await server.users.get({ userId: user17Id, withStats: true }) - expect(user.videosCount).to.equal(0) - expect(user.videoCommentsCount).to.equal(0) - expect(user.abusesCount).to.equal(0) - expect(user.abusesCreatedCount).to.equal(0) - expect(user.abusesAcceptedCount).to.equal(0) - }) - - it('Should report correct videos count', async function () { - const attributes = { name: 'video to test user stats' } - await server.videos.upload({ token: user17AccessToken, attributes }) - - const { data } = await server.videos.list() - videoId = data.find(video => video.name === attributes.name).id - - const user = await server.users.get({ userId: user17Id, withStats: true }) - expect(user.videosCount).to.equal(1) - }) - - it('Should report correct video comments for user', async function () { - const text = 'super comment' - await server.comments.createThread({ token: user17AccessToken, videoId, text }) - - const user = await server.users.get({ userId: user17Id, withStats: true }) - expect(user.videoCommentsCount).to.equal(1) - }) - - it('Should report correct abuses counts', async function () { - const reason = 'my super bad reason' - await server.abuses.report({ token: user17AccessToken, videoId, reason }) - - const body1 = await server.abuses.getAdminList() - const abuseId = body1.data[0].id - - const user2 = await server.users.get({ userId: user17Id, withStats: true }) - expect(user2.abusesCount).to.equal(1) // number of incriminations - expect(user2.abusesCreatedCount).to.equal(1) // number of reports created - - await server.abuses.update({ abuseId, body: { state: AbuseState.ACCEPTED } }) - - const user3 = await server.users.get({ userId: user17Id, withStats: true }) - expect(user3.abusesAcceptedCount).to.equal(1) // number of reports created accepted - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/channel-import-videos.ts b/server/tests/api/videos/channel-import-videos.ts deleted file mode 100644 index a66f88a0e..000000000 --- a/server/tests/api/videos/channel-import-videos.ts +++ /dev/null @@ -1,161 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FIXTURE_URLS } from '@server/tests/shared' -import { areHttpImportTestsDisabled } from '@shared/core-utils' -import { - createSingleServer, - getServerImportConfig, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test videos import in a channel', function () { - if (areHttpImportTestsDisabled()) return - - function runSuite (mode: 'youtube-dl' | 'yt-dlp') { - - describe('Import using ' + mode, function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1, getServerImportConfig(mode)) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableChannelSync() - }) - - it('Should import a whole channel without specifying the sync id', async function () { - this.timeout(240_000) - - await server.channels.importVideos({ channelName: server.store.channel.name, externalChannelUrl: FIXTURE_URLS.youtubeChannel }) - await waitJobs(server) - - const videos = await server.videos.listByChannel({ handle: server.store.channel.name }) - expect(videos.total).to.equal(2) - }) - - it('These imports should not have a sync id', async function () { - const { total, data } = await server.imports.getMyVideoImports() - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const videoImport of data) { - expect(videoImport.videoChannelSync).to.not.exist - } - }) - - it('Should import a whole channel and specifying the sync id', async function () { - this.timeout(240_000) - - { - server.store.channel.name = 'channel2' - const { id } = await server.channels.create({ attributes: { name: server.store.channel.name } }) - server.store.channel.id = id - } - - { - const attributes = { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: server.store.channel.id - } - - const { videoChannelSync } = await server.channelSyncs.create({ attributes }) - server.store.videoChannelSync = videoChannelSync - - await waitJobs(server) - } - - await server.channels.importVideos({ - channelName: server.store.channel.name, - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelSyncId: server.store.videoChannelSync.id - }) - - await waitJobs(server) - }) - - it('These imports should have a sync id', async function () { - const { total, data } = await server.imports.getMyVideoImports() - - expect(total).to.equal(4) - expect(data).to.have.lengthOf(4) - - const importsWithSyncId = data.filter(i => !!i.videoChannelSync) - expect(importsWithSyncId).to.have.lengthOf(2) - - for (const videoImport of importsWithSyncId) { - expect(videoImport.videoChannelSync).to.exist - expect(videoImport.videoChannelSync.id).to.equal(server.store.videoChannelSync.id) - } - }) - - it('Should be able to filter imports by this sync id', async function () { - const { total, data } = await server.imports.getMyVideoImports({ videoChannelSyncId: server.store.videoChannelSync.id }) - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - for (const videoImport of data) { - expect(videoImport.videoChannelSync).to.exist - expect(videoImport.videoChannelSync.id).to.equal(server.store.videoChannelSync.id) - } - }) - - it('Should limit max amount of videos synced on full sync', async function () { - this.timeout(240_000) - - await server.kill() - await server.run({ - import: { - video_channel_synchronization: { - full_sync_videos_limit: 1 - } - } - }) - - const { id } = await server.channels.create({ attributes: { name: 'channel3' } }) - const channel3Id = id - - const { videoChannelSync } = await server.channelSyncs.create({ - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: channel3Id - } - }) - const syncId = videoChannelSync.id - - await waitJobs(server) - - await server.channels.importVideos({ - channelName: 'channel3', - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelSyncId: syncId - }) - - await waitJobs(server) - - const { total, data } = await server.videos.listByChannel({ handle: 'channel3' }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - }) - - after(async function () { - await server?.kill() - }) - }) - } - - runSuite('yt-dlp') - - // FIXME: With recent changes on youtube, youtube-dl doesn't fetch live replays which means the test suite fails - // runSuite('youtube-dl') -}) diff --git a/server/tests/api/videos/index.ts b/server/tests/api/videos/index.ts deleted file mode 100644 index 01d0c5852..000000000 --- a/server/tests/api/videos/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import './multiple-servers' -import './resumable-upload' -import './single-server' -import './video-captions' -import './video-change-ownership' -import './video-channels' -import './channel-import-videos' -import './video-channel-syncs' -import './video-comments' -import './video-description' -import './video-files' -import './video-imports' -import './video-nsfw' -import './video-playlists' -import './video-playlist-thumbnails' -import './video-source' -import './video-privacy' -import './video-schedule-update' -import './videos-common-filters' -import './videos-history' -import './videos-overview' -import './video-static-file-privacy' -import './video-storyboard' diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts deleted file mode 100644 index e9aa0e3a1..000000000 --- a/server/tests/api/videos/multiple-servers.ts +++ /dev/null @@ -1,1099 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import request from 'supertest' -import { - checkTmpIsEmpty, - checkVideoFilesWereRemoved, - checkWebTorrentWorks, - completeVideoCheck, - dateIsValid, - saveVideoInServers, - testImageGeneratedByFFmpeg -} from '@server/tests/shared' -import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' -import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test multiple servers', function () { - let servers: PeerTubeServer[] = [] - const toRemove = [] - let videoUUID = '' - let videoChannelId: number - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - - { - const videoChannel = { - name: 'super_channel_name', - displayName: 'my channel', - description: 'super channel' - } - await servers[0].channels.create({ attributes: videoChannel }) - await setDefaultChannelAvatar(servers[0], videoChannel.name) - await setDefaultAccountAvatar(servers) - - const { data } = await servers[0].channels.list({ start: 0, count: 1 }) - videoChannelId = data[0].id - } - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - // Server 1 and server 3 follow each other - await doubleFollow(servers[0], servers[2]) - // Server 2 and server 3 follow each other - await doubleFollow(servers[1], servers[2]) - }) - - it('Should not have videos for all servers', async function () { - for (const server of servers) { - const { data } = await server.videos.list() - expect(data).to.be.an('array') - expect(data.length).to.equal(0) - } - }) - - describe('Should upload the video and propagate on each server', function () { - - it('Should upload the video on server 1 and propagate on each server', async function () { - this.timeout(60000) - - const attributes = { - name: 'my super name for server 1', - category: 5, - licence: 4, - language: 'ja', - nsfw: true, - description: 'my super description for server 1', - support: 'my super support text for server 1', - originallyPublishedAt: '2019-02-10T13:38:14.449Z', - tags: [ 'tag1p1', 'tag2p1' ], - channelId: videoChannelId, - fixture: 'video_short1.webm' - } - await servers[0].videos.upload({ attributes }) - - await waitJobs(servers) - - // All servers should have this video - let publishedAt: string = null - for (const server of servers) { - const isLocal = server.port === servers[0].port - const checkAttributes = { - name: 'my super name for server 1', - category: 5, - licence: 4, - language: 'ja', - nsfw: true, - description: 'my super description for server 1', - support: 'my super support text for server 1', - originallyPublishedAt: '2019-02-10T13:38:14.449Z', - account: { - name: 'root', - host: servers[0].host - }, - isLocal, - publishedAt, - duration: 10, - tags: [ 'tag1p1', 'tag2p1' ], - privacy: VideoPrivacy.PUBLIC, - commentsEnabled: true, - downloadEnabled: true, - channel: { - displayName: 'my channel', - name: 'super_channel_name', - description: 'super channel', - isLocal - }, - fixture: 'video_short1.webm', - files: [ - { - resolution: 720, - size: 572456 - } - ] - } - - const { data } = await server.videos.list() - expect(data).to.be.an('array') - expect(data.length).to.equal(1) - const video = data[0] - - await completeVideoCheck({ server, originServer: servers[0], videoUUID: video.uuid, attributes: checkAttributes }) - publishedAt = video.publishedAt as string - - expect(video.channel.avatars).to.have.lengthOf(2) - expect(video.account.avatars).to.have.lengthOf(2) - - for (const image of [ ...video.channel.avatars, ...video.account.avatars ]) { - expect(image.createdAt).to.exist - expect(image.updatedAt).to.exist - expect(image.width).to.be.above(20).and.below(1000) - expect(image.path).to.exist - - await makeGetRequest({ - url: server.url, - path: image.path, - expectedStatus: HttpStatusCode.OK_200 - }) - } - } - }) - - it('Should upload the video on server 2 and propagate on each server', async function () { - this.timeout(240000) - - const user = { - username: 'user1', - password: 'super_password' - } - await servers[1].users.create({ username: user.username, password: user.password }) - const userAccessToken = await servers[1].login.getAccessToken(user) - - const attributes = { - name: 'my super name for server 2', - category: 4, - licence: 3, - language: 'de', - nsfw: true, - description: 'my super description for server 2', - support: 'my super support text for server 2', - tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ], - fixture: 'video_short2.webm', - thumbnailfile: 'custom-thumbnail.jpg', - previewfile: 'custom-preview.jpg' - } - await servers[1].videos.upload({ token: userAccessToken, attributes, mode: 'resumable' }) - - // Transcoding - await waitJobs(servers) - - // All servers should have this video - for (const server of servers) { - const isLocal = server.url === servers[1].url - const checkAttributes = { - name: 'my super name for server 2', - category: 4, - licence: 3, - language: 'de', - nsfw: true, - description: 'my super description for server 2', - support: 'my super support text for server 2', - account: { - name: 'user1', - host: servers[1].host - }, - isLocal, - commentsEnabled: true, - downloadEnabled: true, - duration: 5, - tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ], - privacy: VideoPrivacy.PUBLIC, - channel: { - displayName: 'Main user1 channel', - name: 'user1_channel', - description: 'super channel', - isLocal - }, - fixture: 'video_short2.webm', - files: [ - { - resolution: 240, - size: 270000 - }, - { - resolution: 360, - size: 359000 - }, - { - resolution: 480, - size: 465000 - }, - { - resolution: 720, - size: 750000 - } - ], - thumbnailfile: 'custom-thumbnail', - previewfile: 'custom-preview' - } - - const { data } = await server.videos.list() - expect(data).to.be.an('array') - expect(data.length).to.equal(2) - const video = data[1] - - await completeVideoCheck({ server, originServer: servers[1], videoUUID: video.uuid, attributes: checkAttributes }) - } - }) - - it('Should upload two videos on server 3 and propagate on each server', async function () { - this.timeout(45000) - - { - const attributes = { - name: 'my super name for server 3', - category: 6, - licence: 5, - language: 'de', - nsfw: true, - description: 'my super description for server 3', - support: 'my super support text for server 3', - tags: [ 'tag1p3' ], - fixture: 'video_short3.webm' - } - await servers[2].videos.upload({ attributes }) - } - - { - const attributes = { - name: 'my super name for server 3-2', - category: 7, - licence: 6, - language: 'ko', - nsfw: false, - description: 'my super description for server 3-2', - support: 'my super support text for server 3-2', - tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ], - fixture: 'video_short.webm' - } - await servers[2].videos.upload({ attributes }) - } - - await waitJobs(servers) - - // All servers should have this video - for (const server of servers) { - const isLocal = server.url === servers[2].url - const { data } = await server.videos.list() - - expect(data).to.be.an('array') - expect(data.length).to.equal(4) - - // We not sure about the order of the two last uploads - let video1 = null - let video2 = null - if (data[2].name === 'my super name for server 3') { - video1 = data[2] - video2 = data[3] - } else { - video1 = data[3] - video2 = data[2] - } - - const checkAttributesVideo1 = { - name: 'my super name for server 3', - category: 6, - licence: 5, - language: 'de', - nsfw: true, - description: 'my super description for server 3', - support: 'my super support text for server 3', - account: { - name: 'root', - host: servers[2].host - }, - isLocal, - duration: 5, - commentsEnabled: true, - downloadEnabled: true, - tags: [ 'tag1p3' ], - privacy: VideoPrivacy.PUBLIC, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal - }, - fixture: 'video_short3.webm', - files: [ - { - resolution: 720, - size: 292677 - } - ] - } - await completeVideoCheck({ server, originServer: servers[2], videoUUID: video1.uuid, attributes: checkAttributesVideo1 }) - - const checkAttributesVideo2 = { - name: 'my super name for server 3-2', - category: 7, - licence: 6, - language: 'ko', - nsfw: false, - description: 'my super description for server 3-2', - support: 'my super support text for server 3-2', - account: { - name: 'root', - host: servers[2].host - }, - commentsEnabled: true, - downloadEnabled: true, - isLocal, - duration: 5, - tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ], - privacy: VideoPrivacy.PUBLIC, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal - }, - fixture: 'video_short.webm', - files: [ - { - resolution: 720, - size: 218910 - } - ] - } - await completeVideoCheck({ server, originServer: servers[2], videoUUID: video2.uuid, attributes: checkAttributesVideo2 }) - } - }) - }) - - describe('It should list local videos', function () { - it('Should list only local videos on server 1', async function () { - const { data, total } = await servers[0].videos.list({ isLocal: true }) - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data.length).to.equal(1) - expect(data[0].name).to.equal('my super name for server 1') - }) - - it('Should list only local videos on server 2', async function () { - const { data, total } = await servers[1].videos.list({ isLocal: true }) - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data.length).to.equal(1) - expect(data[0].name).to.equal('my super name for server 2') - }) - - it('Should list only local videos on server 3', async function () { - const { data, total } = await servers[2].videos.list({ isLocal: true }) - - expect(total).to.equal(2) - expect(data).to.be.an('array') - expect(data.length).to.equal(2) - expect(data[0].name).to.equal('my super name for server 3') - expect(data[1].name).to.equal('my super name for server 3-2') - }) - }) - - describe('Should seed the uploaded video', function () { - - it('Should add the file 1 by asking server 3', async function () { - this.retries(2) - this.timeout(30000) - - const { data } = await servers[2].videos.list() - - const video = data[0] - toRemove.push(data[2]) - toRemove.push(data[3]) - - const videoDetails = await servers[2].videos.get({ id: video.id }) - - await checkWebTorrentWorks(videoDetails.files[0].magnetUri) - }) - - it('Should add the file 2 by asking server 1', async function () { - this.retries(2) - this.timeout(30000) - - const { data } = await servers[0].videos.list() - - const video = data[1] - const videoDetails = await servers[0].videos.get({ id: video.id }) - - await checkWebTorrentWorks(videoDetails.files[0].magnetUri) - }) - - it('Should add the file 3 by asking server 2', async function () { - this.retries(2) - this.timeout(30000) - - const { data } = await servers[1].videos.list() - - const video = data[2] - const videoDetails = await servers[1].videos.get({ id: video.id }) - - await checkWebTorrentWorks(videoDetails.files[0].magnetUri) - }) - - it('Should add the file 3-2 by asking server 1', async function () { - this.retries(2) - this.timeout(30000) - - const { data } = await servers[0].videos.list() - - const video = data[3] - const videoDetails = await servers[0].videos.get({ id: video.id }) - - await checkWebTorrentWorks(videoDetails.files[0].magnetUri) - }) - - it('Should add the file 2 in 360p by asking server 1', async function () { - this.retries(2) - this.timeout(30000) - - const { data } = await servers[0].videos.list() - - const video = data.find(v => v.name === 'my super name for server 2') - const videoDetails = await servers[0].videos.get({ id: video.id }) - - const file = videoDetails.files.find(f => f.resolution.id === 360) - expect(file).not.to.be.undefined - - await checkWebTorrentWorks(file.magnetUri) - }) - }) - - describe('Should update video views, likes and dislikes', function () { - let localVideosServer3 = [] - let remoteVideosServer1 = [] - let remoteVideosServer2 = [] - let remoteVideosServer3 = [] - - before(async function () { - { - const { data } = await servers[0].videos.list() - remoteVideosServer1 = data.filter(video => video.isLocal === false).map(video => video.uuid) - } - - { - const { data } = await servers[1].videos.list() - remoteVideosServer2 = data.filter(video => video.isLocal === false).map(video => video.uuid) - } - - { - const { data } = await servers[2].videos.list() - localVideosServer3 = data.filter(video => video.isLocal === true).map(video => video.uuid) - remoteVideosServer3 = data.filter(video => video.isLocal === false).map(video => video.uuid) - } - }) - - it('Should view multiple videos on owned servers', async function () { - this.timeout(30000) - - await servers[2].views.simulateView({ id: localVideosServer3[0] }) - await wait(1000) - - await servers[2].views.simulateView({ id: localVideosServer3[0] }) - await servers[2].views.simulateView({ id: localVideosServer3[1] }) - - await wait(1000) - - await servers[2].views.simulateView({ id: localVideosServer3[0] }) - await servers[2].views.simulateView({ id: localVideosServer3[0] }) - - await waitJobs(servers) - - for (const server of servers) { - await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) - } - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const video0 = data.find(v => v.uuid === localVideosServer3[0]) - const video1 = data.find(v => v.uuid === localVideosServer3[1]) - - expect(video0.views).to.equal(3) - expect(video1.views).to.equal(1) - } - }) - - it('Should view multiple videos on each servers', async function () { - this.timeout(45000) - - const tasks: Promise[] = [] - tasks.push(servers[0].views.simulateView({ id: remoteVideosServer1[0] })) - tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] })) - tasks.push(servers[1].views.simulateView({ id: remoteVideosServer2[0] })) - tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[0] })) - tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] })) - tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] })) - tasks.push(servers[2].views.simulateView({ id: remoteVideosServer3[1] })) - tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] })) - tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] })) - tasks.push(servers[2].views.simulateView({ id: localVideosServer3[1] })) - - await Promise.all(tasks) - - await waitJobs(servers) - - for (const server of servers) { - await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) - } - - await waitJobs(servers) - - let baseVideos = null - - for (const server of servers) { - const { data } = await server.videos.list() - - // Initialize base videos for future comparisons - if (baseVideos === null) { - baseVideos = data - continue - } - - for (const baseVideo of baseVideos) { - const sameVideo = data.find(video => video.name === baseVideo.name) - expect(baseVideo.views).to.equal(sameVideo.views) - } - } - }) - - it('Should like and dislikes videos on different services', async function () { - this.timeout(50000) - - await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' }) - await wait(500) - await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'dislike' }) - await wait(500) - await servers[0].videos.rate({ id: remoteVideosServer1[0], rating: 'like' }) - await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'like' }) - await wait(500) - await servers[2].videos.rate({ id: localVideosServer3[1], rating: 'dislike' }) - await servers[2].videos.rate({ id: remoteVideosServer3[1], rating: 'dislike' }) - await wait(500) - await servers[2].videos.rate({ id: remoteVideosServer3[0], rating: 'like' }) - - await waitJobs(servers) - await wait(5000) - await waitJobs(servers) - - let baseVideos = null - for (const server of servers) { - const { data } = await server.videos.list() - - // Initialize base videos for future comparisons - if (baseVideos === null) { - baseVideos = data - continue - } - - for (const baseVideo of baseVideos) { - const sameVideo = data.find(video => video.name === baseVideo.name) - expect(baseVideo.likes).to.equal(sameVideo.likes, `Likes of ${sameVideo.uuid} do not correspond`) - expect(baseVideo.dislikes).to.equal(sameVideo.dislikes, `Dislikes of ${sameVideo.uuid} do not correspond`) - } - } - }) - }) - - describe('Should manipulate these videos', function () { - let updatedAtMin: Date - - it('Should update video 3', async function () { - this.timeout(30000) - - const attributes = { - name: 'my super video updated', - category: 10, - licence: 7, - language: 'fr', - nsfw: true, - description: 'my super description updated', - support: 'my super support text updated', - tags: [ 'tag_up_1', 'tag_up_2' ], - thumbnailfile: 'custom-thumbnail.jpg', - originallyPublishedAt: '2019-02-11T13:38:14.449Z', - previewfile: 'custom-preview.jpg' - } - - updatedAtMin = new Date() - await servers[2].videos.update({ id: toRemove[0].id, attributes }) - - await waitJobs(servers) - }) - - it('Should have the video 3 updated on each server', async function () { - this.timeout(30000) - - for (const server of servers) { - const { data } = await server.videos.list() - - const videoUpdated = data.find(video => video.name === 'my super video updated') - expect(!!videoUpdated).to.be.true - - expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin) - - const isLocal = server.url === servers[2].url - const checkAttributes = { - name: 'my super video updated', - category: 10, - licence: 7, - language: 'fr', - nsfw: true, - description: 'my super description updated', - support: 'my super support text updated', - originallyPublishedAt: '2019-02-11T13:38:14.449Z', - account: { - name: 'root', - host: servers[2].host - }, - isLocal, - duration: 5, - commentsEnabled: true, - downloadEnabled: true, - tags: [ 'tag_up_1', 'tag_up_2' ], - privacy: VideoPrivacy.PUBLIC, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal - }, - fixture: 'video_short3.webm', - files: [ - { - resolution: 720, - size: 292677 - } - ], - thumbnailfile: 'custom-thumbnail', - previewfile: 'custom-preview' - } - await completeVideoCheck({ server, originServer: servers[2], videoUUID: videoUpdated.uuid, attributes: checkAttributes }) - } - }) - - it('Should only update thumbnail and update updatedAt attribute', async function () { - this.timeout(30000) - - const attributes = { - thumbnailfile: 'custom-thumbnail.jpg' - } - - updatedAtMin = new Date() - await servers[2].videos.update({ id: toRemove[0].id, attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - const videoUpdated = data.find(video => video.name === 'my super video updated') - expect(new Date(videoUpdated.updatedAt)).to.be.greaterThan(updatedAtMin) - } - }) - - it('Should remove the videos 3 and 3-2 by asking server 3 and correctly delete files', async function () { - this.timeout(30000) - - for (const id of [ toRemove[0].id, toRemove[1].id ]) { - await saveVideoInServers(servers, id) - - await servers[2].videos.remove({ id }) - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoFilesWereRemoved({ server, video: server.store.videoDetails }) - } - } - }) - - it('Should have videos 1 and 3 on each server', async function () { - for (const server of servers) { - const { data } = await server.videos.list() - - expect(data).to.be.an('array') - expect(data.length).to.equal(2) - expect(data[0].name).not.to.equal(data[1].name) - expect(data[0].name).not.to.equal(toRemove[0].name) - expect(data[1].name).not.to.equal(toRemove[0].name) - expect(data[0].name).not.to.equal(toRemove[1].name) - expect(data[1].name).not.to.equal(toRemove[1].name) - - videoUUID = data.find(video => video.name === 'my super name for server 1').uuid - } - }) - - it('Should get the same video by UUID on each server', async function () { - let baseVideo = null - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - if (baseVideo === null) { - baseVideo = video - continue - } - - expect(baseVideo.name).to.equal(video.name) - expect(baseVideo.uuid).to.equal(video.uuid) - expect(baseVideo.category.id).to.equal(video.category.id) - expect(baseVideo.language.id).to.equal(video.language.id) - expect(baseVideo.licence.id).to.equal(video.licence.id) - expect(baseVideo.nsfw).to.equal(video.nsfw) - expect(baseVideo.account.name).to.equal(video.account.name) - expect(baseVideo.account.displayName).to.equal(video.account.displayName) - expect(baseVideo.account.url).to.equal(video.account.url) - expect(baseVideo.account.host).to.equal(video.account.host) - expect(baseVideo.tags).to.deep.equal(video.tags) - } - }) - - it('Should get the preview from each server', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - await testImageGeneratedByFFmpeg(server.url, 'video_short1-preview.webm', video.previewPath) - } - }) - }) - - describe('Should comment these videos', function () { - let childOfFirstChild: VideoCommentThreadTree - - it('Should add comment (threads and replies)', async function () { - this.timeout(25000) - - { - const text = 'my super first comment' - await servers[0].comments.createThread({ videoId: videoUUID, text }) - } - - { - const text = 'my super second comment' - await servers[2].comments.createThread({ videoId: videoUUID, text }) - } - - await waitJobs(servers) - - { - const threadId = await servers[1].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' }) - - const text = 'my super answer to thread 1' - await servers[1].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text }) - } - - await waitJobs(servers) - - { - const threadId = await servers[2].comments.findCommentId({ videoId: videoUUID, text: 'my super first comment' }) - - const body = await servers[2].comments.getThread({ videoId: videoUUID, threadId }) - const childCommentId = body.children[0].comment.id - - const text3 = 'my second answer to thread 1' - await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text: text3 }) - - const text2 = 'my super answer to answer of thread 1' - await servers[2].comments.addReply({ videoId: videoUUID, toCommentId: childCommentId, text: text2 }) - } - - await waitJobs(servers) - }) - - it('Should have these threads', async function () { - for (const server of servers) { - const body = await server.comments.listThreads({ videoId: videoUUID }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - - { - const comment = body.data.find(c => c.text === 'my super first comment') - expect(comment).to.not.be.undefined - expect(comment.inReplyToCommentId).to.be.null - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(servers[0].host) - expect(comment.totalReplies).to.equal(3) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - } - - { - const comment = body.data.find(c => c.text === 'my super second comment') - expect(comment).to.not.be.undefined - expect(comment.inReplyToCommentId).to.be.null - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(servers[2].host) - expect(comment.totalReplies).to.equal(0) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - } - } - }) - - it('Should have these comments', async function () { - for (const server of servers) { - const body = await server.comments.listThreads({ videoId: videoUUID }) - const threadId = body.data.find(c => c.text === 'my super first comment').id - - const tree = await server.comments.getThread({ videoId: videoUUID, threadId }) - - expect(tree.comment.text).equal('my super first comment') - expect(tree.comment.account.name).equal('root') - expect(tree.comment.account.host).equal(servers[0].host) - expect(tree.children).to.have.lengthOf(2) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('my super answer to thread 1') - expect(firstChild.comment.account.name).equal('root') - expect(firstChild.comment.account.host).equal(servers[1].host) - expect(firstChild.children).to.have.lengthOf(1) - - childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') - expect(childOfFirstChild.comment.account.name).equal('root') - expect(childOfFirstChild.comment.account.host).equal(servers[2].host) - expect(childOfFirstChild.children).to.have.lengthOf(0) - - const secondChild = tree.children[1] - expect(secondChild.comment.text).to.equal('my second answer to thread 1') - expect(secondChild.comment.account.name).equal('root') - expect(secondChild.comment.account.host).equal(servers[2].host) - expect(secondChild.children).to.have.lengthOf(0) - } - }) - - it('Should delete a reply', async function () { - this.timeout(30000) - - await servers[2].comments.delete({ videoId: videoUUID, commentId: childOfFirstChild.comment.id }) - - await waitJobs(servers) - }) - - it('Should have this comment marked as deleted', async function () { - for (const server of servers) { - const { data } = await server.comments.listThreads({ videoId: videoUUID }) - const threadId = data.find(c => c.text === 'my super first comment').id - - const tree = await server.comments.getThread({ videoId: videoUUID, threadId }) - expect(tree.comment.text).equal('my super first comment') - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('my super answer to thread 1') - expect(firstChild.children).to.have.lengthOf(1) - - const deletedComment = firstChild.children[0].comment - expect(deletedComment.isDeleted).to.be.true - expect(deletedComment.deletedAt).to.not.be.null - expect(deletedComment.account).to.be.null - expect(deletedComment.text).to.equal('') - - const secondChild = tree.children[1] - expect(secondChild.comment.text).to.equal('my second answer to thread 1') - } - }) - - it('Should delete the thread comments', async function () { - this.timeout(30000) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - const commentId = data.find(c => c.text === 'my super first comment').id - await servers[0].comments.delete({ videoId: videoUUID, commentId }) - - await waitJobs(servers) - }) - - it('Should have the threads marked as deleted on other servers too', async function () { - for (const server of servers) { - const body = await server.comments.listThreads({ videoId: videoUUID }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - - { - const comment = body.data[0] - expect(comment).to.not.be.undefined - expect(comment.inReplyToCommentId).to.be.null - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(servers[2].host) - expect(comment.totalReplies).to.equal(0) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - } - - { - const deletedComment = body.data[1] - expect(deletedComment).to.not.be.undefined - expect(deletedComment.isDeleted).to.be.true - expect(deletedComment.deletedAt).to.not.be.null - expect(deletedComment.text).to.equal('') - expect(deletedComment.inReplyToCommentId).to.be.null - expect(deletedComment.account).to.be.null - expect(deletedComment.totalReplies).to.equal(2) - expect(dateIsValid(deletedComment.createdAt as string)).to.be.true - expect(dateIsValid(deletedComment.updatedAt as string)).to.be.true - expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true - } - } - }) - - it('Should delete a remote thread by the origin server', async function () { - this.timeout(5000) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - const commentId = data.find(c => c.text === 'my super second comment').id - await servers[0].comments.delete({ videoId: videoUUID, commentId }) - - await waitJobs(servers) - }) - - it('Should have the threads marked as deleted on other servers too', async function () { - for (const server of servers) { - const body = await server.comments.listThreads({ videoId: videoUUID }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - { - const comment = body.data[0] - expect(comment.text).to.equal('') - expect(comment.isDeleted).to.be.true - expect(comment.createdAt).to.not.be.null - expect(comment.deletedAt).to.not.be.null - expect(comment.account).to.be.null - expect(comment.totalReplies).to.equal(0) - } - - { - const comment = body.data[1] - expect(comment.text).to.equal('') - expect(comment.isDeleted).to.be.true - expect(comment.createdAt).to.not.be.null - expect(comment.deletedAt).to.not.be.null - expect(comment.account).to.be.null - expect(comment.totalReplies).to.equal(2) - } - } - }) - - it('Should disable comments and download', async function () { - this.timeout(20000) - - const attributes = { - commentsEnabled: false, - downloadEnabled: false - } - - await servers[0].videos.update({ id: videoUUID, attributes }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.commentsEnabled).to.be.false - expect(video.downloadEnabled).to.be.false - - const text = 'my super forbidden comment' - await server.comments.createThread({ videoId: videoUUID, text, expectedStatus: HttpStatusCode.CONFLICT_409 }) - } - }) - }) - - describe('With minimum parameters', function () { - it('Should upload and propagate the video', async function () { - this.timeout(120000) - - const path = '/api/v1/videos/upload' - - const req = request(servers[1].url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + servers[1].accessToken) - .field('name', 'minimum parameters') - .field('privacy', '1') - .field('channelId', '1') - - await req.attach('videofile', buildAbsoluteFixturePath('video_short.webm')) - .expect(HttpStatusCode.OK_200) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - const video = data.find(v => v.name === 'minimum parameters') - - const isLocal = server.url === servers[1].url - const checkAttributes = { - name: 'minimum parameters', - category: null, - licence: null, - language: null, - nsfw: false, - description: null, - support: null, - account: { - name: 'root', - host: servers[1].host - }, - isLocal, - duration: 5, - commentsEnabled: true, - downloadEnabled: true, - tags: [], - privacy: VideoPrivacy.PUBLIC, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal - }, - fixture: 'video_short.webm', - files: [ - { - resolution: 720, - size: 61000 - }, - { - resolution: 480, - size: 40000 - }, - { - resolution: 360, - size: 32000 - }, - { - resolution: 240, - size: 23000 - } - ] - } - await completeVideoCheck({ server, originServer: servers[1], videoUUID: video.uuid, attributes: checkAttributes }) - } - }) - }) - - describe('TMP directory', function () { - it('Should have an empty tmp directory', async function () { - for (const server of servers) { - await checkTmpIsEmpty(server) - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/resumable-upload.ts b/server/tests/api/videos/resumable-upload.ts deleted file mode 100644 index cac1201e9..000000000 --- a/server/tests/api/videos/resumable-upload.ts +++ /dev/null @@ -1,310 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir, stat } from 'fs-extra' -import { join } from 'path' -import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { sha1 } from '@shared/extra-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' - -// Most classic resumable upload tests are done in other test suites - -describe('Test resumable upload', function () { - const path = '/api/v1/videos/upload-resumable' - const defaultFixture = 'video_short.mp4' - let server: PeerTubeServer - let rootId: number - let userAccessToken: string - let userChannelId: number - - async function buildSize (fixture: string, size?: number) { - if (size !== undefined) return size - - const baseFixture = buildAbsoluteFixturePath(fixture) - return (await stat(baseFixture)).size - } - - async function prepareUpload (options: { - channelId?: number - token?: string - size?: number - originalName?: string - lastModified?: number - } = {}) { - const { token, originalName, lastModified } = options - - const size = await buildSize(defaultFixture, options.size) - - const attributes = { - name: 'video', - channelId: options.channelId ?? server.store.channel.id, - privacy: VideoPrivacy.PUBLIC, - fixture: defaultFixture - } - - const mimetype = 'video/mp4' - - const res = await server.videos.prepareResumableUpload({ path, token, attributes, size, mimetype, originalName, lastModified }) - - return res.header['location'].split('?')[1] - } - - async function sendChunks (options: { - token?: string - pathUploadId: string - size?: number - expectedStatus?: HttpStatusCode - contentLength?: number - contentRange?: string - contentRangeBuilder?: (start: number, chunk: any) => string - digestBuilder?: (chunk: any) => string - }) { - const { token, pathUploadId, expectedStatus, contentLength, contentRangeBuilder, digestBuilder } = options - - const size = await buildSize(defaultFixture, options.size) - const absoluteFilePath = buildAbsoluteFixturePath(defaultFixture) - - return server.videos.sendResumableChunks({ - token, - path, - pathUploadId, - videoFilePath: absoluteFilePath, - size, - contentLength, - contentRangeBuilder, - digestBuilder, - expectedStatus - }) - } - - async function checkFileSize (uploadIdArg: string, expectedSize: number | null) { - const uploadId = uploadIdArg.replace(/^upload_id=/, '') - - const subPath = join('tmp', 'resumable-uploads', `${rootId}-${uploadId}.mp4`) - const filePath = server.servers.buildDirectory(subPath) - const exists = await pathExists(filePath) - - if (expectedSize === null) { - expect(exists).to.be.false - return - } - - expect(exists).to.be.true - - expect((await stat(filePath)).size).to.equal(expectedSize) - } - - async function countResumableUploads (wait?: number) { - const subPath = join('tmp', 'resumable-uploads') - const filePath = server.servers.buildDirectory(subPath) - await new Promise(resolve => setTimeout(resolve, wait)) - const files = await readdir(filePath) - return files.length - } - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - const body = await server.users.getMyInfo() - rootId = body.id - - { - userAccessToken = await server.users.generateUserAndToken('user1') - const { videoChannels } = await server.users.getMyInfo({ token: userAccessToken }) - userChannelId = videoChannels[0].id - } - - await server.users.update({ userId: rootId, videoQuota: 10_000_000 }) - }) - - describe('Directory cleaning', function () { - - it('Should correctly delete files after an upload', async function () { - const uploadId = await prepareUpload() - await sendChunks({ pathUploadId: uploadId }) - await server.videos.endResumableUpload({ path, pathUploadId: uploadId }) - - expect(await countResumableUploads()).to.equal(0) - }) - - it('Should correctly delete corrupt files', async function () { - const uploadId = await prepareUpload({ size: 8 * 1024 }) - await sendChunks({ pathUploadId: uploadId, size: 8 * 1024, expectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422 }) - - expect(await countResumableUploads(2000)).to.equal(0) - }) - - it('Should not delete files after an unfinished upload', async function () { - await prepareUpload() - - expect(await countResumableUploads()).to.equal(2) - }) - - it('Should not delete recent uploads', async function () { - await server.debug.sendCommand({ body: { command: 'remove-dandling-resumable-uploads' } }) - - expect(await countResumableUploads()).to.equal(2) - }) - - it('Should delete old uploads', async function () { - await server.debug.sendCommand({ body: { command: 'remove-dandling-resumable-uploads' } }) - - expect(await countResumableUploads()).to.equal(0) - }) - }) - - describe('Resumable upload and chunks', function () { - - it('Should accept the same amount of chunks', async function () { - const uploadId = await prepareUpload() - await sendChunks({ pathUploadId: uploadId }) - - await checkFileSize(uploadId, null) - }) - - it('Should not accept more chunks than expected', async function () { - const uploadId = await prepareUpload({ size: 100 }) - - await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.CONFLICT_409 }) - await checkFileSize(uploadId, 0) - }) - - it('Should not accept more chunks than expected with an invalid content length/content range', async function () { - const uploadId = await prepareUpload({ size: 1500 }) - - // Content length check can be different depending on the node version - try { - await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.CONFLICT_409, contentLength: 1000 }) - await checkFileSize(uploadId, 0) - } catch { - await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.BAD_REQUEST_400, contentLength: 1000 }) - await checkFileSize(uploadId, 0) - } - }) - - it('Should not accept more chunks than expected with an invalid content length', async function () { - const uploadId = await prepareUpload({ size: 500 }) - - const size = 1000 - - // Content length check seems to have changed in v16 - const expectedStatus = process.version.startsWith('v16') - ? HttpStatusCode.CONFLICT_409 - : HttpStatusCode.BAD_REQUEST_400 - - const contentRangeBuilder = (start: number) => `bytes ${start}-${start + size - 1}/${size}` - await sendChunks({ pathUploadId: uploadId, expectedStatus, contentRangeBuilder, contentLength: size }) - await checkFileSize(uploadId, 0) - }) - - it('Should be able to accept 2 PUT requests', async function () { - const uploadId = await prepareUpload() - - const result1 = await sendChunks({ pathUploadId: uploadId }) - const result2 = await sendChunks({ pathUploadId: uploadId }) - - expect(result1.body.video.uuid).to.exist - expect(result1.body.video.uuid).to.equal(result2.body.video.uuid) - - expect(result1.headers['x-resumable-upload-cached']).to.not.exist - expect(result2.headers['x-resumable-upload-cached']).to.equal('true') - - await checkFileSize(uploadId, null) - }) - - it('Should not have the same upload id with 2 different users', async function () { - const originalName = 'toto.mp4' - const lastModified = new Date().getTime() - - const uploadId1 = await prepareUpload({ originalName, lastModified, token: server.accessToken }) - const uploadId2 = await prepareUpload({ originalName, lastModified, channelId: userChannelId, token: userAccessToken }) - - expect(uploadId1).to.not.equal(uploadId2) - }) - - it('Should have the same upload id with the same user', async function () { - const originalName = 'toto.mp4' - const lastModified = new Date().getTime() - - const uploadId1 = await prepareUpload({ originalName, lastModified }) - const uploadId2 = await prepareUpload({ originalName, lastModified }) - - expect(uploadId1).to.equal(uploadId2) - }) - - it('Should not cache a request with 2 different users', async function () { - const originalName = 'toto.mp4' - const lastModified = new Date().getTime() - - const uploadId = await prepareUpload({ originalName, lastModified, token: server.accessToken }) - - await sendChunks({ pathUploadId: uploadId, token: server.accessToken }) - await sendChunks({ pathUploadId: uploadId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should not cache a request after a delete', async function () { - const originalName = 'toto.mp4' - const lastModified = new Date().getTime() - const uploadId1 = await prepareUpload({ originalName, lastModified, token: server.accessToken }) - - await sendChunks({ pathUploadId: uploadId1 }) - await server.videos.endResumableUpload({ path, pathUploadId: uploadId1 }) - - const uploadId2 = await prepareUpload({ originalName, lastModified, token: server.accessToken }) - expect(uploadId1).to.equal(uploadId2) - - const result2 = await sendChunks({ pathUploadId: uploadId1 }) - expect(result2.headers['x-resumable-upload-cached']).to.not.exist - }) - - it('Should not cache after video deletion', async function () { - const originalName = 'toto.mp4' - const lastModified = new Date().getTime() - - const uploadId1 = await prepareUpload({ originalName, lastModified }) - const result1 = await sendChunks({ pathUploadId: uploadId1 }) - await server.videos.remove({ id: result1.body.video.uuid }) - - const uploadId2 = await prepareUpload({ originalName, lastModified }) - const result2 = await sendChunks({ pathUploadId: uploadId2 }) - expect(result1.body.video.uuid).to.not.equal(result2.body.video.uuid) - - expect(result2.headers['x-resumable-upload-cached']).to.not.exist - - await checkFileSize(uploadId1, null) - await checkFileSize(uploadId2, null) - }) - - it('Should refuse an invalid digest', async function () { - const uploadId = await prepareUpload({ token: server.accessToken }) - - await sendChunks({ - pathUploadId: uploadId, - token: server.accessToken, - digestBuilder: () => 'sha=' + 'a'.repeat(40), - expectedStatus: 460 as any - }) - }) - - it('Should accept an appropriate digest', async function () { - const uploadId = await prepareUpload({ token: server.accessToken }) - - await sendChunks({ - pathUploadId: uploadId, - token: server.accessToken, - digestBuilder: (chunk: Buffer) => { - return 'sha1=' + sha1(chunk, 'base64') - } - }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts deleted file mode 100644 index 66414aa5b..000000000 --- a/server/tests/api/videos/single-server.ts +++ /dev/null @@ -1,460 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkVideoFilesWereRemoved, completeVideoCheck, testImageGeneratedByFFmpeg } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { Video, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - waitJobs -} from '@shared/server-commands' - -describe('Test a single server', function () { - - function runSuite (mode: 'legacy' | 'resumable') { - let server: PeerTubeServer = null - let videoId: number | string - let videoId2: string - let videoUUID = '' - let videosListBase: any[] = null - - const getCheckAttributes = () => ({ - name: 'my super name', - category: 2, - licence: 6, - language: 'zh', - nsfw: true, - description: 'my super description', - support: 'my super support text', - account: { - name: 'root', - host: server.host - }, - isLocal: true, - duration: 5, - tags: [ 'tag1', 'tag2', 'tag3' ], - privacy: VideoPrivacy.PUBLIC, - commentsEnabled: true, - downloadEnabled: true, - channel: { - displayName: 'Main root channel', - name: 'root_channel', - description: '', - isLocal: true - }, - fixture: 'video_short.webm', - files: [ - { - resolution: 720, - size: 218910 - } - ] - }) - - const updateCheckAttributes = () => ({ - name: 'my super video updated', - category: 4, - licence: 2, - language: 'ar', - nsfw: false, - description: 'my super description updated', - support: 'my super support text updated', - account: { - name: 'root', - host: server.host - }, - isLocal: true, - tags: [ 'tagup1', 'tagup2' ], - privacy: VideoPrivacy.PUBLIC, - duration: 5, - commentsEnabled: false, - downloadEnabled: false, - channel: { - name: 'root_channel', - displayName: 'Main root channel', - description: '', - isLocal: true - }, - fixture: 'video_short3.webm', - files: [ - { - resolution: 720, - size: 292677 - } - ] - }) - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(server) - }) - - it('Should list video categories', async function () { - const categories = await server.videos.getCategories() - expect(Object.keys(categories)).to.have.length.above(10) - - expect(categories[11]).to.equal('News & Politics') - }) - - it('Should list video licences', async function () { - const licences = await server.videos.getLicences() - expect(Object.keys(licences)).to.have.length.above(5) - - expect(licences[3]).to.equal('Attribution - No Derivatives') - }) - - it('Should list video languages', async function () { - const languages = await server.videos.getLanguages() - expect(Object.keys(languages)).to.have.length.above(5) - - expect(languages['ru']).to.equal('Russian') - }) - - it('Should list video privacies', async function () { - const privacies = await server.videos.getPrivacies() - expect(Object.keys(privacies)).to.have.length.at.least(3) - - expect(privacies[3]).to.equal('Private') - }) - - it('Should not have videos', async function () { - const { data, total } = await server.videos.list() - - expect(total).to.equal(0) - expect(data).to.be.an('array') - expect(data.length).to.equal(0) - }) - - it('Should upload the video', async function () { - const attributes = { - name: 'my super name', - category: 2, - nsfw: true, - licence: 6, - tags: [ 'tag1', 'tag2', 'tag3' ] - } - const video = await server.videos.upload({ attributes, mode }) - expect(video).to.not.be.undefined - expect(video.id).to.equal(1) - expect(video.uuid).to.have.length.above(5) - - videoId = video.id - videoUUID = video.uuid - }) - - it('Should get and seed the uploaded video', async function () { - this.timeout(5000) - - const { data, total } = await server.videos.list() - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data.length).to.equal(1) - - const video = data[0] - await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: getCheckAttributes() }) - }) - - it('Should get the video by UUID', async function () { - this.timeout(5000) - - const video = await server.videos.get({ id: videoUUID }) - await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: getCheckAttributes() }) - }) - - it('Should have the views updated', async function () { - this.timeout(20000) - - await server.views.simulateView({ id: videoId }) - await server.views.simulateView({ id: videoId }) - await server.views.simulateView({ id: videoId }) - - await wait(1500) - - await server.views.simulateView({ id: videoId }) - await server.views.simulateView({ id: videoId }) - - await wait(1500) - - await server.views.simulateView({ id: videoId }) - await server.views.simulateView({ id: videoId }) - - await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) - - const video = await server.videos.get({ id: videoId }) - expect(video.views).to.equal(3) - }) - - it('Should remove the video', async function () { - const video = await server.videos.get({ id: videoId }) - await server.videos.remove({ id: videoId }) - - await checkVideoFilesWereRemoved({ video, server }) - }) - - it('Should not have videos', async function () { - const { total, data } = await server.videos.list() - - expect(total).to.equal(0) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(0) - }) - - it('Should upload 6 videos', async function () { - this.timeout(120000) - - const videos = new Set([ - 'video_short.mp4', 'video_short.ogv', 'video_short.webm', - 'video_short1.webm', 'video_short2.webm', 'video_short3.webm' - ]) - - for (const video of videos) { - const attributes = { - name: video + ' name', - description: video + ' description', - category: 2, - licence: 1, - language: 'en', - nsfw: true, - tags: [ 'tag1', 'tag2', 'tag3' ], - fixture: video - } - - await server.videos.upload({ attributes, mode }) - } - }) - - it('Should have the correct durations', async function () { - const { total, data } = await server.videos.list() - - expect(total).to.equal(6) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(6) - - const videosByName: { [ name: string ]: Video } = {} - data.forEach(v => { videosByName[v.name] = v }) - - expect(videosByName['video_short.mp4 name'].duration).to.equal(5) - expect(videosByName['video_short.ogv name'].duration).to.equal(5) - expect(videosByName['video_short.webm name'].duration).to.equal(5) - expect(videosByName['video_short1.webm name'].duration).to.equal(10) - expect(videosByName['video_short2.webm name'].duration).to.equal(5) - expect(videosByName['video_short3.webm name'].duration).to.equal(5) - }) - - it('Should have the correct thumbnails', async function () { - const { data } = await server.videos.list() - - // For the next test - videosListBase = data - - for (const video of data) { - const videoName = video.name.replace(' name', '') - await testImageGeneratedByFFmpeg(server.url, videoName, video.thumbnailPath) - } - }) - - it('Should list only the two first videos', async function () { - const { total, data } = await server.videos.list({ start: 0, count: 2, sort: 'name' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(2) - expect(data[0].name).to.equal(videosListBase[0].name) - expect(data[1].name).to.equal(videosListBase[1].name) - }) - - it('Should list only the next three videos', async function () { - const { total, data } = await server.videos.list({ start: 2, count: 3, sort: 'name' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(3) - expect(data[0].name).to.equal(videosListBase[2].name) - expect(data[1].name).to.equal(videosListBase[3].name) - expect(data[2].name).to.equal(videosListBase[4].name) - }) - - it('Should list the last video', async function () { - const { total, data } = await server.videos.list({ start: 5, count: 6, sort: 'name' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(1) - expect(data[0].name).to.equal(videosListBase[5].name) - }) - - it('Should not have the total field', async function () { - const { total, data } = await server.videos.list({ start: 5, count: 6, sort: 'name', skipCount: true }) - - expect(total).to.not.exist - expect(data.length).to.equal(1) - expect(data[0].name).to.equal(videosListBase[5].name) - }) - - it('Should list and sort by name in descending order', async function () { - const { total, data } = await server.videos.list({ sort: '-name' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(6) - expect(data[0].name).to.equal('video_short.webm name') - expect(data[1].name).to.equal('video_short.ogv name') - expect(data[2].name).to.equal('video_short.mp4 name') - expect(data[3].name).to.equal('video_short3.webm name') - expect(data[4].name).to.equal('video_short2.webm name') - expect(data[5].name).to.equal('video_short1.webm name') - - videoId = data[3].uuid - videoId2 = data[5].uuid - }) - - it('Should list and sort by trending in descending order', async function () { - const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-trending' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(2) - }) - - it('Should list and sort by hotness in descending order', async function () { - const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-hot' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(2) - }) - - it('Should list and sort by best in descending order', async function () { - const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-best' }) - - expect(total).to.equal(6) - expect(data.length).to.equal(2) - }) - - it('Should update a video', async function () { - const attributes = { - name: 'my super video updated', - category: 4, - licence: 2, - language: 'ar', - nsfw: false, - description: 'my super description updated', - commentsEnabled: false, - downloadEnabled: false, - tags: [ 'tagup1', 'tagup2' ] - } - await server.videos.update({ id: videoId, attributes }) - }) - - it('Should have the video updated', async function () { - this.timeout(60000) - - await waitJobs([ server ]) - - const video = await server.videos.get({ id: videoId }) - - await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: updateCheckAttributes() }) - }) - - it('Should update only the tags of a video', async function () { - const attributes = { - tags: [ 'supertag', 'tag1', 'tag2' ] - } - await server.videos.update({ id: videoId, attributes }) - - const video = await server.videos.get({ id: videoId }) - - await completeVideoCheck({ - server, - originServer: server, - videoUUID: video.uuid, - attributes: Object.assign(updateCheckAttributes(), attributes) - }) - }) - - it('Should update only the description of a video', async function () { - const attributes = { - description: 'hello everybody' - } - await server.videos.update({ id: videoId, attributes }) - - const video = await server.videos.get({ id: videoId }) - - await completeVideoCheck({ - server, - originServer: server, - videoUUID: video.uuid, - attributes: Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes) - }) - }) - - it('Should like a video', async function () { - await server.videos.rate({ id: videoId, rating: 'like' }) - - const video = await server.videos.get({ id: videoId }) - - expect(video.likes).to.equal(1) - expect(video.dislikes).to.equal(0) - }) - - it('Should dislike the same video', async function () { - await server.videos.rate({ id: videoId, rating: 'dislike' }) - - const video = await server.videos.get({ id: videoId }) - - expect(video.likes).to.equal(0) - expect(video.dislikes).to.equal(1) - }) - - it('Should sort by originallyPublishedAt', async function () { - { - const now = new Date() - const attributes = { originallyPublishedAt: now.toISOString() } - await server.videos.update({ id: videoId, attributes }) - - const { data } = await server.videos.list({ sort: '-originallyPublishedAt' }) - const names = data.map(v => v.name) - - expect(names[0]).to.equal('my super video updated') - expect(names[1]).to.equal('video_short2.webm name') - expect(names[2]).to.equal('video_short1.webm name') - expect(names[3]).to.equal('video_short.webm name') - expect(names[4]).to.equal('video_short.ogv name') - expect(names[5]).to.equal('video_short.mp4 name') - } - - { - const now = new Date() - const attributes = { originallyPublishedAt: now.toISOString() } - await server.videos.update({ id: videoId2, attributes }) - - const { data } = await server.videos.list({ sort: '-originallyPublishedAt' }) - const names = data.map(v => v.name) - - expect(names[0]).to.equal('video_short1.webm name') - expect(names[1]).to.equal('my super video updated') - expect(names[2]).to.equal('video_short2.webm name') - expect(names[3]).to.equal('video_short.webm name') - expect(names[4]).to.equal('video_short.ogv name') - expect(names[5]).to.equal('video_short.mp4 name') - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) - } - - describe('Legacy upload', function () { - runSuite('legacy') - }) - - describe('Resumable upload', function () { - runSuite('resumable') - }) -}) diff --git a/server/tests/api/videos/video-captions.ts b/server/tests/api/videos/video-captions.ts deleted file mode 100644 index 0630c9d3a..000000000 --- a/server/tests/api/videos/video-captions.ts +++ /dev/null @@ -1,188 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkVideoFilesWereRemoved, testCaptionFile } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test video captions', function () { - const uuidRegex = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' - - let servers: PeerTubeServer[] - let videoUUID: string - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await doubleFollow(servers[0], servers[1]) - - await waitJobs(servers) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video name' } }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should list the captions and return an empty list', async function () { - for (const server of servers) { - const body = await server.captions.list({ videoId: videoUUID }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should create two new captions', async function () { - this.timeout(30000) - - await servers[0].captions.add({ - language: 'ar', - videoId: videoUUID, - fixture: 'subtitle-good1.vtt' - }) - - await servers[0].captions.add({ - language: 'zh', - videoId: videoUUID, - fixture: 'subtitle-good2.vtt', - mimeType: 'application/octet-stream' - }) - - await waitJobs(servers) - }) - - it('Should list these uploaded captions', async function () { - for (const server of servers) { - const body = await server.captions.list({ videoId: videoUUID }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - const caption1 = body.data[0] - expect(caption1.language.id).to.equal('ar') - expect(caption1.language.label).to.equal('Arabic') - expect(caption1.captionPath).to.match(new RegExp('^/lazy-static/video-captions/' + uuidRegex + '-ar.vtt$')) - await testCaptionFile(server.url, caption1.captionPath, 'Subtitle good 1.') - - const caption2 = body.data[1] - expect(caption2.language.id).to.equal('zh') - expect(caption2.language.label).to.equal('Chinese') - expect(caption2.captionPath).to.match(new RegExp('^/lazy-static/video-captions/' + uuidRegex + '-zh.vtt$')) - await testCaptionFile(server.url, caption2.captionPath, 'Subtitle good 2.') - } - }) - - it('Should replace an existing caption', async function () { - this.timeout(30000) - - await servers[0].captions.add({ - language: 'ar', - videoId: videoUUID, - fixture: 'subtitle-good2.vtt' - }) - - await waitJobs(servers) - }) - - it('Should have this caption updated', async function () { - for (const server of servers) { - const body = await server.captions.list({ videoId: videoUUID }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - const caption1 = body.data[0] - expect(caption1.language.id).to.equal('ar') - expect(caption1.language.label).to.equal('Arabic') - expect(caption1.captionPath).to.match(new RegExp('^/lazy-static/video-captions/' + uuidRegex + '-ar.vtt$')) - await testCaptionFile(server.url, caption1.captionPath, 'Subtitle good 2.') - } - }) - - it('Should replace an existing caption with a srt file and convert it', async function () { - this.timeout(30000) - - await servers[0].captions.add({ - language: 'ar', - videoId: videoUUID, - fixture: 'subtitle-good.srt' - }) - - await waitJobs(servers) - - // Cache invalidation - await wait(3000) - }) - - it('Should have this caption updated and converted', async function () { - for (const server of servers) { - const body = await server.captions.list({ videoId: videoUUID }) - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(2) - - const caption1 = body.data[0] - expect(caption1.language.id).to.equal('ar') - expect(caption1.language.label).to.equal('Arabic') - expect(caption1.captionPath).to.match(new RegExp('^/lazy-static/video-captions/' + uuidRegex + '-ar.vtt$')) - - const expected = 'WEBVTT FILE\r\n' + - '\r\n' + - '1\r\n' + - '00:00:01.600 --> 00:00:04.200\r\n' + - 'English (US)\r\n' + - '\r\n' + - '2\r\n' + - '00:00:05.900 --> 00:00:07.999\r\n' + - 'This is a subtitle in American English\r\n' + - '\r\n' + - '3\r\n' + - '00:00:10.000 --> 00:00:14.000\r\n' + - 'Adding subtitles is very easy to do\r\n' - await testCaptionFile(server.url, caption1.captionPath, expected) - } - }) - - it('Should remove one caption', async function () { - this.timeout(30000) - - await servers[0].captions.delete({ videoId: videoUUID, language: 'ar' }) - - await waitJobs(servers) - }) - - it('Should only list the caption that was not deleted', async function () { - for (const server of servers) { - const body = await server.captions.list({ videoId: videoUUID }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const caption = body.data[0] - - expect(caption.language.id).to.equal('zh') - expect(caption.language.label).to.equal('Chinese') - expect(caption.captionPath).to.match(new RegExp('^/lazy-static/video-captions/' + uuidRegex + '-zh.vtt$')) - await testCaptionFile(server.url, caption.captionPath, 'Subtitle good 2.') - } - }) - - it('Should remove the video, and thus all video captions', async function () { - const video = await servers[0].videos.get({ id: videoUUID }) - const { data: captions } = await servers[0].captions.list({ videoId: videoUUID }) - - await servers[0].videos.remove({ id: videoUUID }) - - await checkVideoFilesWereRemoved({ server: servers[0], video, captions }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts deleted file mode 100644 index 99d774c2b..000000000 --- a/server/tests/api/videos/video-change-ownership.ts +++ /dev/null @@ -1,314 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - ChangeOwnershipCommand, - cleanupTests, - createMultipleServers, - createSingleServer, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' - -describe('Test video change ownership - nominal', function () { - let servers: PeerTubeServer[] = [] - - const firstUser = 'first' - const secondUser = 'second' - - let firstUserToken = '' - let firstUserChannelId: number - - let secondUserToken = '' - let secondUserChannelId: number - - let lastRequestId: number - - let liveId: number - - let command: ChangeOwnershipCommand - - before(async function () { - this.timeout(50000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: false - }, - live: { - enabled: true - } - } - }) - - firstUserToken = await servers[0].users.generateUserAndToken(firstUser) - secondUserToken = await servers[0].users.generateUserAndToken(secondUser) - - { - const { videoChannels } = await servers[0].users.getMyInfo({ token: firstUserToken }) - firstUserChannelId = videoChannels[0].id - } - - { - const { videoChannels } = await servers[0].users.getMyInfo({ token: secondUserToken }) - secondUserChannelId = videoChannels[0].id - } - - { - const attributes = { - name: 'my super name', - description: 'my super description' - } - const { id } = await servers[0].videos.upload({ token: firstUserToken, attributes }) - - servers[0].store.videoCreated = await servers[0].videos.get({ id }) - } - - { - const attributes = { name: 'live', channelId: firstUserChannelId, privacy: VideoPrivacy.PUBLIC } - const video = await servers[0].live.create({ token: firstUserToken, fields: attributes }) - - liveId = video.id - } - - command = servers[0].changeOwnership - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should not have video change ownership', async function () { - { - const body = await command.list({ token: firstUserToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - - { - const body = await command.list({ token: secondUserToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - }) - - it('Should send a request to change ownership of a video', async function () { - this.timeout(15000) - - await command.create({ token: firstUserToken, videoId: servers[0].store.videoCreated.id, username: secondUser }) - }) - - it('Should only return a request to change ownership for the second user', async function () { - { - const body = await command.list({ token: firstUserToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - - { - const body = await command.list({ token: secondUserToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(1) - - lastRequestId = body.data[0].id - } - }) - - it('Should accept the same change ownership request without crashing', async function () { - await command.create({ token: firstUserToken, videoId: servers[0].store.videoCreated.id, username: secondUser }) - }) - - it('Should not create multiple change ownership requests while one is waiting', async function () { - const body = await command.list({ token: secondUserToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(1) - }) - - it('Should not be possible to refuse the change of ownership from first user', async function () { - await command.refuse({ token: firstUserToken, ownershipId: lastRequestId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should be possible to refuse the change of ownership from second user', async function () { - await command.refuse({ token: secondUserToken, ownershipId: lastRequestId }) - }) - - it('Should send a new request to change ownership of a video', async function () { - this.timeout(15000) - - await command.create({ token: firstUserToken, videoId: servers[0].store.videoCreated.id, username: secondUser }) - }) - - it('Should return two requests to change ownership for the second user', async function () { - { - const body = await command.list({ token: firstUserToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - - { - const body = await command.list({ token: secondUserToken }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(2) - - lastRequestId = body.data[0].id - } - }) - - it('Should not be possible to accept the change of ownership from first user', async function () { - await command.accept({ - token: firstUserToken, - ownershipId: lastRequestId, - channelId: secondUserChannelId, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should be possible to accept the change of ownership from second user', async function () { - await command.accept({ token: secondUserToken, ownershipId: lastRequestId, channelId: secondUserChannelId }) - - await waitJobs(servers) - }) - - it('Should have the channel of the video updated', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: servers[0].store.videoCreated.uuid }) - - expect(video.name).to.equal('my super name') - expect(video.channel.displayName).to.equal('Main second channel') - expect(video.channel.name).to.equal('second_channel') - } - }) - - it('Should send a request to change ownership of a live', async function () { - this.timeout(15000) - - await command.create({ token: firstUserToken, videoId: liveId, username: secondUser }) - - const body = await command.list({ token: secondUserToken }) - - expect(body.total).to.equal(3) - expect(body.data.length).to.equal(3) - - lastRequestId = body.data[0].id - }) - - it('Should accept a live ownership change', async function () { - this.timeout(20000) - - await command.accept({ token: secondUserToken, ownershipId: lastRequestId, channelId: secondUserChannelId }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: servers[0].store.videoCreated.uuid }) - - expect(video.name).to.equal('my super name') - expect(video.channel.displayName).to.equal('Main second channel') - expect(video.channel.name).to.equal('second_channel') - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) - -describe('Test video change ownership - quota too small', function () { - let server: PeerTubeServer - const firstUser = 'first' - const secondUser = 'second' - - let firstUserToken = '' - let secondUserToken = '' - let lastRequestId: number - - before(async function () { - this.timeout(50000) - - // Run one server - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.users.create({ username: secondUser, videoQuota: 10 }) - - firstUserToken = await server.users.generateUserAndToken(firstUser) - secondUserToken = await server.login.getAccessToken(secondUser) - - // Upload some videos on the server - const attributes = { - name: 'my super name', - description: 'my super description' - } - await server.videos.upload({ token: firstUserToken, attributes }) - - await waitJobs(server) - - const { data } = await server.videos.list() - expect(data.length).to.equal(1) - - server.store.videoCreated = data.find(video => video.name === 'my super name') - }) - - it('Should send a request to change ownership of a video', async function () { - this.timeout(15000) - - await server.changeOwnership.create({ token: firstUserToken, videoId: server.store.videoCreated.id, username: secondUser }) - }) - - it('Should only return a request to change ownership for the second user', async function () { - { - const body = await server.changeOwnership.list({ token: firstUserToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(0) - } - - { - const body = await server.changeOwnership.list({ token: secondUserToken }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data.length).to.equal(1) - - lastRequestId = body.data[0].id - } - }) - - it('Should not be possible to accept the change of ownership from second user because of exceeded quota', async function () { - const { videoChannels } = await server.users.getMyInfo({ token: secondUserToken }) - const channelId = videoChannels[0].id - - await server.changeOwnership.accept({ - token: secondUserToken, - ownershipId: lastRequestId, - channelId, - expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413 - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/video-channel-syncs.ts b/server/tests/api/videos/video-channel-syncs.ts deleted file mode 100644 index 7f688c7d6..000000000 --- a/server/tests/api/videos/video-channel-syncs.ts +++ /dev/null @@ -1,320 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FIXTURE_URLS, SQLCommand } from '@server/tests/shared' -import { areHttpImportTestsDisabled } from '@shared/core-utils' -import { VideoChannelSyncState, VideoInclude, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - getServerImportConfig, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test channel synchronizations', function () { - if (areHttpImportTestsDisabled()) return - - function runSuite (mode: 'youtube-dl' | 'yt-dlp') { - - describe('Sync using ' + mode, function () { - let servers: PeerTubeServer[] - let sqlCommands: SQLCommand[] = [] - - let startTestDate: Date - - let rootChannelSyncId: number - const userInfo = { - accessToken: '', - username: 'user1', - channelName: 'user1_channel', - channelId: -1, - syncId: -1 - } - - async function changeDateForSync (channelSyncId: number, newDate: string) { - await sqlCommands[0].updateQuery( - `UPDATE "videoChannelSync" ` + - `SET "createdAt"='${newDate}', "lastSyncAt"='${newDate}' ` + - `WHERE id=${channelSyncId}` - ) - } - - async function listAllVideosOfChannel (channelName: string) { - return servers[0].videos.listByChannel({ - handle: channelName, - include: VideoInclude.NOT_PUBLISHED_STATE - }) - } - - async function forceSyncAll (videoChannelSyncId: number, fromDate = '1970-01-01') { - await changeDateForSync(videoChannelSyncId, fromDate) - - await servers[0].debug.sendCommand({ - body: { - command: 'process-video-channel-sync-latest' - } - }) - - await waitJobs(servers) - } - - before(async function () { - this.timeout(240_000) - - startTestDate = new Date() - - servers = await createMultipleServers(2, getServerImportConfig(mode)) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultChannelAvatar(servers) - await setDefaultAccountAvatar(servers) - - await servers[0].config.enableChannelSync() - - { - userInfo.accessToken = await servers[0].users.generateUserAndToken(userInfo.username) - - const { videoChannels } = await servers[0].users.getMyInfo({ token: userInfo.accessToken }) - userInfo.channelId = videoChannels[0].id - } - - sqlCommands = servers.map(s => new SQLCommand(s)) - }) - - it('Should fetch the latest channel videos of a remote channel', async function () { - this.timeout(120_000) - - { - const { video } = await servers[0].imports.importVideo({ - attributes: { - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - targetUrl: FIXTURE_URLS.youtube - } - }) - - expect(video.name).to.equal('small video - youtube') - expect(video.waitTranscoding).to.be.true - - const { total } = await listAllVideosOfChannel('root_channel') - expect(total).to.equal(1) - } - - const { videoChannelSync } = await servers[0].channelSyncs.create({ - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - videoChannelId: servers[0].store.channel.id - } - }) - rootChannelSyncId = videoChannelSync.id - - await forceSyncAll(rootChannelSyncId) - - { - const { total, data } = await listAllVideosOfChannel('root_channel') - expect(total).to.equal(2) - expect(data[0].name).to.equal('test') - expect(data[0].waitTranscoding).to.be.true - } - }) - - it('Should add another synchronization', async function () { - const externalChannelUrl = FIXTURE_URLS.youtubeChannel + '?foo=bar' - - const { videoChannelSync } = await servers[0].channelSyncs.create({ - attributes: { - externalChannelUrl, - videoChannelId: servers[0].store.channel.id - } - }) - - expect(videoChannelSync.externalChannelUrl).to.equal(externalChannelUrl) - expect(videoChannelSync.channel.id).to.equal(servers[0].store.channel.id) - expect(videoChannelSync.channel.name).to.equal('root_channel') - expect(videoChannelSync.state.id).to.equal(VideoChannelSyncState.WAITING_FIRST_RUN) - expect(new Date(videoChannelSync.createdAt)).to.be.above(startTestDate).and.to.be.at.most(new Date()) - }) - - it('Should add a synchronization for another user', async function () { - const { videoChannelSync } = await servers[0].channelSyncs.create({ - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubeChannel + '?baz=qux', - videoChannelId: userInfo.channelId - }, - token: userInfo.accessToken - }) - userInfo.syncId = videoChannelSync.id - }) - - it('Should not import a channel if not asked', async function () { - await waitJobs(servers) - - const { data } = await servers[0].channelSyncs.listByAccount({ accountName: userInfo.username }) - - expect(data[0].state).to.contain({ - id: VideoChannelSyncState.WAITING_FIRST_RUN, - label: 'Waiting first run' - }) - }) - - it('Should only fetch the videos newer than the creation date', async function () { - this.timeout(120_000) - - await forceSyncAll(userInfo.syncId, '2019-03-01') - - const { data, total } = await listAllVideosOfChannel(userInfo.channelName) - - expect(total).to.equal(1) - expect(data[0].name).to.equal('test') - }) - - it('Should list channel synchronizations', async function () { - // Root - { - const { total, data } = await servers[0].channelSyncs.listByAccount({ accountName: 'root' }) - expect(total).to.equal(2) - - expect(data[0]).to.deep.contain({ - externalChannelUrl: FIXTURE_URLS.youtubeChannel, - state: { - id: VideoChannelSyncState.SYNCED, - label: 'Synchronized' - } - }) - - expect(new Date(data[0].lastSyncAt)).to.be.greaterThan(startTestDate) - - expect(data[0].channel).to.contain({ id: servers[0].store.channel.id }) - expect(data[1]).to.contain({ externalChannelUrl: FIXTURE_URLS.youtubeChannel + '?foo=bar' }) - } - - // User - { - const { total, data } = await servers[0].channelSyncs.listByAccount({ accountName: userInfo.username }) - expect(total).to.equal(1) - expect(data[0]).to.deep.contain({ - externalChannelUrl: FIXTURE_URLS.youtubeChannel + '?baz=qux', - state: { - id: VideoChannelSyncState.SYNCED, - label: 'Synchronized' - } - }) - } - }) - - it('Should list imports of a channel synchronization', async function () { - const { total, data } = await servers[0].imports.getMyVideoImports({ videoChannelSyncId: rootChannelSyncId }) - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - expect(data[0].video.name).to.equal('test') - }) - - it('Should remove user\'s channel synchronizations', async function () { - await servers[0].channelSyncs.delete({ channelSyncId: userInfo.syncId }) - - const { total } = await servers[0].channelSyncs.listByAccount({ accountName: userInfo.username }) - expect(total).to.equal(0) - }) - - // FIXME: youtube-dl/yt-dlp doesn't work when speicifying a port after the hostname - // it('Should import a remote PeerTube channel', async function () { - // this.timeout(240_000) - - // await servers[1].videos.quickUpload({ name: 'remote 1' }) - // await waitJobs(servers) - - // const { videoChannelSync } = await servers[0].channelSyncs.create({ - // attributes: { - // externalChannelUrl: servers[1].url + '/c/root_channel', - // videoChannelId: userInfo.channelId - // }, - // token: userInfo.accessToken - // }) - // await servers[0].channels.importVideos({ - // channelName: userInfo.channelName, - // externalChannelUrl: servers[1].url + '/c/root_channel', - // videoChannelSyncId: videoChannelSync.id, - // token: userInfo.accessToken - // }) - - // await waitJobs(servers) - - // const { data, total } = await servers[0].videos.listByChannel({ - // handle: userInfo.channelName, - // include: VideoInclude.NOT_PUBLISHED_STATE - // }) - - // expect(total).to.equal(2) - // expect(data[0].name).to.equal('remote 1') - // }) - - // it('Should keep synced a remote PeerTube channel', async function () { - // this.timeout(240_000) - - // await servers[1].videos.quickUpload({ name: 'remote 2' }) - // await waitJobs(servers) - - // await servers[0].debug.sendCommand({ - // body: { - // command: 'process-video-channel-sync-latest' - // } - // }) - - // await waitJobs(servers) - - // const { data, total } = await servers[0].videos.listByChannel({ - // handle: userInfo.channelName, - // include: VideoInclude.NOT_PUBLISHED_STATE - // }) - // expect(total).to.equal(2) - // expect(data[0].name).to.equal('remote 2') - // }) - - it('Should fetch the latest videos of a youtube playlist', async function () { - this.timeout(120_000) - - const { id: channelId } = await servers[0].channels.create({ - attributes: { - name: 'channel2' - } - }) - - const { videoChannelSync: { id: videoChannelSyncId } } = await servers[0].channelSyncs.create({ - attributes: { - externalChannelUrl: FIXTURE_URLS.youtubePlaylist, - videoChannelId: channelId - } - }) - - await forceSyncAll(videoChannelSyncId) - - { - - const { total, data } = await listAllVideosOfChannel('channel2') - expect(total).to.equal(2) - expect(data[0].name).to.equal('test') - expect(data[1].name).to.equal('small video - youtube') - } - }) - - after(async function () { - for (const sqlCommand of sqlCommands) { - await sqlCommand.cleanup() - } - - await cleanupTests(servers) - }) - }) - } - - // FIXME: suite is broken with youtube-dl - // runSuite('youtube-dl') - runSuite('yt-dlp') -}) diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts deleted file mode 100644 index f7cf84618..000000000 --- a/server/tests/api/videos/video-channels.ts +++ /dev/null @@ -1,555 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { basename } from 'path' -import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants' -import { SQLCommand, testFileExistsOrNot, testImage } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { ActorImageType, User, VideoChannel } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -async function findChannel (server: PeerTubeServer, channelId: number) { - const body = await server.channels.list({ sort: '-name' }) - - return body.data.find(c => c.id === channelId) -} - -describe('Test video channels', function () { - let servers: PeerTubeServer[] - let sqlCommands: SQLCommand[] = [] - - let userInfo: User - let secondVideoChannelId: number - let totoChannel: number - let videoUUID: string - let accountName: string - let secondUserChannelName: string - - const avatarPaths: { [ port: number ]: string } = {} - const bannerPaths: { [ port: number ]: string } = {} - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - await doubleFollow(servers[0], servers[1]) - - sqlCommands = servers.map(s => new SQLCommand(s)) - }) - - it('Should have one video channel (created with root)', async () => { - const body = await servers[0].channels.list({ start: 0, count: 2 }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - }) - - it('Should create another video channel', async function () { - this.timeout(30000) - - { - const videoChannel = { - name: 'second_video_channel', - displayName: 'second video channel', - description: 'super video channel description', - support: 'super video channel support text' - } - const created = await servers[0].channels.create({ attributes: videoChannel }) - secondVideoChannelId = created.id - } - - // The channel is 1 is propagated to servers 2 - { - const attributes = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } - const { uuid } = await servers[0].videos.upload({ attributes }) - videoUUID = uuid - } - - await waitJobs(servers) - }) - - it('Should have two video channels when getting my information', async () => { - userInfo = await servers[0].users.getMyInfo() - - expect(userInfo.videoChannels).to.be.an('array') - expect(userInfo.videoChannels).to.have.lengthOf(2) - - const videoChannels = userInfo.videoChannels - expect(videoChannels[0].name).to.equal('root_channel') - expect(videoChannels[0].displayName).to.equal('Main root channel') - - expect(videoChannels[1].name).to.equal('second_video_channel') - expect(videoChannels[1].displayName).to.equal('second video channel') - expect(videoChannels[1].description).to.equal('super video channel description') - expect(videoChannels[1].support).to.equal('super video channel support text') - - accountName = userInfo.account.name + '@' + userInfo.account.host - }) - - it('Should have two video channels when getting account channels on server 1', async function () { - const body = await servers[0].channels.listByAccount({ accountName }) - expect(body.total).to.equal(2) - - const videoChannels = body.data - - expect(videoChannels).to.be.an('array') - expect(videoChannels).to.have.lengthOf(2) - - expect(videoChannels[0].name).to.equal('root_channel') - expect(videoChannels[0].displayName).to.equal('Main root channel') - - expect(videoChannels[1].name).to.equal('second_video_channel') - expect(videoChannels[1].displayName).to.equal('second video channel') - expect(videoChannels[1].description).to.equal('super video channel description') - expect(videoChannels[1].support).to.equal('super video channel support text') - }) - - it('Should paginate and sort account channels', async function () { - { - const body = await servers[0].channels.listByAccount({ - accountName, - start: 0, - count: 1, - sort: 'createdAt' - }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(1) - - const videoChannel: VideoChannel = body.data[0] - expect(videoChannel.name).to.equal('root_channel') - } - - { - const body = await servers[0].channels.listByAccount({ - accountName, - start: 0, - count: 1, - sort: '-createdAt' - }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('second_video_channel') - } - - { - const body = await servers[0].channels.listByAccount({ - accountName, - start: 1, - count: 1, - sort: '-createdAt' - }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('root_channel') - } - }) - - it('Should have one video channel when getting account channels on server 2', async function () { - const body = await servers[1].channels.listByAccount({ accountName }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - - const videoChannel = body.data[0] - expect(videoChannel.name).to.equal('second_video_channel') - expect(videoChannel.displayName).to.equal('second video channel') - expect(videoChannel.description).to.equal('super video channel description') - expect(videoChannel.support).to.equal('super video channel support text') - }) - - it('Should list video channels', async function () { - const body = await servers[0].channels.list({ start: 1, count: 1, sort: '-name' }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('root_channel') - expect(body.data[0].displayName).to.equal('Main root channel') - }) - - it('Should update video channel', async function () { - this.timeout(15000) - - const videoChannelAttributes = { - displayName: 'video channel updated', - description: 'video channel description updated', - support: 'support updated' - } - - await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes }) - - await waitJobs(servers) - }) - - it('Should have video channel updated', async function () { - for (const server of servers) { - const body = await server.channels.list({ start: 0, count: 1, sort: '-name' }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - - expect(body.data[0].name).to.equal('second_video_channel') - expect(body.data[0].displayName).to.equal('video channel updated') - expect(body.data[0].description).to.equal('video channel description updated') - expect(body.data[0].support).to.equal('support updated') - } - }) - - it('Should not have updated the video support field', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.support).to.equal('video support field') - } - }) - - it('Should update another accounts video channel', async function () { - this.timeout(15000) - - const result = await servers[0].users.generate('second_user') - secondUserChannelName = result.userChannelName - - await servers[0].videos.quickUpload({ name: 'video', token: result.token }) - - const videoChannelAttributes = { - displayName: 'video channel updated', - description: 'video channel description updated', - support: 'support updated' - } - - await servers[0].channels.update({ channelName: secondUserChannelName, attributes: videoChannelAttributes }) - - await waitJobs(servers) - }) - - it('Should have another accounts video channel updated', async function () { - for (const server of servers) { - const body = await server.channels.get({ channelName: `${secondUserChannelName}@${servers[0].host}` }) - - expect(body.displayName).to.equal('video channel updated') - expect(body.description).to.equal('video channel description updated') - expect(body.support).to.equal('support updated') - } - }) - - it('Should update the channel support field and update videos too', async function () { - this.timeout(35000) - - const videoChannelAttributes = { - support: 'video channel support text updated', - bulkVideosSupportUpdate: true - } - - await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - expect(video.support).to.equal(videoChannelAttributes.support) - } - }) - - it('Should update video channel avatar', async function () { - this.timeout(15000) - - const fixture = 'avatar.png' - - await servers[0].channels.updateImage({ - channelName: 'second_video_channel', - fixture, - type: 'avatar' - }) - - await waitJobs(servers) - - for (let i = 0; i < servers.length; i++) { - const server = servers[i] - - const videoChannel = await findChannel(server, secondVideoChannelId) - const expectedSizes = ACTOR_IMAGES_SIZE[ActorImageType.AVATAR] - - expect(videoChannel.avatars.length).to.equal(expectedSizes.length, 'Expected avatars to be generated in all sizes') - - for (const avatar of videoChannel.avatars) { - avatarPaths[server.port] = avatar.path - await testImage(server.url, `avatar-resized-${avatar.width}x${avatar.width}`, avatarPaths[server.port], '.png') - await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), true) - - const row = await sqlCommands[i].getActorImage(basename(avatarPaths[server.port])) - - expect(expectedSizes.some(({ height, width }) => row.height === height && row.width === width)).to.equal(true) - } - } - }) - - it('Should update video channel banner', async function () { - this.timeout(15000) - - const fixture = 'banner.jpg' - - await servers[0].channels.updateImage({ - channelName: 'second_video_channel', - fixture, - type: 'banner' - }) - - await waitJobs(servers) - - for (let i = 0; i < servers.length; i++) { - const server = servers[i] - - const videoChannel = await server.channels.get({ channelName: 'second_video_channel@' + servers[0].host }) - - bannerPaths[server.port] = videoChannel.banners[0].path - await testImage(server.url, 'banner-resized', bannerPaths[server.port]) - await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), true) - - const row = await sqlCommands[i].getActorImage(basename(bannerPaths[server.port])) - expect(row.height).to.equal(ACTOR_IMAGES_SIZE[ActorImageType.BANNER][0].height) - expect(row.width).to.equal(ACTOR_IMAGES_SIZE[ActorImageType.BANNER][0].width) - } - }) - - it('Should still correctly list channels', async function () { - { - const body = await servers[0].channels.list({ start: 1, count: 1, sort: 'createdAt' }) - - expect(body.total).to.equal(3) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('second_video_channel') - } - - { - const body = await servers[0].channels.listByAccount({ accountName, start: 1, count: 1, sort: 'createdAt' }) - - expect(body.total).to.equal(2) - expect(body.data).to.have.lengthOf(1) - expect(body.data[0].name).to.equal('second_video_channel') - } - }) - - it('Should delete the video channel avatar', async function () { - this.timeout(15000) - await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'avatar' }) - - await waitJobs(servers) - - for (const server of servers) { - const videoChannel = await findChannel(server, secondVideoChannelId) - await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), false) - - expect(videoChannel.avatars).to.be.empty - } - }) - - it('Should delete the video channel banner', async function () { - this.timeout(15000) - - await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'banner' }) - - await waitJobs(servers) - - for (const server of servers) { - const videoChannel = await findChannel(server, secondVideoChannelId) - await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), false) - - expect(videoChannel.banners).to.be.empty - } - }) - - it('Should list the second video channel videos', async function () { - for (const server of servers) { - const channelURI = 'second_video_channel@' + servers[0].host - const { total, data } = await server.videos.listByChannel({ handle: channelURI }) - - expect(total).to.equal(1) - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('my video name') - } - }) - - it('Should change the video channel of a video', async function () { - await servers[0].videos.update({ id: videoUUID, attributes: { channelId: servers[0].store.channel.id } }) - - await waitJobs(servers) - }) - - it('Should list the first video channel videos', async function () { - for (const server of servers) { - { - const secondChannelURI = 'second_video_channel@' + servers[0].host - const { total } = await server.videos.listByChannel({ handle: secondChannelURI }) - expect(total).to.equal(0) - } - - { - const channelURI = 'root_channel@' + servers[0].host - const { total, data } = await server.videos.listByChannel({ handle: channelURI }) - expect(total).to.equal(1) - - expect(data).to.be.an('array') - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('my video name') - } - } - }) - - it('Should delete video channel', async function () { - await servers[0].channels.delete({ channelName: 'second_video_channel' }) - }) - - it('Should have video channel deleted', async function () { - const body = await servers[0].channels.list({ start: 0, count: 10, sort: 'createdAt' }) - - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - expect(body.data[0].displayName).to.equal('Main root channel') - expect(body.data[1].displayName).to.equal('video channel updated') - }) - - it('Should create the main channel with a suffix if there is a conflict', async function () { - { - const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } - const created = await servers[0].channels.create({ attributes: videoChannel }) - totoChannel = created.id - } - - { - await servers[0].users.create({ username: 'toto', password: 'password' }) - const accessToken = await servers[0].login.getAccessToken({ username: 'toto', password: 'password' }) - - const { videoChannels } = await servers[0].users.getMyInfo({ token: accessToken }) - expect(videoChannels[0].name).to.equal('toto_channel-1') - } - }) - - it('Should report correct channel views per days', async function () { - { - const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) - - for (const channel of data) { - expect(channel).to.haveOwnProperty('viewsPerDay') - expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today - - for (const v of channel.viewsPerDay) { - expect(v.date).to.be.an('string') - expect(v.views).to.equal(0) - } - } - } - - { - // video has been posted on channel servers[0].store.videoChannel.id since last update - await servers[0].views.simulateView({ id: videoUUID, xForwardedFor: '0.0.0.1,127.0.0.1' }) - await servers[0].views.simulateView({ id: videoUUID, xForwardedFor: '0.0.0.2,127.0.0.1' }) - - // Wait the repeatable job - await wait(8000) - - const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) - const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id) - expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2) - } - }) - - it('Should report correct total views count', async function () { - // check if there's the property - { - const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) - - for (const channel of data) { - expect(channel).to.haveOwnProperty('totalViews') - expect(channel.totalViews).to.be.a('number') - } - } - - // Check if the totalViews count can be updated - { - const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) - const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id) - expect(channelWithView.totalViews).to.equal(2) - } - }) - - it('Should report correct videos count', async function () { - const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) - - const totoChannel = data.find(c => c.name === 'toto_channel') - const rootChannel = data.find(c => c.name === 'root_channel') - - expect(rootChannel.videosCount).to.equal(1) - expect(totoChannel.videosCount).to.equal(0) - }) - - it('Should search among account video channels', async function () { - { - const body = await servers[0].channels.listByAccount({ accountName, search: 'root' }) - expect(body.total).to.equal(1) - - const channels = body.data - expect(channels).to.have.lengthOf(1) - } - - { - const body = await servers[0].channels.listByAccount({ accountName, search: 'does not exist' }) - expect(body.total).to.equal(0) - - const channels = body.data - expect(channels).to.have.lengthOf(0) - } - }) - - it('Should list channels by updatedAt desc if a video has been uploaded', async function () { - this.timeout(30000) - - await servers[0].videos.upload({ attributes: { channelId: totoChannel } }) - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' }) - - expect(data[0].name).to.equal('toto_channel') - expect(data[1].name).to.equal('root_channel') - } - - await servers[0].videos.upload({ attributes: { channelId: servers[0].store.channel.id } }) - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' }) - - expect(data[0].name).to.equal('root_channel') - expect(data[1].name).to.equal('toto_channel') - } - }) - - after(async function () { - for (const sqlCommand of sqlCommands) { - await sqlCommand.cleanup() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts deleted file mode 100644 index b7d5624a6..000000000 --- a/server/tests/api/videos/video-comments.ts +++ /dev/null @@ -1,335 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { dateIsValid, testImage } from '@server/tests/shared' -import { - cleanupTests, - CommentsCommand, - createSingleServer, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar -} from '@shared/server-commands' - -describe('Test video comments', function () { - let server: PeerTubeServer - let videoId: number - let videoUUID: string - let threadId: number - let replyToDeleteId: number - - let userAccessTokenServer1: string - - let command: CommentsCommand - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - const { id, uuid } = await server.videos.upload() - videoUUID = uuid - videoId = id - - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(server) - - userAccessTokenServer1 = await server.users.generateUserAndToken('user1') - await setDefaultChannelAvatar(server, 'user1_channel') - await setDefaultAccountAvatar(server, userAccessTokenServer1) - - command = server.comments - }) - - describe('User comments', function () { - - it('Should not have threads on this video', async function () { - const body = await command.listThreads({ videoId: videoUUID }) - - expect(body.total).to.equal(0) - expect(body.totalNotDeletedComments).to.equal(0) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(0) - }) - - it('Should create a thread in this video', async function () { - const text = 'my super first comment' - - const comment = await command.createThread({ videoId: videoUUID, text }) - - expect(comment.inReplyToCommentId).to.be.null - expect(comment.text).equal('my super first comment') - expect(comment.videoId).to.equal(videoId) - expect(comment.id).to.equal(comment.threadId) - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(server.host) - expect(comment.account.url).to.equal(server.url + '/accounts/root') - expect(comment.totalReplies).to.equal(0) - expect(comment.totalRepliesFromVideoAuthor).to.equal(0) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - }) - - it('Should list threads of this video', async function () { - const body = await command.listThreads({ videoId: videoUUID }) - - expect(body.total).to.equal(1) - expect(body.totalNotDeletedComments).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - - const comment = body.data[0] - expect(comment.inReplyToCommentId).to.be.null - expect(comment.text).equal('my super first comment') - expect(comment.videoId).to.equal(videoId) - expect(comment.id).to.equal(comment.threadId) - expect(comment.account.name).to.equal('root') - expect(comment.account.host).to.equal(server.host) - - for (const avatar of comment.account.avatars) { - await testImage(server.url, `avatar-resized-${avatar.width}x${avatar.width}`, avatar.path, '.png') - } - - expect(comment.totalReplies).to.equal(0) - expect(comment.totalRepliesFromVideoAuthor).to.equal(0) - expect(dateIsValid(comment.createdAt as string)).to.be.true - expect(dateIsValid(comment.updatedAt as string)).to.be.true - - threadId = comment.threadId - }) - - it('Should get all the thread created', async function () { - const body = await command.getThread({ videoId: videoUUID, threadId }) - - const rootComment = body.comment - expect(rootComment.inReplyToCommentId).to.be.null - expect(rootComment.text).equal('my super first comment') - expect(rootComment.videoId).to.equal(videoId) - expect(dateIsValid(rootComment.createdAt as string)).to.be.true - expect(dateIsValid(rootComment.updatedAt as string)).to.be.true - }) - - it('Should create multiple replies in this thread', async function () { - const text1 = 'my super answer to thread 1' - const created = await command.addReply({ videoId, toCommentId: threadId, text: text1 }) - const childCommentId = created.id - - const text2 = 'my super answer to answer of thread 1' - await command.addReply({ videoId, toCommentId: childCommentId, text: text2 }) - - const text3 = 'my second answer to thread 1' - await command.addReply({ videoId, toCommentId: threadId, text: text3 }) - }) - - it('Should get correctly the replies', async function () { - const tree = await command.getThread({ videoId: videoUUID, threadId }) - - expect(tree.comment.text).equal('my super first comment') - expect(tree.children).to.have.lengthOf(2) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('my super answer to thread 1') - expect(firstChild.children).to.have.lengthOf(1) - - const childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') - expect(childOfFirstChild.children).to.have.lengthOf(0) - - const secondChild = tree.children[1] - expect(secondChild.comment.text).to.equal('my second answer to thread 1') - expect(secondChild.children).to.have.lengthOf(0) - - replyToDeleteId = secondChild.comment.id - }) - - it('Should create other threads', async function () { - const text1 = 'super thread 2' - await command.createThread({ videoId: videoUUID, text: text1 }) - - const text2 = 'super thread 3' - await command.createThread({ videoId: videoUUID, text: text2 }) - }) - - it('Should list the threads', async function () { - const body = await command.listThreads({ videoId: videoUUID, sort: 'createdAt' }) - - expect(body.total).to.equal(3) - expect(body.totalNotDeletedComments).to.equal(6) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(3) - - expect(body.data[0].text).to.equal('my super first comment') - expect(body.data[0].totalReplies).to.equal(3) - expect(body.data[1].text).to.equal('super thread 2') - expect(body.data[1].totalReplies).to.equal(0) - expect(body.data[2].text).to.equal('super thread 3') - expect(body.data[2].totalReplies).to.equal(0) - }) - - it('Should list the and sort them by total replies', async function () { - const body = await command.listThreads({ videoId: videoUUID, sort: 'totalReplies' }) - - expect(body.data[2].text).to.equal('my super first comment') - expect(body.data[2].totalReplies).to.equal(3) - }) - - it('Should delete a reply', async function () { - await command.delete({ videoId, commentId: replyToDeleteId }) - - { - const body = await command.listThreads({ videoId: videoUUID, sort: 'createdAt' }) - - expect(body.total).to.equal(3) - expect(body.totalNotDeletedComments).to.equal(5) - } - - { - const tree = await command.getThread({ videoId: videoUUID, threadId }) - - expect(tree.comment.text).equal('my super first comment') - expect(tree.children).to.have.lengthOf(2) - - const firstChild = tree.children[0] - expect(firstChild.comment.text).to.equal('my super answer to thread 1') - expect(firstChild.children).to.have.lengthOf(1) - - const childOfFirstChild = firstChild.children[0] - expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') - expect(childOfFirstChild.children).to.have.lengthOf(0) - - const deletedChildOfFirstChild = tree.children[1] - expect(deletedChildOfFirstChild.comment.text).to.equal('') - expect(deletedChildOfFirstChild.comment.isDeleted).to.be.true - expect(deletedChildOfFirstChild.comment.deletedAt).to.not.be.null - expect(deletedChildOfFirstChild.comment.account).to.be.null - expect(deletedChildOfFirstChild.children).to.have.lengthOf(0) - } - }) - - it('Should delete a complete thread', async function () { - await command.delete({ videoId, commentId: threadId }) - - const body = await command.listThreads({ videoId: videoUUID, sort: 'createdAt' }) - expect(body.total).to.equal(3) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(3) - - expect(body.data[0].text).to.equal('') - expect(body.data[0].isDeleted).to.be.true - expect(body.data[0].deletedAt).to.not.be.null - expect(body.data[0].account).to.be.null - expect(body.data[0].totalReplies).to.equal(2) - expect(body.data[1].text).to.equal('super thread 2') - expect(body.data[1].totalReplies).to.equal(0) - expect(body.data[2].text).to.equal('super thread 3') - expect(body.data[2].totalReplies).to.equal(0) - }) - - it('Should count replies from the video author correctly', async function () { - await command.createThread({ videoId: videoUUID, text: 'my super first comment' }) - - const { data } = await command.listThreads({ videoId: videoUUID }) - const threadId2 = data[0].threadId - - const text2 = 'a first answer to thread 4 by a third party' - await command.addReply({ token: userAccessTokenServer1, videoId, toCommentId: threadId2, text: text2 }) - - const text3 = 'my second answer to thread 4' - await command.addReply({ videoId, toCommentId: threadId2, text: text3 }) - - const tree = await command.getThread({ videoId: videoUUID, threadId: threadId2 }) - expect(tree.comment.totalRepliesFromVideoAuthor).to.equal(1) - expect(tree.comment.totalReplies).to.equal(2) - }) - }) - - describe('All instance comments', function () { - - it('Should list instance comments as admin', async function () { - { - const { data, total } = await command.listForAdmin({ start: 0, count: 1 }) - - expect(total).to.equal(7) - expect(data).to.have.lengthOf(1) - expect(data[0].text).to.equal('my second answer to thread 4') - expect(data[0].account.name).to.equal('root') - expect(data[0].account.displayName).to.equal('root') - expect(data[0].account.avatars).to.have.lengthOf(2) - } - - { - const { data, total } = await command.listForAdmin({ start: 1, count: 2 }) - - expect(total).to.equal(7) - expect(data).to.have.lengthOf(2) - - expect(data[0].account.avatars).to.have.lengthOf(2) - expect(data[1].account.avatars).to.have.lengthOf(2) - } - }) - - it('Should filter instance comments by isLocal', async function () { - const { total, data } = await command.listForAdmin({ isLocal: false }) - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - }) - - it('Should filter instance comments by onLocalVideo', async function () { - { - const { total, data } = await command.listForAdmin({ onLocalVideo: false }) - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - } - - { - const { total, data } = await command.listForAdmin({ onLocalVideo: true }) - - expect(data).to.not.have.lengthOf(0) - expect(total).to.not.equal(0) - } - }) - - it('Should search instance comments by account', async function () { - const { total, data } = await command.listForAdmin({ searchAccount: 'user' }) - - expect(data).to.have.lengthOf(1) - expect(total).to.equal(1) - - expect(data[0].text).to.equal('a first answer to thread 4 by a third party') - }) - - it('Should search instance comments by video', async function () { - { - const { total, data } = await command.listForAdmin({ searchVideo: 'video' }) - - expect(data).to.have.lengthOf(7) - expect(total).to.equal(7) - } - - { - const { total, data } = await command.listForAdmin({ searchVideo: 'hello' }) - - expect(data).to.have.lengthOf(0) - expect(total).to.equal(0) - } - }) - - it('Should search instance comments', async function () { - const { total, data } = await command.listForAdmin({ search: 'super thread 3' }) - - expect(total).to.equal(1) - - expect(data).to.have.lengthOf(1) - expect(data[0].text).to.equal('super thread 3') - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts deleted file mode 100644 index 1f3d4adbb..000000000 --- a/server/tests/api/videos/video-description.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test video description', function () { - let servers: PeerTubeServer[] = [] - let videoUUID = '' - let videoId: number - - const longDescription = 'my super description for server 1'.repeat(50) - - // 30 characters * 6 -> 240 characters - const truncatedDescription = 'my super description for server 1'.repeat(7) + 'my super descrip...' - - before(async function () { - this.timeout(40000) - - // Run servers - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - it('Should upload video with long description', async function () { - this.timeout(30000) - - const attributes = { - description: longDescription - } - await servers[0].videos.upload({ attributes }) - - await waitJobs(servers) - - const { data } = await servers[0].videos.list() - - videoId = data[0].id - videoUUID = data[0].uuid - }) - - it('Should have a truncated description on each server when listing videos', async function () { - for (const server of servers) { - const { data } = await server.videos.list() - const video = data.find(v => v.uuid === videoUUID) - - expect(video.description).to.equal(truncatedDescription) - expect(video.truncatedDescription).to.equal(truncatedDescription) - } - }) - - it('Should not have a truncated description on each server when getting videos', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.description).to.equal(longDescription) - expect(video.truncatedDescription).to.equal(truncatedDescription) - } - }) - - it('Should fetch long description on each server', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - const { description } = await server.videos.getDescription({ descriptionPath: video.descriptionPath }) - expect(description).to.equal(longDescription) - } - }) - - it('Should update with a short description', async function () { - const attributes = { - description: 'short description' - } - await servers[0].videos.update({ id: videoId, attributes }) - - await waitJobs(servers) - }) - - it('Should have a small description on each server', async function () { - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.description).to.equal('short description') - - const { description } = await server.videos.getDescription({ descriptionPath: video.descriptionPath }) - expect(description).to.equal('short description') - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-files.ts b/server/tests/api/videos/video-files.ts deleted file mode 100644 index 4f75cd106..000000000 --- a/server/tests/api/videos/video-files.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeRawRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test videos files', function () { - let servers: PeerTubeServer[] - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(150_000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - }) - - describe('When deleting all files', function () { - let validId1: string - let validId2: string - - before(async function () { - this.timeout(360_000) - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) - validId1 = uuid - } - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 2' }) - validId2 = uuid - } - - await waitJobs(servers) - }) - - it('Should delete web video files', async function () { - this.timeout(30_000) - - await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1 }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: validId1 }) - - expect(video.files).to.have.lengthOf(0) - expect(video.streamingPlaylists).to.have.lengthOf(1) - } - }) - - it('Should delete HLS files', async function () { - this.timeout(30_000) - - await servers[0].videos.removeHLSPlaylist({ videoId: validId2 }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: validId2 }) - - expect(video.files).to.have.length.above(0) - expect(video.streamingPlaylists).to.have.lengthOf(0) - } - }) - }) - - describe('When deleting a specific file', function () { - let webVideoId: string - let hlsId: string - - before(async function () { - this.timeout(120_000) - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'web-video' }) - webVideoId = uuid - } - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) - hlsId = uuid - } - - await waitJobs(servers) - }) - - it('Shoulde delete a web video file', async function () { - this.timeout(30_000) - - const video = await servers[0].videos.get({ id: webVideoId }) - const files = video.files - - await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: files[0].id }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: webVideoId }) - - expect(video.files).to.have.lengthOf(files.length - 1) - expect(video.files.find(f => f.id === files[0].id)).to.not.exist - } - }) - - it('Should delete all web video files', async function () { - this.timeout(30_000) - - const video = await servers[0].videos.get({ id: webVideoId }) - const files = video.files - - for (const file of files) { - await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: file.id }) - } - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: webVideoId }) - - expect(video.files).to.have.lengthOf(0) - } - }) - - it('Should delete a hls file', async function () { - this.timeout(30_000) - - const video = await servers[0].videos.get({ id: hlsId }) - const files = video.streamingPlaylists[0].files - const toDelete = files[0] - - await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: toDelete.id }) - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: hlsId }) - - expect(video.streamingPlaylists[0].files).to.have.lengthOf(files.length - 1) - expect(video.streamingPlaylists[0].files.find(f => f.id === toDelete.id)).to.not.exist - - const { text } = await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - - expect(text.includes(`-${toDelete.resolution.id}.m3u8`)).to.be.false - expect(text.includes(`-${video.streamingPlaylists[0].files[0].resolution.id}.m3u8`)).to.be.true - } - }) - - it('Should delete all hls files', async function () { - this.timeout(30_000) - - const video = await servers[0].videos.get({ id: hlsId }) - const files = video.streamingPlaylists[0].files - - for (const file of files) { - await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: file.id }) - } - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: hlsId }) - - expect(video.streamingPlaylists).to.have.lengthOf(0) - } - }) - - it('Should not delete last file of a video', async function () { - this.timeout(60_000) - - const webVideoOnly = await servers[0].videos.get({ id: hlsId }) - const hlsOnly = await servers[0].videos.get({ id: webVideoId }) - - for (let i = 0; i < 4; i++) { - await servers[0].videos.removeWebVideoFile({ videoId: webVideoOnly.id, fileId: webVideoOnly.files[i].id }) - await servers[0].videos.removeHLSFile({ videoId: hlsOnly.id, fileId: hlsOnly.streamingPlaylists[0].files[i].id }) - } - - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - await servers[0].videos.removeWebVideoFile({ videoId: webVideoOnly.id, fileId: webVideoOnly.files[4].id, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: hlsOnly.id, fileId: hlsOnly.streamingPlaylists[0].files[4].id, expectedStatus }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts deleted file mode 100644 index b78b4f344..000000000 --- a/server/tests/api/videos/video-imports.ts +++ /dev/null @@ -1,631 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir, remove } from 'fs-extra' -import { join } from 'path' -import { FIXTURE_URLS, testCaptionFile, testImageGeneratedByFFmpeg } from '@server/tests/shared' -import { areHttpImportTestsDisabled } from '@shared/core-utils' -import { CustomConfig, HttpStatusCode, Video, VideoImportState, VideoPrivacy, VideoResolution, VideoState } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - createSingleServer, - doubleFollow, - getServerImportConfig, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' -import { DeepPartial } from '@shared/typescript-utils' - -async function checkVideosServer1 (server: PeerTubeServer, idHttp: string, idMagnet: string, idTorrent: string) { - const videoHttp = await server.videos.get({ id: idHttp }) - - expect(videoHttp.name).to.equal('small video - youtube') - expect(videoHttp.category.label).to.equal('News & Politics') - expect(videoHttp.licence.label).to.equal('Attribution') - expect(videoHttp.language.label).to.equal('Unknown') - expect(videoHttp.nsfw).to.be.false - expect(videoHttp.description).to.equal('this is a super description') - expect(videoHttp.tags).to.deep.equal([ 'tag1', 'tag2' ]) - expect(videoHttp.files).to.have.lengthOf(1) - - const originallyPublishedAt = new Date(videoHttp.originallyPublishedAt) - expect(originallyPublishedAt.getDate()).to.equal(14) - expect(originallyPublishedAt.getMonth()).to.equal(0) - expect(originallyPublishedAt.getFullYear()).to.equal(2019) - - const videoMagnet = await server.videos.get({ id: idMagnet }) - const videoTorrent = await server.videos.get({ id: idTorrent }) - - for (const video of [ videoMagnet, videoTorrent ]) { - expect(video.category.label).to.equal('Unknown') - expect(video.licence.label).to.equal('Unknown') - expect(video.language.label).to.equal('Unknown') - expect(video.nsfw).to.be.false - expect(video.description).to.equal('this is a super torrent description') - expect(video.tags).to.deep.equal([ 'tag_torrent1', 'tag_torrent2' ]) - expect(video.files).to.have.lengthOf(1) - } - - expect(videoTorrent.name).to.contain('你好 世界 720p.mp4') - expect(videoMagnet.name).to.contain('super peertube2 video') - - const bodyCaptions = await server.captions.list({ videoId: idHttp }) - expect(bodyCaptions.total).to.equal(2) -} - -async function checkVideoServer2 (server: PeerTubeServer, id: number | string) { - const video = await server.videos.get({ id }) - - expect(video.name).to.equal('my super name') - expect(video.category.label).to.equal('Entertainment') - expect(video.licence.label).to.equal('Public Domain Dedication') - expect(video.language.label).to.equal('English') - expect(video.nsfw).to.be.false - expect(video.description).to.equal('my super description') - expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ]) - - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', video.thumbnailPath) - - expect(video.files).to.have.lengthOf(1) - - const bodyCaptions = await server.captions.list({ videoId: id }) - expect(bodyCaptions.total).to.equal(2) -} - -describe('Test video imports', function () { - - if (areHttpImportTestsDisabled()) return - - function runSuite (mode: 'youtube-dl' | 'yt-dlp') { - - describe('Import ' + mode, function () { - let servers: PeerTubeServer[] = [] - - before(async function () { - this.timeout(60_000) - - servers = await createMultipleServers(2, getServerImportConfig(mode)) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - for (const server of servers) { - await server.config.updateExistingSubConfig({ - newConfig: { - transcoding: { - alwaysTranscodeOriginalResolution: false - } - } - }) - } - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should import videos on server 1', async function () { - this.timeout(60_000) - - const baseAttributes = { - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - - { - const attributes = { ...baseAttributes, targetUrl: FIXTURE_URLS.youtube } - const { video } = await servers[0].imports.importVideo({ attributes }) - expect(video.name).to.equal('small video - youtube') - - { - expect(video.thumbnailPath).to.match(new RegExp(`^/lazy-static/thumbnails/.+.jpg$`)) - expect(video.previewPath).to.match(new RegExp(`^/lazy-static/previews/.+.jpg$`)) - - const suffix = mode === 'yt-dlp' - ? '_yt_dlp' - : '' - - await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_thumbnail' + suffix, video.thumbnailPath) - await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_preview' + suffix, video.previewPath) - } - - const bodyCaptions = await servers[0].captions.list({ videoId: video.id }) - const videoCaptions = bodyCaptions.data - expect(videoCaptions).to.have.lengthOf(2) - - { - const enCaption = videoCaptions.find(caption => caption.language.id === 'en') - expect(enCaption).to.exist - expect(enCaption.language.label).to.equal('English') - expect(enCaption.captionPath).to.match(new RegExp(`^/lazy-static/video-captions/.+-en.vtt$`)) - - const regex = `WEBVTT[ \n]+Kind: captions[ \n]+` + - `(Language: en[ \n]+)?` + - `00:00:01.600 --> 00:00:04.200( position:\\d+% line:\\d+%)?[ \n]+English \\(US\\)[ \n]+` + - `00:00:05.900 --> 00:00:07.999( position:\\d+% line:\\d+%)?[ \n]+This is a subtitle in American English[ \n]+` + - `00:00:10.000 --> 00:00:14.000( position:\\d+% line:\\d+%)?[ \n]+Adding subtitles is very easy to do` - await testCaptionFile(servers[0].url, enCaption.captionPath, new RegExp(regex)) - } - - { - const frCaption = videoCaptions.find(caption => caption.language.id === 'fr') - expect(frCaption).to.exist - expect(frCaption.language.label).to.equal('French') - expect(frCaption.captionPath).to.match(new RegExp(`^/lazy-static/video-captions/.+-fr.vtt`)) - - const regex = `WEBVTT[ \n]+Kind: captions[ \n]+` + - `(Language: fr[ \n]+)?` + - `00:00:01.600 --> 00:00:04.200( position:\\d+% line:\\d+%)?[ \n]+Français \\(FR\\)[ \n]+` + - `00:00:05.900 --> 00:00:07.999( position:\\d+% line:\\d+%)?[ \n]+C'est un sous-titre français[ \n]+` + - `00:00:10.000 --> 00:00:14.000( position:\\d+% line:\\d+%)?[ \n]+Ajouter un sous-titre est vraiment facile` - - await testCaptionFile(servers[0].url, frCaption.captionPath, new RegExp(regex)) - } - } - - { - const attributes = { - ...baseAttributes, - magnetUri: FIXTURE_URLS.magnet, - description: 'this is a super torrent description', - tags: [ 'tag_torrent1', 'tag_torrent2' ] - } - const { video } = await servers[0].imports.importVideo({ attributes }) - expect(video.name).to.equal('super peertube2 video') - } - - { - const attributes = { - ...baseAttributes, - torrentfile: 'video-720p.torrent' as any, - description: 'this is a super torrent description', - tags: [ 'tag_torrent1', 'tag_torrent2' ] - } - const { video } = await servers[0].imports.importVideo({ attributes }) - expect(video.name).to.equal('你好 世界 720p.mp4') - } - }) - - it('Should list the videos to import in my videos on server 1', async function () { - const { total, data } = await servers[0].videos.listMyVideos({ sort: 'createdAt' }) - - expect(total).to.equal(3) - - expect(data).to.have.lengthOf(3) - expect(data[0].name).to.equal('small video - youtube') - expect(data[1].name).to.equal('super peertube2 video') - expect(data[2].name).to.equal('你好 世界 720p.mp4') - }) - - it('Should list the videos to import in my imports on server 1', async function () { - const { total, data: videoImports } = await servers[0].imports.getMyVideoImports({ sort: '-createdAt' }) - expect(total).to.equal(3) - - expect(videoImports).to.have.lengthOf(3) - - expect(videoImports[2].targetUrl).to.equal(FIXTURE_URLS.youtube) - expect(videoImports[2].magnetUri).to.be.null - expect(videoImports[2].torrentName).to.be.null - expect(videoImports[2].video.name).to.equal('small video - youtube') - - expect(videoImports[1].targetUrl).to.be.null - expect(videoImports[1].magnetUri).to.equal(FIXTURE_URLS.magnet) - expect(videoImports[1].torrentName).to.be.null - expect(videoImports[1].video.name).to.equal('super peertube2 video') - - expect(videoImports[0].targetUrl).to.be.null - expect(videoImports[0].magnetUri).to.be.null - expect(videoImports[0].torrentName).to.equal('video-720p.torrent') - expect(videoImports[0].video.name).to.equal('你好 世界 720p.mp4') - }) - - it('Should filter my imports on target URL', async function () { - const { total, data: videoImports } = await servers[0].imports.getMyVideoImports({ targetUrl: FIXTURE_URLS.youtube }) - expect(total).to.equal(1) - expect(videoImports).to.have.lengthOf(1) - - expect(videoImports[0].targetUrl).to.equal(FIXTURE_URLS.youtube) - }) - - it('Should search in my imports', async function () { - const { total, data: videoImports } = await servers[0].imports.getMyVideoImports({ search: 'peertube2' }) - expect(total).to.equal(1) - expect(videoImports).to.have.lengthOf(1) - - expect(videoImports[0].magnetUri).to.equal(FIXTURE_URLS.magnet) - expect(videoImports[0].video.name).to.equal('super peertube2 video') - }) - - it('Should have the video listed on the two instances', async function () { - this.timeout(120_000) - - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - - const [ videoHttp, videoMagnet, videoTorrent ] = data - await checkVideosServer1(server, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) - } - }) - - it('Should import a video on server 2 with some fields', async function () { - this.timeout(60_000) - - const { video } = await servers[1].imports.importVideo({ - attributes: { - targetUrl: FIXTURE_URLS.youtube, - channelId: servers[1].store.channel.id, - privacy: VideoPrivacy.PUBLIC, - category: 10, - licence: 7, - language: 'en', - name: 'my super name', - description: 'my super description', - tags: [ 'supertag1', 'supertag2' ], - thumbnailfile: 'custom-thumbnail.jpg' - } - }) - expect(video.name).to.equal('my super name') - }) - - it('Should have the videos listed on the two instances', async function () { - this.timeout(120_000) - - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - expect(total).to.equal(4) - expect(data).to.have.lengthOf(4) - - await checkVideoServer2(server, data[0].uuid) - - const [ , videoHttp, videoMagnet, videoTorrent ] = data - await checkVideosServer1(server, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) - } - }) - - it('Should import a video that will be transcoded', async function () { - this.timeout(240_000) - - const attributes = { - name: 'transcoded video', - magnetUri: FIXTURE_URLS.magnet, - channelId: servers[1].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { video } = await servers[1].imports.importVideo({ attributes }) - const videoUUID = video.uuid - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.name).to.equal('transcoded video') - expect(video.files).to.have.lengthOf(4) - } - }) - - it('Should import no HDR version on a HDR video', async function () { - this.timeout(300_000) - - const config: DeepPartial = { - transcoding: { - enabled: true, - resolutions: { - '0p': false, - '144p': true, - '240p': true, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, // the resulting resolution shouldn't be higher than this, and not vp9.2/av01 - '1440p': false, - '2160p': false - }, - webVideos: { enabled: true }, - hls: { enabled: false } - } - } - await servers[0].config.updateExistingSubConfig({ newConfig: config }) - - const attributes = { - name: 'hdr video', - targetUrl: FIXTURE_URLS.youtubeHDR, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { video: videoImported } = await servers[0].imports.importVideo({ attributes }) - const videoUUID = videoImported.uuid - - await waitJobs(servers) - - // test resolution - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.name).to.equal('hdr video') - const maxResolution = Math.max.apply(Math, video.files.map(function (o) { return o.resolution.id })) - expect(maxResolution, 'expected max resolution not met').to.equals(VideoResolution.H_240P) - }) - - it('Should not import resolution higher than enabled transcoding resolution', async function () { - this.timeout(300_000) - - const config: DeepPartial = { - transcoding: { - enabled: true, - resolutions: { - '0p': false, - '144p': true, - '240p': false, - '360p': false, - '480p': false, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - alwaysTranscodeOriginalResolution: false - } - } - await servers[0].config.updateExistingSubConfig({ newConfig: config }) - - const attributes = { - name: 'small resolution video', - targetUrl: FIXTURE_URLS.youtube, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { video: videoImported } = await servers[0].imports.importVideo({ attributes }) - const videoUUID = videoImported.uuid - - await waitJobs(servers) - - // test resolution - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.name).to.equal('small resolution video') - expect(video.files).to.have.lengthOf(1) - expect(video.files[0].resolution.id).to.equal(144) - }) - - it('Should import resolution higher than enabled transcoding resolution', async function () { - this.timeout(300_000) - - const config: DeepPartial = { - transcoding: { - alwaysTranscodeOriginalResolution: true - } - } - await servers[0].config.updateExistingSubConfig({ newConfig: config }) - - const attributes = { - name: 'bigger resolution video', - targetUrl: FIXTURE_URLS.youtube, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { video: videoImported } = await servers[0].imports.importVideo({ attributes }) - const videoUUID = videoImported.uuid - - await waitJobs(servers) - - // test resolution - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.name).to.equal('bigger resolution video') - - expect(video.files).to.have.lengthOf(2) - expect(video.files.find(f => f.resolution.id === 240)).to.exist - expect(video.files.find(f => f.resolution.id === 144)).to.exist - }) - - it('Should import a peertube video', async function () { - this.timeout(120_000) - - const toTest = [ FIXTURE_URLS.peertube_long ] - - // TODO: include peertube_short when https://github.com/ytdl-org/youtube-dl/pull/29475 is merged - if (mode === 'yt-dlp') { - toTest.push(FIXTURE_URLS.peertube_short) - } - - for (const targetUrl of toTest) { - await servers[0].config.disableTranscoding() - - const attributes = { - targetUrl, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { video } = await servers[0].imports.importVideo({ attributes }) - const videoUUID = video.uuid - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.name).to.equal('E2E tests') - - const { data: captions } = await server.captions.list({ videoId: videoUUID }) - expect(captions).to.have.lengthOf(1) - expect(captions[0].language.id).to.equal('fr') - - const str = `WEBVTT FILE\r?\n\r?\n` + - `1\r?\n` + - `00:00:04.000 --> 00:00:09.000\r?\n` + - `January 1, 1994. The North American` - await testCaptionFile(server.url, captions[0].captionPath, new RegExp(str)) - } - } - }) - - after(async function () { - await cleanupTests(servers) - }) - }) - } - - // FIXME: youtube-dl seems broken - // runSuite('youtube-dl') - - runSuite('yt-dlp') - - describe('Delete/cancel an import', function () { - let server: PeerTubeServer - - let finishedImportId: number - let finishedVideo: Video - let pendingImportId: number - - async function importVideo (name: string) { - const attributes = { name, channelId: server.store.channel.id, targetUrl: FIXTURE_URLS.goodVideo } - const res = await server.imports.importVideo({ attributes }) - - return res.id - } - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - finishedImportId = await importVideo('finished') - await waitJobs([ server ]) - - await server.jobs.pauseJobQueue() - pendingImportId = await importVideo('pending') - - const { data } = await server.imports.getMyVideoImports() - expect(data).to.have.lengthOf(2) - - finishedVideo = data.find(i => i.id === finishedImportId).video - }) - - it('Should delete a video import', async function () { - await server.imports.delete({ importId: finishedImportId }) - - const { data } = await server.imports.getMyVideoImports() - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(pendingImportId) - expect(data[0].state.id).to.equal(VideoImportState.PENDING) - }) - - it('Should not have deleted the associated video', async function () { - const video = await server.videos.get({ id: finishedVideo.id, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - expect(video.name).to.equal('finished') - expect(video.state.id).to.equal(VideoState.PUBLISHED) - }) - - it('Should cancel a video import', async function () { - await server.imports.cancel({ importId: pendingImportId }) - - const { data } = await server.imports.getMyVideoImports() - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(pendingImportId) - expect(data[0].state.id).to.equal(VideoImportState.CANCELLED) - }) - - it('Should not have processed the cancelled video import', async function () { - this.timeout(60_000) - - await server.jobs.resumeJobQueue() - - await waitJobs([ server ]) - - const { data } = await server.imports.getMyVideoImports() - expect(data).to.have.lengthOf(1) - expect(data[0].id).to.equal(pendingImportId) - expect(data[0].state.id).to.equal(VideoImportState.CANCELLED) - expect(data[0].video.state.id).to.equal(VideoState.TO_IMPORT) - }) - - it('Should delete the cancelled video import', async function () { - await server.imports.delete({ importId: pendingImportId }) - const { data } = await server.imports.getMyVideoImports() - expect(data).to.have.lengthOf(0) - }) - - after(async function () { - await cleanupTests([ server ]) - }) - }) - - describe('Auto update', function () { - let server: PeerTubeServer - - function quickPeerTubeImport () { - const attributes = { - targetUrl: FIXTURE_URLS.peertube_long, - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - - return server.imports.importVideo({ attributes }) - } - - async function testBinaryUpdate (releaseUrl: string, releaseName: string) { - await remove(join(server.servers.buildDirectory('bin'), releaseName)) - - await server.kill() - await server.run({ - import: { - videos: { - http: { - youtube_dl_release: { - url: releaseUrl, - name: releaseName - } - } - } - } - }) - - await quickPeerTubeImport() - - const base = server.servers.buildDirectory('bin') - const content = await readdir(base) - const binaryPath = join(base, releaseName) - - expect(await pathExists(binaryPath), `${binaryPath} does not exist in ${base} (${content.join(', ')})`).to.be.true - } - - before(async function () { - this.timeout(30_000) - - // Run servers - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - }) - - it('Should update youtube-dl from github URL', async function () { - this.timeout(120_000) - - await testBinaryUpdate('https://api.github.com/repos/ytdl-org/youtube-dl/releases', 'youtube-dl') - }) - - it('Should update youtube-dl from raw URL', async function () { - this.timeout(120_000) - - await testBinaryUpdate('https://yt-dl.org/downloads/latest/youtube-dl', 'youtube-dl') - }) - - it('Should update youtube-dl from youtube-dl fork', async function () { - this.timeout(120_000) - - await testBinaryUpdate('https://api.github.com/repos/yt-dlp/yt-dlp/releases', 'yt-dlp') - }) - - after(async function () { - await cleanupTests([ server ]) - }) - }) -}) diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts deleted file mode 100644 index 65e9c8730..000000000 --- a/server/tests/api/videos/video-nsfw.ts +++ /dev/null @@ -1,227 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' -import { BooleanBothQuery, CustomConfig, ResultList, Video, VideosOverview } from '@shared/models' - -function createOverviewRes (overview: VideosOverview) { - const videos = overview.categories[0].videos - return { data: videos, total: videos.length } -} - -describe('Test video NSFW policy', function () { - let server: PeerTubeServer - let userAccessToken: string - let customConfig: CustomConfig - - async function getVideosFunctions (token?: string, query: { nsfw?: BooleanBothQuery } = {}) { - const user = await server.users.getMyInfo() - - const channelName = user.videoChannels[0].name - const accountName = user.account.name + '@' + user.account.host - - const hasQuery = Object.keys(query).length !== 0 - let promises: Promise>[] - - if (token) { - promises = [ - server.search.advancedVideoSearch({ token, search: { search: 'n', sort: '-publishedAt', ...query } }), - server.videos.listWithToken({ token, ...query }), - server.videos.listByAccount({ token, handle: accountName, ...query }), - server.videos.listByChannel({ token, handle: channelName, ...query }) - ] - - // Overviews do not support video filters - if (!hasQuery) { - const p = server.overviews.getVideos({ page: 1, token }) - .then(res => createOverviewRes(res)) - promises.push(p) - } - - return Promise.all(promises) - } - - promises = [ - server.search.searchVideos({ search: 'n', sort: '-publishedAt' }), - server.videos.list(), - server.videos.listByAccount({ token: null, handle: accountName }), - server.videos.listByChannel({ token: null, handle: channelName }) - ] - - // Overviews do not support video filters - if (!hasQuery) { - const p = server.overviews.getVideos({ page: 1 }) - .then(res => createOverviewRes(res)) - promises.push(p) - } - - return Promise.all(promises) - } - - before(async function () { - this.timeout(50000) - server = await createSingleServer(1) - - // Get the access tokens - await setAccessTokensToServers([ server ]) - - { - const attributes = { name: 'nsfw', nsfw: true, category: 1 } - await server.videos.upload({ attributes }) - } - - { - const attributes = { name: 'normal', nsfw: false, category: 1 } - await server.videos.upload({ attributes }) - } - - customConfig = await server.config.getCustomConfig() - }) - - describe('Instance default NSFW policy', function () { - - it('Should display NSFW videos with display default NSFW policy', async function () { - const serverConfig = await server.config.getConfig() - expect(serverConfig.instance.defaultNSFWPolicy).to.equal('display') - - for (const body of await getVideosFunctions()) { - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - expect(videos[0].name).to.equal('normal') - expect(videos[1].name).to.equal('nsfw') - } - }) - - it('Should not display NSFW videos with do_not_list default NSFW policy', async function () { - customConfig.instance.defaultNSFWPolicy = 'do_not_list' - await server.config.updateCustomConfig({ newCustomConfig: customConfig }) - - const serverConfig = await server.config.getConfig() - expect(serverConfig.instance.defaultNSFWPolicy).to.equal('do_not_list') - - for (const body of await getVideosFunctions()) { - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('normal') - } - }) - - it('Should display NSFW videos with blur default NSFW policy', async function () { - customConfig.instance.defaultNSFWPolicy = 'blur' - await server.config.updateCustomConfig({ newCustomConfig: customConfig }) - - const serverConfig = await server.config.getConfig() - expect(serverConfig.instance.defaultNSFWPolicy).to.equal('blur') - - for (const body of await getVideosFunctions()) { - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - expect(videos[0].name).to.equal('normal') - expect(videos[1].name).to.equal('nsfw') - } - }) - }) - - describe('User NSFW policy', function () { - - it('Should create a user having the default nsfw policy', async function () { - const username = 'user1' - const password = 'my super password' - await server.users.create({ username, password }) - - userAccessToken = await server.login.getAccessToken({ username, password }) - - const user = await server.users.getMyInfo({ token: userAccessToken }) - expect(user.nsfwPolicy).to.equal('blur') - }) - - it('Should display NSFW videos with blur user NSFW policy', async function () { - customConfig.instance.defaultNSFWPolicy = 'do_not_list' - await server.config.updateCustomConfig({ newCustomConfig: customConfig }) - - for (const body of await getVideosFunctions(userAccessToken)) { - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - expect(videos[0].name).to.equal('normal') - expect(videos[1].name).to.equal('nsfw') - } - }) - - it('Should display NSFW videos with display user NSFW policy', async function () { - await server.users.updateMe({ nsfwPolicy: 'display' }) - - for (const body of await getVideosFunctions(server.accessToken)) { - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - expect(videos[0].name).to.equal('normal') - expect(videos[1].name).to.equal('nsfw') - } - }) - - it('Should not display NSFW videos with do_not_list user NSFW policy', async function () { - await server.users.updateMe({ nsfwPolicy: 'do_not_list' }) - - for (const body of await getVideosFunctions(server.accessToken)) { - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('normal') - } - }) - - it('Should be able to see my NSFW videos even with do_not_list user NSFW policy', async function () { - const { total, data } = await server.videos.listMyVideos() - expect(total).to.equal(2) - - expect(data).to.have.lengthOf(2) - expect(data[0].name).to.equal('normal') - expect(data[1].name).to.equal('nsfw') - }) - - it('Should display NSFW videos when the nsfw param === true', async function () { - for (const body of await getVideosFunctions(server.accessToken, { nsfw: 'true' })) { - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('nsfw') - } - }) - - it('Should hide NSFW videos when the nsfw param === true', async function () { - for (const body of await getVideosFunctions(server.accessToken, { nsfw: 'false' })) { - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('normal') - } - }) - - it('Should display both videos when the nsfw param === both', async function () { - for (const body of await getVideosFunctions(server.accessToken, { nsfw: 'both' })) { - expect(body.total).to.equal(2) - - const videos = body.data - expect(videos).to.have.lengthOf(2) - expect(videos[0].name).to.equal('normal') - expect(videos[1].name).to.equal('nsfw') - } - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/video-passwords.ts b/server/tests/api/videos/video-passwords.ts deleted file mode 100644 index e01a93a4d..000000000 --- a/server/tests/api/videos/video-passwords.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - VideoPasswordsCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar -} from '@shared/server-commands' -import { VideoPrivacy } from '@shared/models' - -describe('Test video passwords', function () { - let server: PeerTubeServer - let videoUUID: string - - let userAccessTokenServer1: string - - let videoPasswords: string[] = [] - let command: VideoPasswordsCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - for (let i = 0; i < 10; i++) { - videoPasswords.push(`password ${i + 1}`) - } - const { uuid } = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PASSWORD_PROTECTED, videoPasswords } }) - videoUUID = uuid - - await setDefaultChannelAvatar(server) - await setDefaultAccountAvatar(server) - - userAccessTokenServer1 = await server.users.generateUserAndToken('user1') - await setDefaultChannelAvatar(server, 'user1_channel') - await setDefaultAccountAvatar(server, userAccessTokenServer1) - - command = server.videoPasswords - }) - - it('Should list video passwords', async function () { - const body = await command.list({ videoId: videoUUID }) - - expect(body.total).to.equal(10) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(10) - }) - - it('Should filter passwords on this video', async function () { - const body = await command.list({ videoId: videoUUID, count: 2, start: 3, sort: 'createdAt' }) - - expect(body.total).to.equal(10) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - expect(body.data[0].password).to.equal('password 4') - expect(body.data[1].password).to.equal('password 5') - }) - - it('Should update password for this video', async function () { - videoPasswords = [ 'my super new password 1', 'my super new password 2' ] - - await command.updateAll({ videoId: videoUUID, passwords: videoPasswords }) - const body = await command.list({ videoId: videoUUID }) - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - expect(body.data[0].password).to.equal('my super new password 2') - expect(body.data[1].password).to.equal('my super new password 1') - }) - - it('Should delete one password', async function () { - { - const body = await command.list({ videoId: videoUUID }) - expect(body.total).to.equal(2) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(2) - await command.remove({ id: body.data[0].id, videoId: videoUUID }) - } - { - const body = await command.list({ videoId: videoUUID }) - - expect(body.total).to.equal(1) - expect(body.data).to.be.an('array') - expect(body.data).to.have.lengthOf(1) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts deleted file mode 100644 index c274c20bf..000000000 --- a/server/tests/api/videos/video-playlist-thumbnails.ts +++ /dev/null @@ -1,234 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { testImageGeneratedByFFmpeg } from '@server/tests/shared' -import { VideoPlaylistPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Playlist thumbnail', function () { - let servers: PeerTubeServer[] = [] - - let playlistWithoutThumbnailId: number - let playlistWithThumbnailId: number - - let withThumbnailE1: number - let withThumbnailE2: number - let withoutThumbnailE1: number - let withoutThumbnailE2: number - - let video1: number - let video2: number - - async function getPlaylistWithoutThumbnail (server: PeerTubeServer) { - const body = await server.playlists.list({ start: 0, count: 10 }) - - return body.data.find(p => p.displayName === 'playlist without thumbnail') - } - - async function getPlaylistWithThumbnail (server: PeerTubeServer) { - const body = await server.playlists.list({ start: 0, count: 10 }) - - return body.data.find(p => p.displayName === 'playlist with thumbnail') - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - for (const server of servers) { - await server.config.disableTranscoding() - } - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - - video1 = (await servers[0].videos.quickUpload({ name: 'video 1' })).id - video2 = (await servers[0].videos.quickUpload({ name: 'video 2' })).id - - await waitJobs(servers) - }) - - it('Should automatically update the thumbnail when adding an element', async function () { - this.timeout(30000) - - const created = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist without thumbnail', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[1].store.channel.id - } - }) - playlistWithoutThumbnailId = created.id - - const added = await servers[1].playlists.addElement({ - playlistId: playlistWithoutThumbnailId, - attributes: { videoId: video1 } - }) - withoutThumbnailE1 = added.id - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithoutThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath) - } - }) - - it('Should not update the thumbnail if we explicitly uploaded a thumbnail', async function () { - this.timeout(30000) - - const created = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist with thumbnail', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[1].store.channel.id, - thumbnailfile: 'custom-thumbnail.jpg' - } - }) - playlistWithThumbnailId = created.id - - const added = await servers[1].playlists.addElement({ - playlistId: playlistWithThumbnailId, - attributes: { videoId: video1 } - }) - withThumbnailE1 = added.id - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath) - } - }) - - it('Should automatically update the thumbnail when moving the first element', async function () { - this.timeout(30000) - - const added = await servers[1].playlists.addElement({ - playlistId: playlistWithoutThumbnailId, - attributes: { videoId: video2 } - }) - withoutThumbnailE2 = added.id - - await servers[1].playlists.reorderElements({ - playlistId: playlistWithoutThumbnailId, - attributes: { - startPosition: 1, - insertAfterPosition: 2 - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithoutThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath) - } - }) - - it('Should not update the thumbnail when moving the first element if we explicitly uploaded a thumbnail', async function () { - this.timeout(30000) - - const added = await servers[1].playlists.addElement({ - playlistId: playlistWithThumbnailId, - attributes: { videoId: video2 } - }) - withThumbnailE2 = added.id - - await servers[1].playlists.reorderElements({ - playlistId: playlistWithThumbnailId, - attributes: { - startPosition: 1, - insertAfterPosition: 2 - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath) - } - }) - - it('Should automatically update the thumbnail when deleting the first element', async function () { - this.timeout(30000) - - await servers[1].playlists.removeElement({ - playlistId: playlistWithoutThumbnailId, - elementId: withoutThumbnailE1 - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithoutThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath) - } - }) - - it('Should not update the thumbnail when deleting the first element if we explicitly uploaded a thumbnail', async function () { - this.timeout(30000) - - await servers[1].playlists.removeElement({ - playlistId: playlistWithThumbnailId, - elementId: withThumbnailE1 - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath) - } - }) - - it('Should the thumbnail when we delete the last element', async function () { - this.timeout(30000) - - await servers[1].playlists.removeElement({ - playlistId: playlistWithoutThumbnailId, - elementId: withoutThumbnailE2 - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithoutThumbnail(server) - expect(p.thumbnailPath).to.be.null - } - }) - - it('Should not update the thumbnail when we delete the last element if we explicitly uploaded a thumbnail', async function () { - this.timeout(30000) - - await servers[1].playlists.removeElement({ - playlistId: playlistWithThumbnailId, - elementId: withThumbnailE2 - }) - - await waitJobs(servers) - - for (const server of servers) { - const p = await getPlaylistWithThumbnail(server) - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts deleted file mode 100644 index 3bfa874cb..000000000 --- a/server/tests/api/videos/video-playlists.ts +++ /dev/null @@ -1,1208 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { checkPlaylistFilesWereRemoved, testImageGeneratedByFFmpeg } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { uuidToShort } from '@shared/extra-utils' -import { - HttpStatusCode, - VideoPlaylist, - VideoPlaylistCreateResult, - VideoPlaylistElementType, - VideoPlaylistPrivacy, - VideoPlaylistType, - VideoPrivacy -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - PlaylistsCommand, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -async function checkPlaylistElementType ( - servers: PeerTubeServer[], - playlistId: string, - type: VideoPlaylistElementType, - position: number, - name: string, - total: number -) { - for (const server of servers) { - const body = await server.playlists.listVideos({ token: server.accessToken, playlistId, start: 0, count: 10 }) - expect(body.total).to.equal(total) - - const videoElement = body.data.find(e => e.position === position) - expect(videoElement.type).to.equal(type, 'On server ' + server.url) - - if (type === VideoPlaylistElementType.REGULAR) { - expect(videoElement.video).to.not.be.null - expect(videoElement.video.name).to.equal(name) - } else { - expect(videoElement.video).to.be.null - } - } -} - -describe('Test video playlists', function () { - let servers: PeerTubeServer[] = [] - - let playlistServer2Id1: number - let playlistServer2Id2: number - let playlistServer2UUID2: string - - let playlistServer1Id: number - let playlistServer1DisplayName: string - let playlistServer1UUID: string - let playlistServer1UUID2: string - - let playlistElementServer1Video4: number - let playlistElementServer1Video5: number - let playlistElementNSFW: number - - let nsfwVideoServer1: number - - let userTokenServer1: string - - let commands: PlaylistsCommand[] - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(3) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - for (const server of servers) { - await server.config.disableTranscoding() - } - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - // Server 1 and server 3 follow each other - await doubleFollow(servers[0], servers[2]) - - commands = servers.map(s => s.playlists) - - { - servers[0].store.videos = [] - servers[1].store.videos = [] - servers[2].store.videos = [] - - for (const server of servers) { - for (let i = 0; i < 7; i++) { - const name = `video ${i} server ${server.serverNumber}` - const video = await server.videos.upload({ attributes: { name, nsfw: false } }) - - server.store.videos.push(video) - } - } - } - - nsfwVideoServer1 = (await servers[0].videos.quickUpload({ name: 'NSFW video', nsfw: true })).id - - userTokenServer1 = await servers[0].users.generateUserAndToken('user1') - - await waitJobs(servers) - }) - - describe('Check playlists filters and privacies', function () { - - it('Should list video playlist privacies', async function () { - const privacies = await commands[0].getPrivacies() - - expect(Object.keys(privacies)).to.have.length.at.least(3) - expect(privacies[3]).to.equal('Private') - }) - - it('Should filter on playlist type', async function () { - this.timeout(30000) - - const token = servers[0].accessToken - - await commands[0].create({ - attributes: { - displayName: 'my super playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - description: 'my super description', - thumbnailfile: 'custom-thumbnail.jpg', - videoChannelId: servers[0].store.channel.id - } - }) - - { - const body = await commands[0].listByAccount({ token, handle: 'root', playlistType: VideoPlaylistType.WATCH_LATER }) - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlist = body.data[0] - expect(playlist.displayName).to.equal('Watch later') - expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) - expect(playlist.type.label).to.equal('Watch later') - expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) - } - - { - const bodyList = await commands[0].list({ playlistType: VideoPlaylistType.WATCH_LATER }) - const bodyChannel = await commands[0].listByChannel({ handle: 'root_channel', playlistType: VideoPlaylistType.WATCH_LATER }) - - for (const body of [ bodyList, bodyChannel ]) { - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - } - - { - const bodyList = await commands[0].list({ playlistType: VideoPlaylistType.REGULAR }) - const bodyChannel = await commands[0].listByChannel({ handle: 'root_channel', playlistType: VideoPlaylistType.REGULAR }) - - let playlist: VideoPlaylist = null - for (const body of [ bodyList, bodyChannel ]) { - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - playlist = body.data[0] - expect(playlist.displayName).to.equal('my super playlist') - expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC) - expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR) - } - - await commands[0].update({ - playlistId: playlist.id, - attributes: { - privacy: VideoPlaylistPrivacy.PRIVATE - } - }) - } - - { - const bodyList = await commands[0].list({ playlistType: VideoPlaylistType.REGULAR }) - const bodyChannel = await commands[0].listByChannel({ handle: 'root_channel', playlistType: VideoPlaylistType.REGULAR }) - - for (const body of [ bodyList, bodyChannel ]) { - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - } - - { - const body = await commands[0].listByAccount({ handle: 'root' }) - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - } - }) - - it('Should get private playlist for a classic user', async function () { - const token = await servers[0].users.generateUserAndToken('toto') - - const body = await commands[0].listByAccount({ token, handle: 'toto' }) - - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlistId = body.data[0].id - await commands[0].listVideos({ token, playlistId }) - }) - }) - - describe('Create and federate playlists', function () { - - it('Should create a playlist on server 1 and have the playlist on server 2 and 3', async function () { - this.timeout(30000) - - await commands[0].create({ - attributes: { - displayName: 'my super playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - description: 'my super description', - thumbnailfile: 'custom-thumbnail.jpg', - videoChannelId: servers[0].store.channel.id - } - }) - - await waitJobs(servers) - // Processing a playlist by the receiver could be long - await wait(3000) - - for (const server of servers) { - const body = await server.playlists.list({ start: 0, count: 5 }) - expect(body.total).to.equal(1) - expect(body.data).to.have.lengthOf(1) - - const playlistFromList = body.data[0] - - const playlistFromGet = await server.playlists.get({ playlistId: playlistFromList.uuid }) - - for (const playlist of [ playlistFromGet, playlistFromList ]) { - expect(playlist.id).to.be.a('number') - expect(playlist.uuid).to.be.a('string') - - expect(playlist.isLocal).to.equal(server.serverNumber === 1) - - expect(playlist.displayName).to.equal('my super playlist') - expect(playlist.description).to.equal('my super description') - expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC) - expect(playlist.privacy.label).to.equal('Public') - expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR) - expect(playlist.type.label).to.equal('Regular') - expect(playlist.embedPath).to.equal('/video-playlists/embed/' + playlist.uuid) - - expect(playlist.videosLength).to.equal(0) - - expect(playlist.ownerAccount.name).to.equal('root') - expect(playlist.ownerAccount.displayName).to.equal('root') - expect(playlist.videoChannel.name).to.equal('root_channel') - expect(playlist.videoChannel.displayName).to.equal('Main root channel') - } - } - }) - - it('Should create a playlist on server 2 and have the playlist on server 1 but not on server 3', async function () { - this.timeout(30000) - - { - const playlist = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist 2', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[1].store.channel.id - } - }) - playlistServer2Id1 = playlist.id - } - - { - const playlist = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist 3', - privacy: VideoPlaylistPrivacy.PUBLIC, - thumbnailfile: 'custom-thumbnail.jpg', - videoChannelId: servers[1].store.channel.id - } - }) - - playlistServer2Id2 = playlist.id - playlistServer2UUID2 = playlist.uuid - } - - for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) { - await servers[1].playlists.addElement({ - playlistId: id, - attributes: { videoId: servers[1].store.videos[0].id, startTimestamp: 1, stopTimestamp: 2 } - }) - await servers[1].playlists.addElement({ - playlistId: id, - attributes: { videoId: servers[1].store.videos[1].id } - }) - } - - await waitJobs(servers) - await wait(3000) - - for (const server of [ servers[0], servers[1] ]) { - const body = await server.playlists.list({ start: 0, count: 5 }) - - const playlist2 = body.data.find(p => p.displayName === 'playlist 2') - expect(playlist2).to.not.be.undefined - await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', playlist2.thumbnailPath) - - const playlist3 = body.data.find(p => p.displayName === 'playlist 3') - expect(playlist3).to.not.be.undefined - await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', playlist3.thumbnailPath) - } - - const body = await servers[2].playlists.list({ start: 0, count: 5 }) - expect(body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined - expect(body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined - }) - - it('Should have the playlist on server 3 after a new follow', async function () { - this.timeout(30000) - - // Server 2 and server 3 follow each other - await doubleFollow(servers[1], servers[2]) - - const body = await servers[2].playlists.list({ start: 0, count: 5 }) - - const playlist2 = body.data.find(p => p.displayName === 'playlist 2') - expect(playlist2).to.not.be.undefined - await testImageGeneratedByFFmpeg(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath) - - expect(body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined - }) - }) - - describe('List playlists', function () { - - it('Should correctly list the playlists', async function () { - this.timeout(30000) - - { - const body = await servers[2].playlists.list({ start: 1, count: 2, sort: 'createdAt' }) - expect(body.total).to.equal(3) - - const data = body.data - expect(data).to.have.lengthOf(2) - expect(data[0].displayName).to.equal('playlist 2') - expect(data[1].displayName).to.equal('playlist 3') - } - - { - const body = await servers[2].playlists.list({ start: 1, count: 2, sort: '-createdAt' }) - expect(body.total).to.equal(3) - - const data = body.data - expect(data).to.have.lengthOf(2) - expect(data[0].displayName).to.equal('playlist 2') - expect(data[1].displayName).to.equal('my super playlist') - } - }) - - it('Should list video channel playlists', async function () { - this.timeout(30000) - - { - const body = await commands[0].listByChannel({ handle: 'root_channel', start: 0, count: 2, sort: '-createdAt' }) - expect(body.total).to.equal(1) - - const data = body.data - expect(data).to.have.lengthOf(1) - expect(data[0].displayName).to.equal('my super playlist') - } - }) - - it('Should list account playlists', async function () { - this.timeout(30000) - - { - const body = await servers[1].playlists.listByAccount({ handle: 'root', start: 1, count: 2, sort: '-createdAt' }) - expect(body.total).to.equal(2) - - const data = body.data - expect(data).to.have.lengthOf(1) - expect(data[0].displayName).to.equal('playlist 2') - } - - { - const body = await servers[1].playlists.listByAccount({ handle: 'root', start: 1, count: 2, sort: 'createdAt' }) - expect(body.total).to.equal(2) - - const data = body.data - expect(data).to.have.lengthOf(1) - expect(data[0].displayName).to.equal('playlist 3') - } - - { - const body = await servers[1].playlists.listByAccount({ handle: 'root', sort: 'createdAt', search: '3' }) - expect(body.total).to.equal(1) - - const data = body.data - expect(data).to.have.lengthOf(1) - expect(data[0].displayName).to.equal('playlist 3') - } - - { - const body = await servers[1].playlists.listByAccount({ handle: 'root', sort: 'createdAt', search: '4' }) - expect(body.total).to.equal(0) - - const data = body.data - expect(data).to.have.lengthOf(0) - } - }) - }) - - describe('Playlist rights', function () { - let unlistedPlaylist: VideoPlaylistCreateResult - let privatePlaylist: VideoPlaylistCreateResult - - before(async function () { - this.timeout(30000) - - { - unlistedPlaylist = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist unlisted', - privacy: VideoPlaylistPrivacy.UNLISTED, - videoChannelId: servers[1].store.channel.id - } - }) - } - - { - privatePlaylist = await servers[1].playlists.create({ - attributes: { - displayName: 'playlist private', - privacy: VideoPlaylistPrivacy.PRIVATE - } - }) - } - - await waitJobs(servers) - await wait(3000) - }) - - it('Should not list unlisted or private playlists', async function () { - for (const server of servers) { - const results = [ - await server.playlists.listByAccount({ handle: 'root@' + servers[1].host, sort: '-createdAt' }), - await server.playlists.list({ start: 0, count: 2, sort: '-createdAt' }) - ] - - expect(results[0].total).to.equal(2) - expect(results[1].total).to.equal(3) - - for (const body of results) { - const data = body.data - expect(data).to.have.lengthOf(2) - expect(data[0].displayName).to.equal('playlist 3') - expect(data[1].displayName).to.equal('playlist 2') - } - } - }) - - it('Should not get unlisted playlist using only the id', async function () { - await servers[1].playlists.get({ playlistId: unlistedPlaylist.id, expectedStatus: 404 }) - }) - - it('Should get unlisted playlist using uuid or shortUUID', async function () { - await servers[1].playlists.get({ playlistId: unlistedPlaylist.uuid }) - await servers[1].playlists.get({ playlistId: unlistedPlaylist.shortUUID }) - }) - - it('Should not get private playlist without token', async function () { - for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) { - await servers[1].playlists.get({ playlistId: id, expectedStatus: 401 }) - } - }) - - it('Should get private playlist with a token', async function () { - for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) { - await servers[1].playlists.get({ token: servers[1].accessToken, playlistId: id }) - } - }) - }) - - describe('Update playlists', function () { - - it('Should update a playlist', async function () { - this.timeout(30000) - - await servers[1].playlists.update({ - attributes: { - displayName: 'playlist 3 updated', - description: 'description updated', - privacy: VideoPlaylistPrivacy.UNLISTED, - thumbnailfile: 'custom-thumbnail.jpg', - videoChannelId: servers[1].store.channel.id - }, - playlistId: playlistServer2Id2 - }) - - await waitJobs(servers) - - for (const server of servers) { - const playlist = await server.playlists.get({ playlistId: playlistServer2UUID2 }) - - expect(playlist.displayName).to.equal('playlist 3 updated') - expect(playlist.description).to.equal('description updated') - - expect(playlist.privacy.id).to.equal(VideoPlaylistPrivacy.UNLISTED) - expect(playlist.privacy.label).to.equal('Unlisted') - - expect(playlist.type.id).to.equal(VideoPlaylistType.REGULAR) - expect(playlist.type.label).to.equal('Regular') - - expect(playlist.videosLength).to.equal(2) - - expect(playlist.ownerAccount.name).to.equal('root') - expect(playlist.ownerAccount.displayName).to.equal('root') - expect(playlist.videoChannel.name).to.equal('root_channel') - expect(playlist.videoChannel.displayName).to.equal('Main root channel') - } - }) - }) - - describe('Element timestamps', function () { - - it('Should create a playlist containing different startTimestamp/endTimestamp videos', async function () { - this.timeout(30000) - - const addVideo = (attributes: any) => { - return commands[0].addElement({ playlistId: playlistServer1Id, attributes }) - } - - const playlistDisplayName = 'playlist 4' - const playlist = await commands[0].create({ - attributes: { - displayName: playlistDisplayName, - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[0].store.channel.id - } - }) - - playlistServer1Id = playlist.id - playlistServer1DisplayName = playlistDisplayName - playlistServer1UUID = playlist.uuid - - await addVideo({ videoId: servers[0].store.videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 }) - await addVideo({ videoId: servers[2].store.videos[1].uuid, startTimestamp: 35 }) - await addVideo({ videoId: servers[2].store.videos[2].uuid }) - { - const element = await addVideo({ videoId: servers[0].store.videos[3].uuid, stopTimestamp: 35 }) - playlistElementServer1Video4 = element.id - } - - { - const element = await addVideo({ videoId: servers[0].store.videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 }) - playlistElementServer1Video5 = element.id - } - - { - const element = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 }) - playlistElementNSFW = element.id - - await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 4 }) - await addVideo({ videoId: nsfwVideoServer1 }) - } - - await waitJobs(servers) - }) - - it('Should correctly list playlist videos', async function () { - this.timeout(30000) - - for (const server of servers) { - { - const body = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - - expect(body.total).to.equal(8) - - const videoElements = body.data - expect(videoElements).to.have.lengthOf(8) - - expect(videoElements[0].video.name).to.equal('video 0 server 1') - expect(videoElements[0].position).to.equal(1) - expect(videoElements[0].startTimestamp).to.equal(15) - expect(videoElements[0].stopTimestamp).to.equal(28) - - expect(videoElements[1].video.name).to.equal('video 1 server 3') - expect(videoElements[1].position).to.equal(2) - expect(videoElements[1].startTimestamp).to.equal(35) - expect(videoElements[1].stopTimestamp).to.be.null - - expect(videoElements[2].video.name).to.equal('video 2 server 3') - expect(videoElements[2].position).to.equal(3) - expect(videoElements[2].startTimestamp).to.be.null - expect(videoElements[2].stopTimestamp).to.be.null - - expect(videoElements[3].video.name).to.equal('video 3 server 1') - expect(videoElements[3].position).to.equal(4) - expect(videoElements[3].startTimestamp).to.be.null - expect(videoElements[3].stopTimestamp).to.equal(35) - - expect(videoElements[4].video.name).to.equal('video 4 server 1') - expect(videoElements[4].position).to.equal(5) - expect(videoElements[4].startTimestamp).to.equal(45) - expect(videoElements[4].stopTimestamp).to.equal(60) - - expect(videoElements[5].video.name).to.equal('NSFW video') - expect(videoElements[5].position).to.equal(6) - expect(videoElements[5].startTimestamp).to.equal(5) - expect(videoElements[5].stopTimestamp).to.be.null - - expect(videoElements[6].video.name).to.equal('NSFW video') - expect(videoElements[6].position).to.equal(7) - expect(videoElements[6].startTimestamp).to.equal(4) - expect(videoElements[6].stopTimestamp).to.be.null - - expect(videoElements[7].video.name).to.equal('NSFW video') - expect(videoElements[7].position).to.equal(8) - expect(videoElements[7].startTimestamp).to.be.null - expect(videoElements[7].stopTimestamp).to.be.null - } - - { - const body = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 2 }) - expect(body.data).to.have.lengthOf(2) - } - } - }) - }) - - describe('Element type', function () { - let groupUser1: PeerTubeServer[] - let groupWithoutToken1: PeerTubeServer[] - let group1: PeerTubeServer[] - let group2: PeerTubeServer[] - - let video1: string - let video2: string - let video3: string - - before(async function () { - this.timeout(60000) - - groupUser1 = [ Object.assign({}, servers[0], { accessToken: userTokenServer1 }) ] - groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ] - group1 = [ servers[0] ] - group2 = [ servers[1], servers[2] ] - - const playlist = await commands[0].create({ - token: userTokenServer1, - attributes: { - displayName: 'playlist 56', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[0].store.channel.id - } - }) - - const playlistServer1Id2 = playlist.id - playlistServer1UUID2 = playlist.uuid - - const addVideo = (attributes: any) => { - return commands[0].addElement({ token: userTokenServer1, playlistId: playlistServer1Id2, attributes }) - } - - video1 = (await servers[0].videos.quickUpload({ name: 'video 89', token: userTokenServer1 })).uuid - video2 = (await servers[1].videos.quickUpload({ name: 'video 90' })).uuid - video3 = (await servers[0].videos.quickUpload({ name: 'video 91', nsfw: true })).uuid - - await waitJobs(servers) - - await addVideo({ videoId: video1, startTimestamp: 15, stopTimestamp: 28 }) - await addVideo({ videoId: video2, startTimestamp: 35 }) - await addVideo({ videoId: video3 }) - - await waitJobs(servers) - }) - - it('Should update the element type if the video is private/password protected', async function () { - this.timeout(20000) - - const name = 'video 89' - const position = 1 - - { - await servers[0].videos.update({ id: video1, attributes: { privacy: VideoPrivacy.PRIVATE } }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3) - await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3) - } - - { - await servers[0].videos.update({ - id: video1, - attributes: { privacy: VideoPrivacy.PASSWORD_PROTECTED, videoPasswords: [ 'password' ] } - }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3) - await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.PRIVATE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3) - } - - { - await servers[0].videos.update({ id: video1, attributes: { privacy: VideoPrivacy.PUBLIC } }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - // We deleted the video, so even if we recreated it, the old entry is still deleted - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3) - } - }) - - it('Should update the element type if the video is blacklisted', async function () { - this.timeout(20000) - - const name = 'video 89' - const position = 1 - - { - await servers[0].blacklist.add({ videoId: video1, reason: 'reason', unfederate: true }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3) - } - - { - await servers[0].blacklist.remove({ videoId: video1 }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(groupWithoutToken1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - await checkPlaylistElementType(group1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - // We deleted the video (because unfederated), so even if we recreated it, the old entry is still deleted - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.DELETED, position, name, 3) - } - }) - - it('Should update the element type if the account or server of the video is blocked', async function () { - this.timeout(90000) - - const command = servers[0].blocklist - - const name = 'video 90' - const position = 2 - - { - await command.addToMyBlocklist({ token: userTokenServer1, account: 'root@' + servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - - await command.removeFromMyBlocklist({ token: userTokenServer1, account: 'root@' + servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - } - - { - await command.addToMyBlocklist({ token: userTokenServer1, server: servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - - await command.removeFromMyBlocklist({ token: userTokenServer1, server: servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - } - - { - await command.addToServerBlocklist({ account: 'root@' + servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - - await command.removeFromServerBlocklist({ account: 'root@' + servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - } - - { - await command.addToServerBlocklist({ server: servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - - await command.removeFromServerBlocklist({ server: servers[1].host }) - await waitJobs(servers) - - await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) - } - }) - }) - - describe('Managing playlist elements', function () { - - it('Should reorder the playlist', async function () { - this.timeout(30000) - - { - await commands[0].reorderElements({ - playlistId: playlistServer1Id, - attributes: { - startPosition: 2, - insertAfterPosition: 3 - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const body = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - const names = body.data.map(v => v.video.name) - - expect(names).to.deep.equal([ - 'video 0 server 1', - 'video 2 server 3', - 'video 1 server 3', - 'video 3 server 1', - 'video 4 server 1', - 'NSFW video', - 'NSFW video', - 'NSFW video' - ]) - } - } - - { - await commands[0].reorderElements({ - playlistId: playlistServer1Id, - attributes: { - startPosition: 1, - reorderLength: 3, - insertAfterPosition: 4 - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const body = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - const names = body.data.map(v => v.video.name) - - expect(names).to.deep.equal([ - 'video 3 server 1', - 'video 0 server 1', - 'video 2 server 3', - 'video 1 server 3', - 'video 4 server 1', - 'NSFW video', - 'NSFW video', - 'NSFW video' - ]) - } - } - - { - await commands[0].reorderElements({ - playlistId: playlistServer1Id, - attributes: { - startPosition: 6, - insertAfterPosition: 3 - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const { data: elements } = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - const names = elements.map(v => v.video.name) - - expect(names).to.deep.equal([ - 'video 3 server 1', - 'video 0 server 1', - 'video 2 server 3', - 'NSFW video', - 'video 1 server 3', - 'video 4 server 1', - 'NSFW video', - 'NSFW video' - ]) - - for (let i = 1; i <= elements.length; i++) { - expect(elements[i - 1].position).to.equal(i) - } - } - } - }) - - it('Should update startTimestamp/endTimestamp of some elements', async function () { - this.timeout(30000) - - await commands[0].updateElement({ - playlistId: playlistServer1Id, - elementId: playlistElementServer1Video4, - attributes: { - startTimestamp: 1 - } - }) - - await commands[0].updateElement({ - playlistId: playlistServer1Id, - elementId: playlistElementServer1Video5, - attributes: { - stopTimestamp: null - } - }) - - await waitJobs(servers) - - for (const server of servers) { - const { data: elements } = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - - expect(elements[0].video.name).to.equal('video 3 server 1') - expect(elements[0].position).to.equal(1) - expect(elements[0].startTimestamp).to.equal(1) - expect(elements[0].stopTimestamp).to.equal(35) - - expect(elements[5].video.name).to.equal('video 4 server 1') - expect(elements[5].position).to.equal(6) - expect(elements[5].startTimestamp).to.equal(45) - expect(elements[5].stopTimestamp).to.be.null - } - }) - - it('Should check videos existence in my playlist', async function () { - const videoIds = [ - servers[0].store.videos[0].id, - 42000, - servers[0].store.videos[3].id, - 43000, - servers[0].store.videos[4].id - ] - const obj = await commands[0].videosExist({ videoIds }) - - { - const elem = obj[servers[0].store.videos[0].id] - expect(elem).to.have.lengthOf(1) - expect(elem[0].playlistElementId).to.exist - expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) - expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) - expect(elem[0].playlistId).to.equal(playlistServer1Id) - expect(elem[0].startTimestamp).to.equal(15) - expect(elem[0].stopTimestamp).to.equal(28) - } - - { - const elem = obj[servers[0].store.videos[3].id] - expect(elem).to.have.lengthOf(1) - expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4) - expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) - expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) - expect(elem[0].playlistId).to.equal(playlistServer1Id) - expect(elem[0].startTimestamp).to.equal(1) - expect(elem[0].stopTimestamp).to.equal(35) - } - - { - const elem = obj[servers[0].store.videos[4].id] - expect(elem).to.have.lengthOf(1) - expect(elem[0].playlistId).to.equal(playlistServer1Id) - expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) - expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) - expect(elem[0].startTimestamp).to.equal(45) - expect(elem[0].stopTimestamp).to.equal(null) - } - - expect(obj[42000]).to.have.lengthOf(0) - expect(obj[43000]).to.have.lengthOf(0) - }) - - it('Should automatically update updatedAt field of playlists', async function () { - const server = servers[1] - const videoId = servers[1].store.videos[5].id - - async function getPlaylistNames () { - const { data } = await server.playlists.listByAccount({ token: server.accessToken, handle: 'root', sort: '-updatedAt' }) - - return data.map(p => p.displayName) - } - - const attributes = { videoId } - const element1 = await server.playlists.addElement({ playlistId: playlistServer2Id1, attributes }) - const element2 = await server.playlists.addElement({ playlistId: playlistServer2Id2, attributes }) - - const names1 = await getPlaylistNames() - expect(names1[0]).to.equal('playlist 3 updated') - expect(names1[1]).to.equal('playlist 2') - - await server.playlists.removeElement({ playlistId: playlistServer2Id1, elementId: element1.id }) - - const names2 = await getPlaylistNames() - expect(names2[0]).to.equal('playlist 2') - expect(names2[1]).to.equal('playlist 3 updated') - - await server.playlists.removeElement({ playlistId: playlistServer2Id2, elementId: element2.id }) - - const names3 = await getPlaylistNames() - expect(names3[0]).to.equal('playlist 3 updated') - expect(names3[1]).to.equal('playlist 2') - }) - - it('Should delete some elements', async function () { - this.timeout(30000) - - await commands[0].removeElement({ playlistId: playlistServer1Id, elementId: playlistElementServer1Video4 }) - await commands[0].removeElement({ playlistId: playlistServer1Id, elementId: playlistElementNSFW }) - - await waitJobs(servers) - - for (const server of servers) { - const body = await server.playlists.listVideos({ playlistId: playlistServer1UUID, start: 0, count: 10 }) - expect(body.total).to.equal(6) - - const elements = body.data - expect(elements).to.have.lengthOf(6) - - expect(elements[0].video.name).to.equal('video 0 server 1') - expect(elements[0].position).to.equal(1) - - expect(elements[1].video.name).to.equal('video 2 server 3') - expect(elements[1].position).to.equal(2) - - expect(elements[2].video.name).to.equal('video 1 server 3') - expect(elements[2].position).to.equal(3) - - expect(elements[3].video.name).to.equal('video 4 server 1') - expect(elements[3].position).to.equal(4) - - expect(elements[4].video.name).to.equal('NSFW video') - expect(elements[4].position).to.equal(5) - - expect(elements[5].video.name).to.equal('NSFW video') - expect(elements[5].position).to.equal(6) - } - }) - - it('Should be able to create a public playlist, and set it to private', async function () { - this.timeout(30000) - - const videoPlaylistIds = await commands[0].create({ - attributes: { - displayName: 'my super public playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[0].store.channel.id - } - }) - - await waitJobs(servers) - - for (const server of servers) { - await server.playlists.get({ playlistId: videoPlaylistIds.uuid, expectedStatus: HttpStatusCode.OK_200 }) - } - - const attributes = { privacy: VideoPlaylistPrivacy.PRIVATE } - await commands[0].update({ playlistId: videoPlaylistIds.id, attributes }) - - await waitJobs(servers) - - for (const server of [ servers[1], servers[2] ]) { - await server.playlists.get({ playlistId: videoPlaylistIds.uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - - await commands[0].get({ playlistId: videoPlaylistIds.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await commands[0].get({ token: servers[0].accessToken, playlistId: videoPlaylistIds.uuid, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - describe('Playlist deletion', function () { - - it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { - this.timeout(30000) - - await commands[0].delete({ playlistId: playlistServer1Id }) - - await waitJobs(servers) - - for (const server of servers) { - await server.playlists.get({ playlistId: playlistServer1UUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - }) - - it('Should have deleted the thumbnail on server 1, 2 and 3', async function () { - this.timeout(30000) - - for (const server of servers) { - await checkPlaylistFilesWereRemoved(playlistServer1UUID, server) - } - }) - - it('Should unfollow servers 1 and 2 and hide their playlists', async function () { - this.timeout(30000) - - const finder = (data: VideoPlaylist[]) => data.find(p => p.displayName === 'my super playlist') - - { - const body = await servers[2].playlists.list({ start: 0, count: 5 }) - expect(body.total).to.equal(3) - - expect(finder(body.data)).to.not.be.undefined - } - - await servers[2].follows.unfollow({ target: servers[0] }) - - { - const body = await servers[2].playlists.list({ start: 0, count: 5 }) - expect(body.total).to.equal(1) - - expect(finder(body.data)).to.be.undefined - } - }) - - it('Should delete a channel and put the associated playlist in private mode', async function () { - this.timeout(30000) - - const channel = await servers[0].channels.create({ attributes: { name: 'super_channel', displayName: 'super channel' } }) - - const playlistCreated = await commands[0].create({ - attributes: { - displayName: 'channel playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: channel.id - } - }) - - await waitJobs(servers) - - await servers[0].channels.delete({ channelName: 'super_channel' }) - - await waitJobs(servers) - - const body = await commands[0].get({ token: servers[0].accessToken, playlistId: playlistCreated.uuid }) - expect(body.displayName).to.equal('channel playlist') - expect(body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) - - await servers[1].playlists.get({ playlistId: playlistCreated.uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - - it('Should delete an account and delete its playlists', async function () { - this.timeout(30000) - - const { userId, token } = await servers[0].users.generate('user_1') - - const { videoChannels } = await servers[0].users.getMyInfo({ token }) - const userChannel = videoChannels[0] - - await commands[0].create({ - attributes: { - displayName: 'playlist to be deleted', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: userChannel.id - } - }) - - await waitJobs(servers) - - const finder = (data: VideoPlaylist[]) => data.find(p => p.displayName === 'playlist to be deleted') - - { - for (const server of [ servers[0], servers[1] ]) { - const body = await server.playlists.list({ start: 0, count: 15 }) - - expect(finder(body.data)).to.not.be.undefined - } - } - - await servers[0].users.remove({ userId }) - await waitJobs(servers) - - { - for (const server of [ servers[0], servers[1] ]) { - const body = await server.playlists.list({ start: 0, count: 15 }) - - expect(finder(body.data)).to.be.undefined - } - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts deleted file mode 100644 index de96bcfcc..000000000 --- a/server/tests/api/videos/video-privacy.ts +++ /dev/null @@ -1,287 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' - -describe('Test video privacy', function () { - const servers: PeerTubeServer[] = [] - let anotherUserToken: string - - let privateVideoId: number - let privateVideoUUID: string - - let internalVideoId: number - let internalVideoUUID: string - - let unlistedVideo: VideoCreateResult - let nonFederatedUnlistedVideoUUID: string - - let now: number - - const dontFederateUnlistedConfig = { - federation: { - videos: { - federate_unlisted: false - } - } - } - - before(async function () { - this.timeout(50000) - - // Run servers - servers.push(await createSingleServer(1, dontFederateUnlistedConfig)) - servers.push(await createSingleServer(2)) - - // Get the access tokens - await setAccessTokensToServers(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - describe('Private and internal videos', function () { - - it('Should upload a private and internal videos on server 1', async function () { - this.timeout(50000) - - for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { - const attributes = { privacy } - await servers[0].videos.upload({ attributes }) - } - - await waitJobs(servers) - }) - - it('Should not have these private and internal videos on server 2', async function () { - const { total, data } = await servers[1].videos.list() - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - }) - - it('Should not list the private and internal videos for an unauthenticated user on server 1', async function () { - const { total, data } = await servers[0].videos.list() - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - }) - - it('Should not list the private video and list the internal video for an authenticated user on server 1', async function () { - const { total, data } = await servers[0].videos.listWithToken() - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - expect(data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL) - }) - - it('Should list my (private and internal) videos', async function () { - const { total, data } = await servers[0].videos.listMyVideos() - - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - const privateVideo = data.find(v => v.privacy.id === VideoPrivacy.PRIVATE) - privateVideoId = privateVideo.id - privateVideoUUID = privateVideo.uuid - - const internalVideo = data.find(v => v.privacy.id === VideoPrivacy.INTERNAL) - internalVideoId = internalVideo.id - internalVideoUUID = internalVideo.uuid - }) - - it('Should not be able to watch the private/internal video with non authenticated user', async function () { - await servers[0].videos.get({ id: privateVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - await servers[0].videos.get({ id: internalVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should not be able to watch the private video with another user', async function () { - const user = { - username: 'hello', - password: 'super password' - } - await servers[0].users.create({ username: user.username, password: user.password }) - - anotherUserToken = await servers[0].login.getAccessToken(user) - - await servers[0].videos.getWithToken({ - token: anotherUserToken, - id: privateVideoUUID, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should be able to watch the internal video with another user', async function () { - await servers[0].videos.getWithToken({ token: anotherUserToken, id: internalVideoUUID }) - }) - - it('Should be able to watch the private video with the correct user', async function () { - await servers[0].videos.getWithToken({ id: privateVideoUUID }) - }) - }) - - describe('Unlisted videos', function () { - - it('Should upload an unlisted video on server 2', async function () { - this.timeout(120000) - - const attributes = { - name: 'unlisted video', - privacy: VideoPrivacy.UNLISTED - } - await servers[1].videos.upload({ attributes }) - - // Server 2 has transcoding enabled - await waitJobs(servers) - }) - - it('Should not have this unlisted video listed on server 1 and 2', async function () { - for (const server of servers) { - const { total, data } = await server.videos.list() - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - }) - - it('Should list my (unlisted) videos', async function () { - const { total, data } = await servers[1].videos.listMyVideos() - - expect(total).to.equal(1) - expect(data).to.have.lengthOf(1) - - unlistedVideo = data[0] - }) - - it('Should not be able to get this unlisted video using its id', async function () { - await servers[1].videos.get({ id: unlistedVideo.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should be able to get this unlisted video using its uuid/shortUUID', async function () { - for (const server of servers) { - for (const id of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) { - const video = await server.videos.get({ id }) - - expect(video.name).to.equal('unlisted video') - } - } - }) - - it('Should upload a non-federating unlisted video to server 1', async function () { - this.timeout(30000) - - const attributes = { - name: 'unlisted video', - privacy: VideoPrivacy.UNLISTED - } - await servers[0].videos.upload({ attributes }) - - await waitJobs(servers) - }) - - it('Should list my new unlisted video', async function () { - const { total, data } = await servers[0].videos.listMyVideos() - - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - - nonFederatedUnlistedVideoUUID = data[0].uuid - }) - - it('Should be able to get non-federated unlisted video from origin', async function () { - const video = await servers[0].videos.get({ id: nonFederatedUnlistedVideoUUID }) - - expect(video.name).to.equal('unlisted video') - }) - - it('Should not be able to get non-federated unlisted video from federated server', async function () { - await servers[1].videos.get({ id: nonFederatedUnlistedVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) - }) - - describe('Privacy update', function () { - - it('Should update the private and internal videos to public on server 1', async function () { - this.timeout(100000) - - now = Date.now() - - { - const attributes = { - name: 'private video becomes public', - privacy: VideoPrivacy.PUBLIC - } - - await servers[0].videos.update({ id: privateVideoId, attributes }) - } - - { - const attributes = { - name: 'internal video becomes public', - privacy: VideoPrivacy.PUBLIC - } - await servers[0].videos.update({ id: internalVideoId, attributes }) - } - - await wait(10000) - await waitJobs(servers) - }) - - it('Should have this new public video listed on server 1 and 2', async function () { - for (const server of servers) { - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - expect(data).to.have.lengthOf(2) - - const privateVideo = data.find(v => v.name === 'private video becomes public') - const internalVideo = data.find(v => v.name === 'internal video becomes public') - - expect(privateVideo).to.not.be.undefined - expect(internalVideo).to.not.be.undefined - - expect(new Date(privateVideo.publishedAt).getTime()).to.be.at.least(now) - // We don't change the publish date of internal videos - expect(new Date(internalVideo.publishedAt).getTime()).to.be.below(now) - - expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC) - expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC) - } - }) - - it('Should set these videos as private and internal', async function () { - await servers[0].videos.update({ id: internalVideoId, attributes: { privacy: VideoPrivacy.PRIVATE } }) - await servers[0].videos.update({ id: privateVideoId, attributes: { privacy: VideoPrivacy.INTERNAL } }) - - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - - expect(total).to.equal(0) - expect(data).to.have.lengthOf(0) - } - - { - const { total, data } = await servers[0].videos.listMyVideos() - expect(total).to.equal(3) - expect(data).to.have.lengthOf(3) - - const privateVideo = data.find(v => v.name === 'private video becomes public') - const internalVideo = data.find(v => v.name === 'internal video becomes public') - - expect(privateVideo).to.not.be.undefined - expect(internalVideo).to.not.be.undefined - - expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL) - expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE) - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts deleted file mode 100644 index bf341c648..000000000 --- a/server/tests/api/videos/video-schedule-update.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -function in10Seconds () { - const now = new Date() - now.setSeconds(now.getSeconds() + 10) - - return now -} - -describe('Test video update scheduler', function () { - let servers: PeerTubeServer[] = [] - let video2UUID: string - - before(async function () { - this.timeout(30000) - - // Run servers - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should upload a video and schedule an update in 10 seconds', async function () { - const attributes = { - name: 'video 1', - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: in10Seconds().toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - - await servers[0].videos.upload({ attributes }) - - await waitJobs(servers) - }) - - it('Should not list the video (in privacy mode)', async function () { - for (const server of servers) { - const { total } = await server.videos.list() - - expect(total).to.equal(0) - } - }) - - it('Should have my scheduled video in my account videos', async function () { - const { total, data } = await servers[0].videos.listMyVideos() - expect(total).to.equal(1) - - const videoFromList = data[0] - const videoFromGet = await servers[0].videos.getWithToken({ id: videoFromList.uuid }) - - for (const video of [ videoFromList, videoFromGet ]) { - expect(video.name).to.equal('video 1') - expect(video.privacy.id).to.equal(VideoPrivacy.PRIVATE) - expect(new Date(video.scheduledUpdate.updateAt)).to.be.above(new Date()) - expect(video.scheduledUpdate.privacy).to.equal(VideoPrivacy.PUBLIC) - } - }) - - it('Should wait some seconds and have the video in public privacy', async function () { - this.timeout(50000) - - await wait(15000) - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - - expect(total).to.equal(1) - expect(data[0].name).to.equal('video 1') - } - }) - - it('Should upload a video without scheduling an update', async function () { - const attributes = { - name: 'video 2', - privacy: VideoPrivacy.PRIVATE - } - - const { uuid } = await servers[0].videos.upload({ attributes }) - video2UUID = uuid - - await waitJobs(servers) - }) - - it('Should update a video by scheduling an update', async function () { - const attributes = { - name: 'video 2 updated', - scheduleUpdate: { - updateAt: in10Seconds().toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - - await servers[0].videos.update({ id: video2UUID, attributes }) - await waitJobs(servers) - }) - - it('Should not display the updated video', async function () { - for (const server of servers) { - const { total } = await server.videos.list() - - expect(total).to.equal(1) - } - }) - - it('Should have my scheduled updated video in my account videos', async function () { - const { total, data } = await servers[0].videos.listMyVideos() - expect(total).to.equal(2) - - const video = data.find(v => v.uuid === video2UUID) - expect(video).not.to.be.undefined - - expect(video.name).to.equal('video 2 updated') - expect(video.privacy.id).to.equal(VideoPrivacy.PRIVATE) - - expect(new Date(video.scheduledUpdate.updateAt)).to.be.above(new Date()) - expect(video.scheduledUpdate.privacy).to.equal(VideoPrivacy.PUBLIC) - }) - - it('Should wait some seconds and have the updated video in public privacy', async function () { - this.timeout(20000) - - await wait(15000) - await waitJobs(servers) - - for (const server of servers) { - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - - const video = data.find(v => v.uuid === video2UUID) - expect(video).not.to.be.undefined - expect(video.name).to.equal('video 2 updated') - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-source.ts b/server/tests/api/videos/video-source.ts deleted file mode 100644 index 1f394f904..000000000 --- a/server/tests/api/videos/video-source.ts +++ /dev/null @@ -1,447 +0,0 @@ -import { expect } from 'chai' -import { expectStartWith } from '@server/tests/shared' -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test a video file replacement', function () { - let servers: PeerTubeServer[] = [] - - let replaceDate: Date - let userToken: string - let uuid: string - - before(async function () { - this.timeout(50000) - - servers = await createMultipleServers(2) - - // Get the access tokens - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - await servers[0].config.enableFileUpdate() - - userToken = await servers[0].users.generateUserAndToken('user1') - - // Server 1 and server 2 follow each other - await doubleFollow(servers[0], servers[1]) - }) - - describe('Getting latest video source', () => { - const fixture = 'video_short.webm' - const uuids: string[] = [] - - it('Should get the source filename with legacy upload', async function () { - this.timeout(30000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'legacy' }) - uuids.push(uuid) - - const source = await servers[0].videos.getSource({ id: uuid }) - expect(source.filename).to.equal(fixture) - }) - - it('Should get the source filename with resumable upload', async function () { - this.timeout(30000) - - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'resumable' }) - uuids.push(uuid) - - const source = await servers[0].videos.getSource({ id: uuid }) - expect(source.filename).to.equal(fixture) - }) - - after(async function () { - this.timeout(60000) - - for (const uuid of uuids) { - await servers[0].videos.remove({ id: uuid }) - } - - await waitJobs(servers) - }) - }) - - describe('Updating video source', function () { - - describe('Filesystem', function () { - - it('Should replace a video file with transcoding disabled', async function () { - this.timeout(120000) - - await servers[0].config.disableTranscoding() - - const { uuid } = await servers[0].videos.quickUpload({ name: 'fs without transcoding', fixture: 'video_short_720p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(1) - expect(files[0].resolution.id).to.equal(720) - } - - await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(1) - expect(files[0].resolution.id).to.equal(360) - } - }) - - it('Should replace a video file with transcoding enabled', async function () { - this.timeout(120000) - - const previousPaths: string[] = [] - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - - const { uuid: videoUUID } = await servers[0].videos.quickUpload({ name: 'fs with transcoding', fixture: 'video_short_720p.mp4' }) - uuid = videoUUID - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - expect(video.inputFileUpdatedAt).to.be.null - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(6 * 2) - - // Grab old paths to ensure we'll regenerate - - previousPaths.push(video.previewPath) - previousPaths.push(video.thumbnailPath) - - for (const file of files) { - previousPaths.push(file.fileUrl) - previousPaths.push(file.torrentUrl) - previousPaths.push(file.metadataUrl) - - const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) - previousPaths.push(JSON.stringify(metadata)) - } - - const { storyboards } = await server.storyboard.list({ id: uuid }) - for (const s of storyboards) { - previousPaths.push(s.storyboardPath) - } - } - - replaceDate = new Date() - - await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - expect(video.inputFileUpdatedAt).to.not.be.null - expect(new Date(video.inputFileUpdatedAt)).to.be.above(replaceDate) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(4 * 2) - - expect(previousPaths).to.not.include(video.previewPath) - expect(previousPaths).to.not.include(video.thumbnailPath) - - await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - - for (const file of files) { - expect(previousPaths).to.not.include(file.fileUrl) - expect(previousPaths).to.not.include(file.torrentUrl) - expect(previousPaths).to.not.include(file.metadataUrl) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) - - const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) - expect(previousPaths).to.not.include(JSON.stringify(metadata)) - } - - const { storyboards } = await server.storyboard.list({ id: uuid }) - for (const s of storyboards) { - expect(previousPaths).to.not.include(s.storyboardPath) - - await makeGetRequest({ url: server.url, path: s.storyboardPath, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - await servers[0].config.enableMinimumTranscoding() - }) - - it('Should have cleaned up old files', async function () { - { - const count = await servers[0].servers.countFiles('storyboards') - expect(count).to.equal(2) - } - - { - const count = await servers[0].servers.countFiles('web-videos') - expect(count).to.equal(5 + 1) // +1 for private directory - } - - { - const count = await servers[0].servers.countFiles('streaming-playlists/hls') - expect(count).to.equal(1 + 1) // +1 for private directory - } - - { - const count = await servers[0].servers.countFiles('torrents') - expect(count).to.equal(9) - } - }) - - it('Should have the correct source input', async function () { - const source = await servers[0].videos.getSource({ id: uuid }) - - expect(source.filename).to.equal('video_short_360p.mp4') - expect(new Date(source.createdAt)).to.be.above(replaceDate) - }) - - it('Should not have regenerated miniatures that were previously uploaded', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.upload({ - attributes: { - name: 'custom miniatures', - thumbnailfile: 'custom-thumbnail.jpg', - previewfile: 'custom-preview.jpg' - } - }) - - await waitJobs(servers) - - const previousPaths: string[] = [] - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - previousPaths.push(video.previewPath) - previousPaths.push(video.thumbnailPath) - - await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - } - - await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - expect(previousPaths).to.include(video.previewPath) - expect(previousPaths).to.include(video.thumbnailPath) - - await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) - await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - }) - - describe('Autoblacklist', function () { - - function updateAutoBlacklist (enabled: boolean) { - return servers[0].config.updateExistingSubConfig({ - newConfig: { - autoBlacklist: { - videos: { - ofUsers: { - enabled - } - } - } - } - }) - } - - async function expectBlacklist (uuid: string, value: boolean) { - const video = await servers[0].videos.getWithToken({ id: uuid }) - - expect(video.blacklisted).to.equal(value) - } - - before(async function () { - await updateAutoBlacklist(true) - }) - - it('Should auto blacklist an unblacklisted video after file replacement', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) - await waitJobs(servers) - await expectBlacklist(uuid, true) - - await servers[0].blacklist.remove({ videoId: uuid }) - await expectBlacklist(uuid, false) - - await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - await expectBlacklist(uuid, true) - }) - - it('Should auto blacklist an already blacklisted video after file replacement', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) - await waitJobs(servers) - await expectBlacklist(uuid, true) - - await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - await expectBlacklist(uuid, true) - }) - - it('Should not auto blacklist if auto blacklist has been disabled between the upload and the replacement', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) - await waitJobs(servers) - await expectBlacklist(uuid, true) - - await servers[0].blacklist.remove({ videoId: uuid }) - await expectBlacklist(uuid, false) - - await updateAutoBlacklist(false) - - await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short1.webm' }) - await waitJobs(servers) - - await expectBlacklist(uuid, false) - }) - }) - - describe('With object storage enabled', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(120000) - - const configOverride = objectStorage.getDefaultMockConfig() - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - await servers[0].run(configOverride) - }) - - it('Should replace a video file with transcoding disabled', async function () { - this.timeout(120000) - - await servers[0].config.disableTranscoding() - - const { uuid } = await servers[0].videos.quickUpload({ - name: 'object storage without transcoding', - fixture: 'video_short_720p.mp4' - }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(1) - expect(files[0].resolution.id).to.equal(720) - expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - - await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(1) - expect(files[0].resolution.id).to.equal(360) - expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - }) - - it('Should replace a video file with transcoding enabled', async function () { - this.timeout(120000) - - const previousPaths: string[] = [] - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - - const { uuid: videoUUID } = await servers[0].videos.quickUpload({ - name: 'object storage with transcoding', - fixture: 'video_short_360p.mp4' - }) - uuid = videoUUID - - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(4 * 2) - - for (const file of files) { - previousPaths.push(file.fileUrl) - } - - for (const file of video.files) { - expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - - for (const file of video.streamingPlaylists[0].files) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - } - } - - await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_240p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - - const files = getAllFiles(video) - expect(files).to.have.lengthOf(3 * 2) - - for (const file of files) { - expect(previousPaths).to.not.include(file.fileUrl) - } - - for (const file of video.files) { - expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - - for (const file of video.streamingPlaylists[0].files) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - } - } - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/video-static-file-privacy.ts b/server/tests/api/videos/video-static-file-privacy.ts deleted file mode 100644 index 0a9864134..000000000 --- a/server/tests/api/videos/video-static-file-privacy.ts +++ /dev/null @@ -1,600 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { decode } from 'magnet-uri' -import { checkVideoFileTokenReinjection, expectStartWith, parseTorrentVideo } from '@server/tests/shared' -import { getAllFiles, wait } from '@shared/core-utils' -import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - findExternalSavedVideo, - makeRawRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -describe('Test video static file privacy', function () { - let server: PeerTubeServer - let userToken: string - - before(async function () { - this.timeout(50000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - userToken = await server.users.generateUserAndToken('user1') - }) - - describe('VOD static file path', function () { - - function runSuite () { - - async function checkPrivateFiles (uuid: string) { - const video = await server.videos.getWithToken({ id: uuid }) - - for (const file of video.files) { - expect(file.fileDownloadUrl).to.not.include('/private/') - expectStartWith(file.fileUrl, server.url + '/static/web-videos/private/') - - const torrent = await parseTorrentVideo(server, file) - expect(torrent.urlList).to.have.lengthOf(0) - - const magnet = decode(file.magnetUri) - expect(magnet.urlList).to.have.lengthOf(0) - - await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - } - - const hls = video.streamingPlaylists[0] - if (hls) { - expectStartWith(hls.playlistUrl, server.url + '/static/streaming-playlists/hls/private/') - expectStartWith(hls.segmentsSha256Url, server.url + '/static/streaming-playlists/hls/private/') - - await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - async function checkPublicFiles (uuid: string) { - const video = await server.videos.get({ id: uuid }) - - for (const file of getAllFiles(video)) { - expect(file.fileDownloadUrl).to.not.include('/private/') - expect(file.fileUrl).to.not.include('/private/') - - const torrent = await parseTorrentVideo(server, file) - expect(torrent.urlList[0]).to.not.include('private') - - const magnet = decode(file.magnetUri) - expect(magnet.urlList[0]).to.not.include('private') - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: torrent.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: magnet.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) - } - - const hls = video.streamingPlaylists[0] - if (hls) { - expect(hls.playlistUrl).to.not.include('private') - expect(hls.segmentsSha256Url).to.not.include('private') - - await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - it('Should upload a private/internal/password protected video and have a private static path', async function () { - this.timeout(120000) - - for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy }) - await waitJobs([ server ]) - - await checkPrivateFiles(uuid) - } - - const { uuid } = await server.videos.quickUpload({ - name: 'video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ 'my super password' ] - }) - await waitJobs([ server ]) - - await checkPrivateFiles(uuid) - }) - - it('Should upload a public video and update it as private/internal to have a private static path', async function () { - this.timeout(120000) - - for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PUBLIC }) - await waitJobs([ server ]) - - await server.videos.update({ id: uuid, attributes: { privacy } }) - await waitJobs([ server ]) - - await checkPrivateFiles(uuid) - } - }) - - it('Should upload a private video and update it to unlisted to have a public static path', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - await waitJobs([ server ]) - - await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.UNLISTED } }) - await waitJobs([ server ]) - - await checkPublicFiles(uuid) - }) - - it('Should upload an internal video and update it to public to have a public static path', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) - await waitJobs([ server ]) - - await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) - await waitJobs([ server ]) - - await checkPublicFiles(uuid) - }) - - it('Should upload an internal video and schedule a public publish', async function () { - this.timeout(120000) - - const attributes = { - name: 'video', - privacy: VideoPrivacy.PRIVATE, - scheduleUpdate: { - updateAt: new Date(Date.now() + 1000).toISOString(), - privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC - } - } - - const { uuid } = await server.videos.upload({ attributes }) - - await waitJobs([ server ]) - await wait(1000) - await server.debug.sendCommand({ body: { command: 'process-update-videos-scheduler' } }) - - await waitJobs([ server ]) - - await checkPublicFiles(uuid) - }) - } - - describe('Without transcoding', function () { - runSuite() - }) - - describe('With transcoding', function () { - - before(async function () { - await server.config.enableMinimumTranscoding() - }) - - runSuite() - }) - }) - - describe('VOD static file right check', function () { - let unrelatedFileToken: string - - async function checkVideoFiles (options: { - id: string - expectedStatus: HttpStatusCode - token: string - videoFileToken: string - videoPassword?: string - }) { - const { id, expectedStatus, token, videoFileToken, videoPassword } = options - - const video = await server.videos.getWithToken({ id }) - - for (const file of getAllFiles(video)) { - await makeRawRequest({ url: file.fileUrl, token, expectedStatus }) - await makeRawRequest({ url: file.fileDownloadUrl, token, expectedStatus }) - - await makeRawRequest({ url: file.fileUrl, query: { videoFileToken }, expectedStatus }) - await makeRawRequest({ url: file.fileDownloadUrl, query: { videoFileToken }, expectedStatus }) - - if (videoPassword) { - const headers = { 'x-peertube-video-password': videoPassword } - await makeRawRequest({ url: file.fileUrl, headers, expectedStatus }) - await makeRawRequest({ url: file.fileDownloadUrl, headers, expectedStatus }) - } - } - - const hls = video.streamingPlaylists[0] - await makeRawRequest({ url: hls.playlistUrl, token, expectedStatus }) - await makeRawRequest({ url: hls.segmentsSha256Url, token, expectedStatus }) - - await makeRawRequest({ url: hls.playlistUrl, query: { videoFileToken }, expectedStatus }) - await makeRawRequest({ url: hls.segmentsSha256Url, query: { videoFileToken }, expectedStatus }) - - if (videoPassword) { - const headers = { 'x-peertube-video-password': videoPassword } - await makeRawRequest({ url: hls.playlistUrl, token: null, headers, expectedStatus }) - await makeRawRequest({ url: hls.segmentsSha256Url, token: null, headers, expectedStatus }) - } - } - - before(async function () { - await server.config.enableMinimumTranscoding() - - const { uuid } = await server.videos.quickUpload({ name: 'another video' }) - unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - }) - - it('Should not be able to access a private video files without OAuth token and file token', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - await waitJobs([ server ]) - - await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: null, videoFileToken: null }) - }) - - it('Should not be able to access password protected video files without OAuth token, file token and password', async function () { - this.timeout(120000) - const videoPassword = 'my super password' - - const { uuid } = await server.videos.quickUpload({ - name: 'password protected video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ videoPassword ] - }) - await waitJobs([ server ]) - - await checkVideoFiles({ - id: uuid, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - token: null, - videoFileToken: null, - videoPassword: null - }) - }) - - it('Should not be able to access an password video files with incorrect OAuth token, file token and password', async function () { - this.timeout(120000) - const videoPassword = 'my super password' - - const { uuid } = await server.videos.quickUpload({ - name: 'password protected video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ videoPassword ] - }) - await waitJobs([ server ]) - - await checkVideoFiles({ - id: uuid, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - token: userToken, - videoFileToken: unrelatedFileToken, - videoPassword: 'incorrectPassword' - }) - }) - - it('Should not be able to access an private video files without appropriate OAuth token and file token', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - await waitJobs([ server ]) - - await checkVideoFiles({ - id: uuid, - expectedStatus: HttpStatusCode.FORBIDDEN_403, - token: userToken, - videoFileToken: unrelatedFileToken - }) - }) - - it('Should be able to access a private video files with appropriate OAuth token or file token', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - - await waitJobs([ server ]) - - await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) - }) - - it('Should be able to access a password protected video files with appropriate OAuth token or file token', async function () { - this.timeout(120000) - const videoPassword = 'my super password' - - const { uuid } = await server.videos.quickUpload({ - name: 'video', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ videoPassword ] - }) - - const videoFileToken = await server.videoToken.getVideoFileToken({ token: null, videoId: uuid, videoPassword }) - - await waitJobs([ server ]) - - await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken, videoPassword }) - }) - - it('Should reinject video file token', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) - - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - await waitJobs([ server ]) - - { - const video = await server.videos.getWithToken({ id: uuid }) - const hls = video.streamingPlaylists[0] - const query = { videoFileToken } - const { text } = await makeRawRequest({ url: hls.playlistUrl, query, expectedStatus: HttpStatusCode.OK_200 }) - - expect(text).to.not.include(videoFileToken) - } - - { - await checkVideoFileTokenReinjection({ - server, - videoUUID: uuid, - videoFileToken, - resolutions: [ 240, 720 ], - isLive: false - }) - } - }) - - it('Should be able to access a private video of another user with an admin OAuth token or file token', async function () { - this.timeout(120000) - - const { uuid } = await server.videos.quickUpload({ name: 'video', token: userToken, privacy: VideoPrivacy.PRIVATE }) - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - - await waitJobs([ server ]) - - await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) - }) - }) - - describe('Live static file path and check', function () { - let normalLiveId: string - let normalLive: LiveVideo - - let permanentLiveId: string - let permanentLive: LiveVideo - - let passwordProtectedLiveId: string - let passwordProtectedLive: LiveVideo - - const correctPassword = 'my super password' - - let unrelatedFileToken: string - - async function checkLiveFiles (options: { live: LiveVideo, liveId: string, videoPassword?: string }) { - const { live, liveId, videoPassword } = options - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await server.live.waitUntilPublished({ videoId: liveId }) - - const video = await server.videos.getWithToken({ id: liveId }) - - const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) - - const hls = video.streamingPlaylists[0] - - for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { - expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') - - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - - if (videoPassword) { - await makeRawRequest({ url, headers: { 'x-peertube-video-password': videoPassword }, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ - url, - headers: { 'x-peertube-video-password': 'incorrectPassword' }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - - } - - await stopFfmpeg(ffmpegCommand) - } - - async function checkReplay (replay: VideoDetails) { - const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) - - const hls = replay.streamingPlaylists[0] - expect(hls.files).to.not.have.lengthOf(0) - - for (const file of hls.files) { - await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ - url: file.fileUrl, - query: { videoFileToken: unrelatedFileToken }, - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - } - - for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { - expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') - - await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) - - await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - } - } - - before(async function () { - await server.config.enableMinimumTranscoding() - - const { uuid } = await server.videos.quickUpload({ name: 'another video' }) - unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) - - await server.config.enableLive({ - allowReplay: true, - transcoding: true, - resolutions: 'min' - }) - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: true, - permanentLive: false, - privacy: VideoPrivacy.PRIVATE - }) - normalLiveId = video.uuid - normalLive = live - } - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: true, - permanentLive: true, - privacy: VideoPrivacy.PRIVATE - }) - permanentLiveId = video.uuid - permanentLive = live - } - - { - const { video, live } = await server.live.quickCreate({ - saveReplay: false, - permanentLive: false, - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ correctPassword ] - }) - passwordProtectedLiveId = video.uuid - passwordProtectedLive = live - } - }) - - it('Should create a private normal live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles({ live: normalLive, liveId: normalLiveId }) - }) - - it('Should create a private permanent live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles({ live: permanentLive, liveId: permanentLiveId }) - }) - - it('Should create a password protected live and have a private static path', async function () { - this.timeout(240000) - - await checkLiveFiles({ live: passwordProtectedLive, liveId: passwordProtectedLiveId, videoPassword: correctPassword }) - }) - - it('Should reinject video file token on permanent live', async function () { - this.timeout(240000) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: permanentLive.rtmpUrl, streamKey: permanentLive.streamKey }) - await server.live.waitUntilPublished({ videoId: permanentLiveId }) - - const video = await server.videos.getWithToken({ id: permanentLiveId }) - const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) - const hls = video.streamingPlaylists[0] - - { - const query = { videoFileToken } - const { text } = await makeRawRequest({ url: hls.playlistUrl, query, expectedStatus: HttpStatusCode.OK_200 }) - - expect(text).to.not.include(videoFileToken) - } - - { - await checkVideoFileTokenReinjection({ - server, - videoUUID: permanentLiveId, - videoFileToken, - resolutions: [ 720 ], - isLive: true - }) - } - - await stopFfmpeg(ffmpegCommand) - }) - - it('Should have created a replay of the normal live with a private static path', async function () { - this.timeout(240000) - - await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) - - const replay = await server.videos.getWithToken({ id: normalLiveId }) - await checkReplay(replay) - }) - - it('Should have created a replay of the permanent live with a private static path', async function () { - this.timeout(240000) - - await server.live.waitUntilWaiting({ videoId: permanentLiveId }) - await waitJobs([ server ]) - - const live = await server.videos.getWithToken({ id: permanentLiveId }) - const replayFromList = await findExternalSavedVideo(server, live) - const replay = await server.videos.getWithToken({ id: replayFromList.id }) - - await checkReplay(replay) - }) - }) - - describe('With static file right check disabled', function () { - let videoUUID: string - - before(async function () { - this.timeout(240000) - - await server.kill() - - await server.run({ - static_files: { - private_files_require_auth: false - } - }) - - const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) - videoUUID = uuid - - await waitJobs([ server ]) - }) - - it('Should not check auth for private static files', async function () { - const video = await server.videos.getWithToken({ id: videoUUID }) - - for (const file of getAllFiles(video)) { - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - const hls = video.streamingPlaylists[0] - await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/video-storyboard.ts b/server/tests/api/videos/video-storyboard.ts deleted file mode 100644 index 07f371cad..000000000 --- a/server/tests/api/videos/video-storyboard.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readdir } from 'fs-extra' -import { basename } from 'path' -import { FIXTURE_URLS } from '@server/tests/shared' -import { areHttpImportTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - sendRTMPStream, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -async function checkStoryboard (options: { - server: PeerTubeServer - uuid: string - tilesCount?: number - minSize?: number -}) { - const { server, uuid, tilesCount, minSize = 1000 } = options - - const { storyboards } = await server.storyboard.list({ id: uuid }) - - expect(storyboards).to.have.lengthOf(1) - - const storyboard = storyboards[0] - - expect(storyboard.spriteDuration).to.equal(1) - expect(storyboard.spriteHeight).to.equal(108) - expect(storyboard.spriteWidth).to.equal(192) - expect(storyboard.storyboardPath).to.exist - - if (tilesCount) { - expect(storyboard.totalWidth).to.equal(192 * Math.min(tilesCount, 10)) - expect(storyboard.totalHeight).to.equal(108 * Math.max((tilesCount / 10), 1)) - } - - const { body } = await makeGetRequest({ url: server.url, path: storyboard.storyboardPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(body.length).to.be.above(minSize) -} - -describe('Test video storyboard', function () { - let servers: PeerTubeServer[] - - let baseUUID: string - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should generate a storyboard after upload without transcoding', async function () { - this.timeout(120000) - - // 5s video - const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_short.webm' }) - baseUUID = uuid - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid, tilesCount: 5 }) - } - }) - - it('Should generate a storyboard after upload without transcoding with a long video', async function () { - this.timeout(120000) - - // 124s video - const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_very_long_10p.mp4' }) - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid, tilesCount: 100 }) - } - }) - - it('Should generate a storyboard after upload with transcoding', async function () { - this.timeout(120000) - - await servers[0].config.enableMinimumTranscoding() - - // 5s video - const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_short.webm' }) - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid, tilesCount: 5 }) - } - }) - - it('Should generate a storyboard after an audio upload', async function () { - this.timeout(120000) - - // 6s audio - const attributes = { name: 'audio', fixture: 'sample.ogg' } - const { uuid } = await servers[0].videos.upload({ attributes, mode: 'legacy' }) - await waitJobs(servers) - - for (const server of servers) { - try { - await checkStoryboard({ server, uuid, tilesCount: 6, minSize: 250 }) - } catch { // FIXME: to remove after ffmpeg CI upgrade, ffmpeg CI version (4.3) generates a 7.6s length video - await checkStoryboard({ server, uuid, tilesCount: 8, minSize: 250 }) - } - } - }) - - it('Should generate a storyboard after HTTP import', async function () { - this.timeout(120000) - - if (areHttpImportTestsDisabled()) return - - // 3s video - const { video } = await servers[0].imports.importVideo({ - attributes: { - targetUrl: FIXTURE_URLS.goodVideo, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - }) - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid: video.uuid, tilesCount: 3 }) - } - }) - - it('Should generate a storyboard after torrent import', async function () { - this.timeout(120000) - - if (areHttpImportTestsDisabled()) return - - // 10s video - const { video } = await servers[0].imports.importVideo({ - attributes: { - magnetUri: FIXTURE_URLS.magnet, - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - }) - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid: video.uuid, tilesCount: 10 }) - } - }) - - it('Should generate a storyboard after a live', async function () { - this.timeout(240000) - - await servers[0].config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' }) - - const { live, video } = await servers[0].live.quickCreate({ - saveReplay: true, - permanentLive: false, - privacy: VideoPrivacy.PUBLIC - }) - - const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) - await servers[0].live.waitUntilPublished({ videoId: video.id }) - - await stopFfmpeg(ffmpegCommand) - - await servers[0].live.waitUntilReplacedByReplay({ videoId: video.id }) - await waitJobs(servers) - - for (const server of servers) { - await checkStoryboard({ server, uuid: video.uuid }) - } - }) - - it('Should cleanup storyboards on video deletion', async function () { - this.timeout(60000) - - const { storyboards } = await servers[0].storyboard.list({ id: baseUUID }) - const storyboardName = basename(storyboards[0].storyboardPath) - - const listFiles = () => { - const storyboardPath = servers[0].getDirectoryPath('storyboards') - return readdir(storyboardPath) - } - - { - const storyboads = await listFiles() - expect(storyboads).to.include(storyboardName) - } - - await servers[0].videos.remove({ id: baseUUID }) - await waitJobs(servers) - - { - const storyboads = await listFiles() - expect(storyboads).to.not.include(storyboardName) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/videos-common-filters.ts b/server/tests/api/videos/videos-common-filters.ts deleted file mode 100644 index 48de7c537..000000000 --- a/server/tests/api/videos/videos-common-filters.ts +++ /dev/null @@ -1,489 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pick } from '@shared/core-utils' -import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test videos filter', function () { - let servers: PeerTubeServer[] - let paths: string[] - let remotePaths: string[] - - const subscriptionVideosPath = '/api/v1/users/me/subscriptions/videos' - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(240000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultAccountAvatar(servers) - - await servers[1].config.enableMinimumTranscoding() - - for (const server of servers) { - const moderator = { username: 'moderator', password: 'my super password' } - await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR }) - server['moderatorAccessToken'] = await server.login.getAccessToken(moderator) - - await server.videos.upload({ attributes: { name: 'public ' + server.serverNumber } }) - - { - const attributes = { name: 'unlisted ' + server.serverNumber, privacy: VideoPrivacy.UNLISTED } - await server.videos.upload({ attributes }) - } - - { - const attributes = { name: 'private ' + server.serverNumber, privacy: VideoPrivacy.PRIVATE } - await server.videos.upload({ attributes }) - } - - // Subscribing to itself - await server.subscriptions.add({ targetUri: 'root_channel@' + server.host }) - } - - await doubleFollow(servers[0], servers[1]) - - paths = [ - `/api/v1/video-channels/root_channel/videos`, - `/api/v1/accounts/root/videos`, - '/api/v1/videos', - '/api/v1/search/videos', - subscriptionVideosPath - ] - - remotePaths = [ - `/api/v1/video-channels/root_channel@${servers[1].host}/videos`, - `/api/v1/accounts/root@${servers[1].host}/videos`, - '/api/v1/videos', - '/api/v1/search/videos' - ] - }) - - describe('Check videos filters', function () { - - async function listVideos (options: { - server: PeerTubeServer - path: string - isLocal?: boolean - hasWebVideoFiles?: boolean - hasHLSFiles?: boolean - include?: VideoInclude - privacyOneOf?: VideoPrivacy[] - category?: number - tagsAllOf?: string[] - token?: string - expectedStatus?: HttpStatusCode - excludeAlreadyWatched?: boolean - }) { - const res = await makeGetRequest({ - url: options.server.url, - path: options.path, - token: options.token ?? options.server.accessToken, - query: { - ...pick(options, [ - 'isLocal', - 'include', - 'category', - 'tagsAllOf', - 'hasWebVideoFiles', - 'hasHLSFiles', - 'privacyOneOf', - 'excludeAlreadyWatched' - ]), - - sort: 'createdAt' - }, - expectedStatus: options.expectedStatus ?? HttpStatusCode.OK_200 - }) - - return res.body.data as Video[] - } - - async function getVideosNames ( - options: { - server: PeerTubeServer - isLocal?: boolean - include?: VideoInclude - privacyOneOf?: VideoPrivacy[] - token?: string - expectedStatus?: HttpStatusCode - skipSubscription?: boolean - excludeAlreadyWatched?: boolean - } - ) { - const { skipSubscription = false } = options - const videosResults: string[][] = [] - - for (const path of paths) { - if (skipSubscription && path === subscriptionVideosPath) continue - - const videos = await listVideos({ ...options, path }) - - videosResults.push(videos.map(v => v.name)) - } - - return videosResults - } - - it('Should display local videos', async function () { - for (const server of servers) { - const namesResults = await getVideosNames({ server, isLocal: true }) - - for (const names of namesResults) { - expect(names).to.have.lengthOf(1) - expect(names[0]).to.equal('public ' + server.serverNumber) - } - } - }) - - it('Should display local videos with hidden privacy by the admin or the moderator', async function () { - for (const server of servers) { - for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) { - - const namesResults = await getVideosNames( - { - server, - token, - isLocal: true, - privacyOneOf: [ VideoPrivacy.UNLISTED, VideoPrivacy.PUBLIC, VideoPrivacy.PRIVATE ], - skipSubscription: true - } - ) - - for (const names of namesResults) { - expect(names).to.have.lengthOf(3) - - expect(names[0]).to.equal('public ' + server.serverNumber) - expect(names[1]).to.equal('unlisted ' + server.serverNumber) - expect(names[2]).to.equal('private ' + server.serverNumber) - } - } - } - }) - - it('Should display all videos by the admin or the moderator', async function () { - for (const server of servers) { - for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) { - - const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames({ - server, - token, - privacyOneOf: [ VideoPrivacy.UNLISTED, VideoPrivacy.PUBLIC, VideoPrivacy.PRIVATE ] - }) - - expect(channelVideos).to.have.lengthOf(3) - expect(accountVideos).to.have.lengthOf(3) - - expect(videos).to.have.lengthOf(5) - expect(searchVideos).to.have.lengthOf(5) - } - } - }) - - it('Should display only remote videos', async function () { - this.timeout(120000) - - await servers[1].videos.upload({ attributes: { name: 'remote video' } }) - - await waitJobs(servers) - - const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video') - - for (const path of remotePaths) { - { - const videos = await listVideos({ server: servers[0], path }) - const video = finder(videos) - expect(video).to.exist - } - - { - const videos = await listVideos({ server: servers[0], path, isLocal: false }) - const video = finder(videos) - expect(video).to.exist - } - - { - const videos = await listVideos({ server: servers[0], path, isLocal: true }) - const video = finder(videos) - expect(video).to.not.exist - } - } - }) - - it('Should include not published videos', async function () { - await servers[0].config.enableLive({ allowReplay: false, transcoding: false }) - await servers[0].live.create({ fields: { name: 'live video', channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC } }) - - const finder = (videos: Video[]) => videos.find(v => v.name === 'live video') - - for (const path of paths) { - { - const videos = await listVideos({ server: servers[0], path }) - const video = finder(videos) - expect(video).to.not.exist - expect(videos[0].state).to.not.exist - expect(videos[0].waitTranscoding).to.not.exist - } - - { - const videos = await listVideos({ server: servers[0], path, include: VideoInclude.NOT_PUBLISHED_STATE }) - const video = finder(videos) - expect(video).to.exist - expect(video.state).to.exist - } - } - }) - - it('Should include blacklisted videos', async function () { - const { id } = await servers[0].videos.upload({ attributes: { name: 'blacklisted' } }) - - await servers[0].blacklist.add({ videoId: id }) - - const finder = (videos: Video[]) => videos.find(v => v.name === 'blacklisted') - - for (const path of paths) { - { - const videos = await listVideos({ server: servers[0], path }) - const video = finder(videos) - expect(video).to.not.exist - expect(videos[0].blacklisted).to.not.exist - } - - { - const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLACKLISTED }) - const video = finder(videos) - expect(video).to.exist - expect(video.blacklisted).to.be.true - } - } - }) - - it('Should include videos from muted account', async function () { - const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video') - - await servers[0].blocklist.addToServerBlocklist({ account: 'root@' + servers[1].host }) - - for (const path of remotePaths) { - { - const videos = await listVideos({ server: servers[0], path }) - const video = finder(videos) - expect(video).to.not.exist - - // Some paths won't have videos - if (videos[0]) { - expect(videos[0].blockedOwner).to.not.exist - expect(videos[0].blockedServer).to.not.exist - } - } - - { - const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER }) - - const video = finder(videos) - expect(video).to.exist - expect(video.blockedServer).to.be.false - expect(video.blockedOwner).to.be.true - } - } - - await servers[0].blocklist.removeFromServerBlocklist({ account: 'root@' + servers[1].host }) - }) - - it('Should include videos from muted server', async function () { - const finder = (videos: Video[]) => videos.find(v => v.name === 'remote video') - - await servers[0].blocklist.addToServerBlocklist({ server: servers[1].host }) - - for (const path of remotePaths) { - { - const videos = await listVideos({ server: servers[0], path }) - const video = finder(videos) - expect(video).to.not.exist - - // Some paths won't have videos - if (videos[0]) { - expect(videos[0].blockedOwner).to.not.exist - expect(videos[0].blockedServer).to.not.exist - } - } - - { - const videos = await listVideos({ server: servers[0], path, include: VideoInclude.BLOCKED_OWNER }) - const video = finder(videos) - expect(video).to.exist - expect(video.blockedServer).to.be.true - expect(video.blockedOwner).to.be.false - } - } - - await servers[0].blocklist.removeFromServerBlocklist({ server: servers[1].host }) - }) - - it('Should include video files', async function () { - for (const path of paths) { - { - const videos = await listVideos({ server: servers[0], path }) - - for (const video of videos) { - const videoWithFiles = video as VideoDetails - - expect(videoWithFiles.files).to.not.exist - expect(videoWithFiles.streamingPlaylists).to.not.exist - } - } - - { - const videos = await listVideos({ server: servers[0], path, include: VideoInclude.FILES }) - - for (const video of videos) { - const videoWithFiles = video as VideoDetails - - expect(videoWithFiles.files).to.exist - expect(videoWithFiles.files).to.have.length.at.least(1) - } - } - } - }) - - it('Should filter by tags and category', async function () { - await servers[0].videos.upload({ attributes: { name: 'tag filter', tags: [ 'tag1', 'tag2' ] } }) - await servers[0].videos.upload({ attributes: { name: 'tag filter with category', tags: [ 'tag3' ], category: 4 } }) - - for (const path of paths) { - { - const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] }) - expect(videos).to.have.lengthOf(1) - expect(videos[0].name).to.equal('tag filter') - } - - { - const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag3' ] }) - expect(videos).to.have.lengthOf(0) - } - - { - const { data, total } = await servers[0].videos.list({ tagsAllOf: [ 'tag3' ], categoryOneOf: [ 4 ] }) - expect(total).to.equal(1) - expect(data[0].name).to.equal('tag filter with category') - } - - { - const { total } = await servers[0].videos.list({ tagsAllOf: [ 'tag4' ], categoryOneOf: [ 4 ] }) - expect(total).to.equal(0) - } - } - }) - - it('Should filter by HLS or Web Video files', async function () { - this.timeout(360000) - - const finderFactory = (name: string) => (videos: Video[]) => videos.some(v => v.name === name) - - await servers[0].config.enableTranscoding({ hls: false, webVideo: true }) - await servers[0].videos.upload({ attributes: { name: 'web video' } }) - const hasWebVideo = finderFactory('web video') - - await waitJobs(servers) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: false }) - await servers[0].videos.upload({ attributes: { name: 'hls video' } }) - const hasHLS = finderFactory('hls video') - - await waitJobs(servers) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - await servers[0].videos.upload({ attributes: { name: 'hls and web video' } }) - const hasBoth = finderFactory('hls and web video') - - await waitJobs(servers) - - for (const path of paths) { - { - const videos = await listVideos({ server: servers[0], path, hasWebVideoFiles: true }) - - expect(hasWebVideo(videos)).to.be.true - expect(hasHLS(videos)).to.be.false - expect(hasBoth(videos)).to.be.true - } - - { - const videos = await listVideos({ server: servers[0], path, hasWebVideoFiles: false }) - - expect(hasWebVideo(videos)).to.be.false - expect(hasHLS(videos)).to.be.true - expect(hasBoth(videos)).to.be.false - } - - { - const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true }) - - expect(hasWebVideo(videos)).to.be.false - expect(hasHLS(videos)).to.be.true - expect(hasBoth(videos)).to.be.true - } - - { - const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false }) - - expect(hasWebVideo(videos)).to.be.true - expect(hasHLS(videos)).to.be.false - expect(hasBoth(videos)).to.be.false - } - - { - const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false, hasWebVideoFiles: false }) - - expect(hasWebVideo(videos)).to.be.false - expect(hasHLS(videos)).to.be.false - expect(hasBoth(videos)).to.be.false - } - - { - const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true, hasWebVideoFiles: true }) - - expect(hasWebVideo(videos)).to.be.false - expect(hasHLS(videos)).to.be.false - expect(hasBoth(videos)).to.be.true - } - } - }) - - it('Should filter already watched videos by the user', async function () { - const { id } = await servers[0].videos.upload({ attributes: { name: 'video for history' } }) - - for (const path of paths) { - const videos = await listVideos({ server: servers[0], path, isLocal: true, excludeAlreadyWatched: true }) - const foundVideo = videos.find(video => video.id === id) - - expect(foundVideo).to.not.be.undefined - } - await servers[0].views.view({ id, currentTime: 1, token: servers[0].accessToken }) - - for (const path of paths) { - const videos = await listVideos({ server: servers[0], path, excludeAlreadyWatched: true }) - const foundVideo = videos.find(video => video.id === id) - - expect(foundVideo).to.be.undefined - } - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts deleted file mode 100644 index 6df26ab7d..000000000 --- a/server/tests/api/videos/videos-history.ts +++ /dev/null @@ -1,224 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { Video } from '@shared/models' -import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test videos history', function () { - let server: PeerTubeServer = null - let video1Id: number - let video1UUID: string - let video2UUID: string - let video3UUID: string - let video3WatchedDate: Date - let userAccessToken: string - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - // 10 seconds long - const fixture = 'video_short1.webm' - - { - const { id, uuid } = await server.videos.upload({ attributes: { name: 'video 1', fixture } }) - video1UUID = uuid - video1Id = id - } - - { - const { uuid } = await server.videos.upload({ attributes: { name: 'video 2', fixture } }) - video2UUID = uuid - } - - { - const { uuid } = await server.videos.upload({ attributes: { name: 'video 3', fixture } }) - video3UUID = uuid - } - - userAccessToken = await server.users.generateUserAndToken('user_1') - }) - - it('Should get videos, without watching history', async function () { - const { data } = await server.videos.listWithToken() - - for (const video of data) { - const videoDetails = await server.videos.getWithToken({ id: video.id }) - - expect(video.userHistory).to.be.undefined - expect(videoDetails.userHistory).to.be.undefined - } - }) - - it('Should watch the first and second video', async function () { - await server.views.view({ id: video2UUID, token: server.accessToken, currentTime: 8 }) - await server.views.view({ id: video1UUID, token: server.accessToken, currentTime: 3 }) - }) - - it('Should return the correct history when listing, searching and getting videos', async function () { - const videosOfVideos: Video[][] = [] - - { - const { data } = await server.videos.listWithToken() - videosOfVideos.push(data) - } - - { - const body = await server.search.searchVideos({ token: server.accessToken, search: 'video' }) - videosOfVideos.push(body.data) - } - - for (const videos of videosOfVideos) { - const video1 = videos.find(v => v.uuid === video1UUID) - const video2 = videos.find(v => v.uuid === video2UUID) - const video3 = videos.find(v => v.uuid === video3UUID) - - expect(video1.userHistory).to.not.be.undefined - expect(video1.userHistory.currentTime).to.equal(3) - - expect(video2.userHistory).to.not.be.undefined - expect(video2.userHistory.currentTime).to.equal(8) - - expect(video3.userHistory).to.be.undefined - } - - { - const videoDetails = await server.videos.getWithToken({ id: video1UUID }) - - expect(videoDetails.userHistory).to.not.be.undefined - expect(videoDetails.userHistory.currentTime).to.equal(3) - } - - { - const videoDetails = await server.videos.getWithToken({ id: video2UUID }) - - expect(videoDetails.userHistory).to.not.be.undefined - expect(videoDetails.userHistory.currentTime).to.equal(8) - } - - { - const videoDetails = await server.videos.getWithToken({ id: video3UUID }) - - expect(videoDetails.userHistory).to.be.undefined - } - }) - - it('Should have these videos when listing my history', async function () { - video3WatchedDate = new Date() - await server.views.view({ id: video3UUID, token: server.accessToken, currentTime: 2 }) - - const body = await server.history.list() - - expect(body.total).to.equal(3) - - const videos = body.data - expect(videos[0].name).to.equal('video 3') - expect(videos[1].name).to.equal('video 1') - expect(videos[2].name).to.equal('video 2') - }) - - it('Should not have videos history on another user', async function () { - const body = await server.history.list({ token: userAccessToken }) - - expect(body.total).to.equal(0) - expect(body.data).to.have.lengthOf(0) - }) - - it('Should be able to search through videos in my history', async function () { - const body = await server.history.list({ search: '2' }) - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos[0].name).to.equal('video 2') - }) - - it('Should clear my history', async function () { - await server.history.removeAll({ beforeDate: video3WatchedDate.toISOString() }) - }) - - it('Should have my history cleared', async function () { - const body = await server.history.list() - expect(body.total).to.equal(1) - - const videos = body.data - expect(videos[0].name).to.equal('video 3') - }) - - it('Should disable videos history', async function () { - await server.users.updateMe({ - videosHistoryEnabled: false - }) - - await server.views.view({ id: video2UUID, token: server.accessToken, currentTime: 8 }) - - const { data } = await server.history.list() - expect(data[0].name).to.not.equal('video 2') - }) - - it('Should re-enable videos history', async function () { - await server.users.updateMe({ - videosHistoryEnabled: true - }) - - await server.views.view({ id: video2UUID, token: server.accessToken, currentTime: 8 }) - - const { data } = await server.history.list() - expect(data[0].name).to.equal('video 2') - }) - - it('Should not clean old history', async function () { - this.timeout(50000) - - await killallServers([ server ]) - - await server.run({ history: { videos: { max_age: '10 days' } } }) - - await wait(6000) - - // Should still have history - - const body = await server.history.list() - expect(body.total).to.equal(2) - }) - - it('Should clean old history', async function () { - this.timeout(50000) - - await killallServers([ server ]) - - await server.run({ history: { videos: { max_age: '5 seconds' } } }) - - await wait(6000) - - const body = await server.history.list() - expect(body.total).to.equal(0) - }) - - it('Should delete a specific history element', async function () { - { - await server.views.view({ id: video1UUID, token: server.accessToken, currentTime: 4 }) - await server.views.view({ id: video2UUID, token: server.accessToken, currentTime: 8 }) - } - - { - const body = await server.history.list() - expect(body.total).to.equal(2) - } - - { - await server.history.removeElement({ videoId: video1Id }) - - const body = await server.history.list() - expect(body.total).to.equal(1) - expect(body.data[0].uuid).to.equal(video2UUID) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts deleted file mode 100644 index f2496e35e..000000000 --- a/server/tests/api/videos/videos-overview.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { VideosOverview } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test a videos overview', function () { - let server: PeerTubeServer = null - - function testOverviewCount (overview: VideosOverview, expected: number) { - expect(overview.tags).to.have.lengthOf(expected) - expect(overview.categories).to.have.lengthOf(expected) - expect(overview.channels).to.have.lengthOf(expected) - } - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - }) - - it('Should send empty overview', async function () { - const body = await server.overviews.getVideos({ page: 1 }) - - testOverviewCount(body, 0) - }) - - it('Should upload 5 videos in a specific category, tag and channel but not include them in overview', async function () { - this.timeout(60000) - - await wait(3000) - - await server.videos.upload({ - attributes: { - name: 'video 0', - category: 3, - tags: [ 'coucou1', 'coucou2' ] - } - }) - - const body = await server.overviews.getVideos({ page: 1 }) - - testOverviewCount(body, 0) - }) - - it('Should upload another video and include all videos in the overview', async function () { - this.timeout(120000) - - { - for (let i = 1; i < 6; i++) { - await server.videos.upload({ - attributes: { - name: 'video ' + i, - category: 3, - tags: [ 'coucou1', 'coucou2' ] - } - }) - } - - await wait(3000) - } - - { - const body = await server.overviews.getVideos({ page: 1 }) - - testOverviewCount(body, 1) - } - - { - const overview = await server.overviews.getVideos({ page: 2 }) - - expect(overview.tags).to.have.lengthOf(1) - expect(overview.categories).to.have.lengthOf(0) - expect(overview.channels).to.have.lengthOf(0) - } - }) - - it('Should have the correct overview', async function () { - const overview1 = await server.overviews.getVideos({ page: 1 }) - const overview2 = await server.overviews.getVideos({ page: 2 }) - - for (const arr of [ overview1.tags, overview1.categories, overview1.channels, overview2.tags ]) { - expect(arr).to.have.lengthOf(1) - - const obj = arr[0] - - expect(obj.videos).to.have.lengthOf(6) - expect(obj.videos[0].name).to.equal('video 5') - expect(obj.videos[1].name).to.equal('video 4') - expect(obj.videos[2].name).to.equal('video 3') - expect(obj.videos[3].name).to.equal('video 2') - expect(obj.videos[4].name).to.equal('video 1') - expect(obj.videos[5].name).to.equal('video 0') - } - - const tags = [ overview1.tags[0].tag, overview2.tags[0].tag ] - expect(tags.find(t => t === 'coucou1')).to.not.be.undefined - expect(tags.find(t => t === 'coucou2')).to.not.be.undefined - - expect(overview1.categories[0].category.id).to.equal(3) - - expect(overview1.channels[0].channel.name).to.equal('root_channel') - }) - - it('Should hide muted accounts', async function () { - const token = await server.users.generateUserAndToken('choco') - - await server.blocklist.addToMyBlocklist({ token, account: 'root@' + server.host }) - - { - const body = await server.overviews.getVideos({ page: 1 }) - - testOverviewCount(body, 1) - } - - { - const body = await server.overviews.getVideos({ page: 1, token }) - - testOverviewCount(body, 0) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/views/index.ts b/server/tests/api/views/index.ts deleted file mode 100644 index 5e06b31fb..000000000 --- a/server/tests/api/views/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './video-views-counter' -export * from './video-views-overall-stats' -export * from './video-views-retention-stats' -export * from './video-views-timeserie-stats' -export * from './videos-views-cleaner' diff --git a/server/tests/api/views/video-views-counter.ts b/server/tests/api/views/video-views-counter.ts deleted file mode 100644 index 0c1b7859c..000000000 --- a/server/tests/api/views/video-views-counter.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FfmpegCommand } from 'fluent-ffmpeg' -import { prepareViewsServers, prepareViewsVideos, processViewsBuffer } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { cleanupTests, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands' - -describe('Test video views/viewers counters', function () { - let servers: PeerTubeServer[] - - async function checkCounter (field: 'views' | 'viewers', id: string, expected: number) { - for (const server of servers) { - const video = await server.videos.get({ id }) - - const messageSuffix = video.isLive - ? 'live video' - : 'vod video' - - expect(video[field]).to.equal(expected, `${field} not valid on server ${server.serverNumber} for ${messageSuffix} ${video.uuid}`) - } - } - - before(async function () { - this.timeout(120000) - - servers = await prepareViewsServers() - }) - - describe('Test views counter on VOD', function () { - let videoUUID: string - - before(async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should not view a video if watch time is below the threshold', async function () { - await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 2 ] }) - await processViewsBuffer(servers) - - await checkCounter('views', videoUUID, 0) - }) - - it('Should view a video if watch time is above the threshold', async function () { - await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 4 ] }) - await processViewsBuffer(servers) - - await checkCounter('views', videoUUID, 1) - }) - - it('Should not view again this video with the same IP', async function () { - await servers[0].views.simulateViewer({ id: videoUUID, xForwardedFor: '0.0.0.1,127.0.0.1', currentTimes: [ 1, 4 ] }) - await servers[0].views.simulateViewer({ id: videoUUID, xForwardedFor: '0.0.0.1,127.0.0.1', currentTimes: [ 1, 4 ] }) - await processViewsBuffer(servers) - - await checkCounter('views', videoUUID, 2) - }) - - it('Should view the video from server 2 and send the event', async function () { - await servers[1].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 4 ] }) - await waitJobs(servers) - await processViewsBuffer(servers) - - await checkCounter('views', videoUUID, 3) - }) - }) - - describe('Test views and viewers counters on live and VOD', function () { - let liveVideoId: string - let vodVideoId: string - let command: FfmpegCommand - - before(async function () { - this.timeout(240000); - - ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) - }) - - it('Should display no views and viewers', async function () { - await checkCounter('views', liveVideoId, 0) - await checkCounter('viewers', liveVideoId, 0) - - await checkCounter('views', vodVideoId, 0) - await checkCounter('viewers', vodVideoId, 0) - }) - - it('Should view twice and display 1 view/viewer', async function () { - this.timeout(30000) - - await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) - await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) - await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - - await waitJobs(servers) - await checkCounter('viewers', liveVideoId, 1) - await checkCounter('viewers', vodVideoId, 1) - - await processViewsBuffer(servers) - - await checkCounter('views', liveVideoId, 1) - await checkCounter('views', vodVideoId, 1) - }) - - it('Should wait and display 0 viewers but still have 1 view', async function () { - this.timeout(30000) - - await wait(12000) - await waitJobs(servers) - - await checkCounter('views', liveVideoId, 1) - await checkCounter('viewers', liveVideoId, 0) - - await checkCounter('views', vodVideoId, 1) - await checkCounter('viewers', vodVideoId, 0) - }) - - it('Should view on a remote and on local and display 2 viewers and 3 views', async function () { - this.timeout(30000) - - await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - - await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) - await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) - await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) - - await waitJobs(servers) - - await checkCounter('viewers', liveVideoId, 2) - await checkCounter('viewers', vodVideoId, 2) - - await processViewsBuffer(servers) - - await checkCounter('views', liveVideoId, 3) - await checkCounter('views', vodVideoId, 3) - }) - - after(async function () { - await stopFfmpeg(command) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/views/video-views-overall-stats.ts b/server/tests/api/views/video-views-overall-stats.ts deleted file mode 100644 index ac636961e..000000000 --- a/server/tests/api/views/video-views-overall-stats.ts +++ /dev/null @@ -1,368 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FfmpegCommand } from 'fluent-ffmpeg' -import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared' -import { cleanupTests, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands' -import { wait } from '@shared/core-utils' -import { VideoStatsOverall } from '@shared/models' - -/** - * - * Simulate 5 sections of viewers - * * user0 started and ended before start date - * * user1 started before start date and ended in the interval - * * user2 started started in the interval and ended after end date - * * user3 started and ended in the interval - * * user4 started and ended after end date - */ -async function simulateComplexViewers (servers: PeerTubeServer[], videoUUID: string) { - const user0 = '8.8.8.8,127.0.0.1' - const user1 = '8.8.8.8,127.0.0.1' - const user2 = '8.8.8.9,127.0.0.1' - const user3 = '8.8.8.10,127.0.0.1' - const user4 = '8.8.8.11,127.0.0.1' - - await servers[0].views.view({ id: videoUUID, currentTime: 0, xForwardedFor: user0 }) // User 0 starts - await wait(500) - - await servers[0].views.view({ id: videoUUID, currentTime: 0, xForwardedFor: user1 }) // User 1 starts - await servers[0].views.view({ id: videoUUID, currentTime: 2, xForwardedFor: user0 }) // User 0 ends - await wait(500) - - const startDate = new Date().toISOString() - await servers[0].views.view({ id: videoUUID, currentTime: 0, xForwardedFor: user2 }) // User 2 starts - await wait(500) - - await servers[0].views.view({ id: videoUUID, currentTime: 0, xForwardedFor: user3 }) // User 3 starts - await wait(500) - - await servers[0].views.view({ id: videoUUID, currentTime: 4, xForwardedFor: user1 }) // User 1 ends - await wait(500) - - await servers[0].views.view({ id: videoUUID, currentTime: 3, xForwardedFor: user3 }) // User 3 ends - await wait(500) - - const endDate = new Date().toISOString() - await servers[0].views.view({ id: videoUUID, currentTime: 0, xForwardedFor: user4 }) // User 4 starts - await servers[0].views.view({ id: videoUUID, currentTime: 5, xForwardedFor: user2 }) // User 2 ends - await wait(500) - - await servers[0].views.view({ id: videoUUID, currentTime: 1, xForwardedFor: user4 }) // User 4 ends - - await processViewersStats(servers) - - return { startDate, endDate } -} - -describe('Test views overall stats', function () { - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(120000) - - servers = await prepareViewsServers() - }) - - describe('Test watch time stats of local videos on live and VOD', function () { - let vodVideoId: string - let liveVideoId: string - let command: FfmpegCommand - - before(async function () { - this.timeout(240000); - - ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) - }) - - it('Should display overall stats of a video with no viewers', async function () { - for (const videoId of [ liveVideoId, vodVideoId ]) { - const stats = await servers[0].videoStats.getOverallStats({ videoId }) - const video = await servers[0].videos.get({ id: videoId }) - - expect(video.views).to.equal(0) - expect(stats.averageWatchTime).to.equal(0) - expect(stats.totalWatchTime).to.equal(0) - expect(stats.totalViewers).to.equal(0) - } - }) - - it('Should display overall stats with 1 viewer below the watch time limit', async function () { - this.timeout(60000) - - for (const videoId of [ liveVideoId, vodVideoId ]) { - await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] }) - } - - await processViewersStats(servers) - - for (const videoId of [ liveVideoId, vodVideoId ]) { - const stats = await servers[0].videoStats.getOverallStats({ videoId }) - const video = await servers[0].videos.get({ id: videoId }) - - expect(video.views).to.equal(0) - expect(stats.averageWatchTime).to.equal(1) - expect(stats.totalWatchTime).to.equal(1) - expect(stats.totalViewers).to.equal(1) - } - }) - - it('Should display overall stats with 2 viewers', async function () { - this.timeout(60000) - - { - await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 3 ] }) - await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35, 40 ] }) - - await processViewersStats(servers) - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId }) - const video = await servers[0].videos.get({ id: vodVideoId }) - - expect(video.views).to.equal(1) - expect(stats.averageWatchTime).to.equal(2) - expect(stats.totalWatchTime).to.equal(4) - expect(stats.totalViewers).to.equal(2) - } - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId }) - const video = await servers[0].videos.get({ id: liveVideoId }) - - expect(video.views).to.equal(1) - expect(stats.averageWatchTime).to.equal(21) - expect(stats.totalWatchTime).to.equal(41) - expect(stats.totalViewers).to.equal(2) - } - } - }) - - it('Should display overall stats with a remote viewer below the watch time limit', async function () { - this.timeout(60000) - - for (const videoId of [ liveVideoId, vodVideoId ]) { - await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 2 ] }) - } - - await processViewersStats(servers) - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId }) - const video = await servers[0].videos.get({ id: vodVideoId }) - - expect(video.views).to.equal(1) - expect(stats.averageWatchTime).to.equal(2) - expect(stats.totalWatchTime).to.equal(6) - expect(stats.totalViewers).to.equal(3) - } - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId }) - const video = await servers[0].videos.get({ id: liveVideoId }) - - expect(video.views).to.equal(1) - expect(stats.averageWatchTime).to.equal(14) - expect(stats.totalWatchTime).to.equal(43) - expect(stats.totalViewers).to.equal(3) - } - }) - - it('Should display overall stats with a remote viewer above the watch time limit', async function () { - this.timeout(60000) - - await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) - await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 45 ] }) - await processViewersStats(servers) - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId }) - const video = await servers[0].videos.get({ id: vodVideoId }) - - expect(video.views).to.equal(2) - expect(stats.averageWatchTime).to.equal(3) - expect(stats.totalWatchTime).to.equal(11) - expect(stats.totalViewers).to.equal(4) - } - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId }) - const video = await servers[0].videos.get({ id: liveVideoId }) - - expect(video.views).to.equal(2) - expect(stats.averageWatchTime).to.equal(22) - expect(stats.totalWatchTime).to.equal(88) - expect(stats.totalViewers).to.equal(4) - } - }) - - it('Should filter overall stats by date', async function () { - this.timeout(60000) - - const beforeView = new Date() - - await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 3 ] }) - await processViewersStats(servers) - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId, startDate: beforeView.toISOString() }) - expect(stats.averageWatchTime).to.equal(3) - expect(stats.totalWatchTime).to.equal(3) - expect(stats.totalViewers).to.equal(1) - } - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId, endDate: beforeView.toISOString() }) - expect(stats.averageWatchTime).to.equal(22) - expect(stats.totalWatchTime).to.equal(88) - expect(stats.totalViewers).to.equal(4) - } - }) - - after(async function () { - await stopFfmpeg(command) - }) - }) - - describe('Test watchers peak stats of local videos on VOD', function () { - let videoUUID: string - let before2Watchers: Date - - before(async function () { - this.timeout(240000); - - ({ vodVideoId: videoUUID } = await prepareViewsVideos({ servers, live: true, vod: true })) - }) - - it('Should not have watchers peak', async function () { - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID }) - - expect(stats.viewersPeak).to.equal(0) - expect(stats.viewersPeakDate).to.be.null - }) - - it('Should have watcher peak with 1 watcher', async function () { - this.timeout(60000) - - const before = new Date() - await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 0, 2 ] }) - const after = new Date() - - await processViewersStats(servers) - - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID }) - - expect(stats.viewersPeak).to.equal(1) - expect(new Date(stats.viewersPeakDate)).to.be.above(before).and.below(after) - }) - - it('Should have watcher peak with 2 watchers', async function () { - this.timeout(60000) - - before2Watchers = new Date() - await servers[0].views.view({ id: videoUUID, currentTime: 0 }) - await servers[1].views.view({ id: videoUUID, currentTime: 0 }) - await servers[0].views.view({ id: videoUUID, currentTime: 2 }) - await servers[1].views.view({ id: videoUUID, currentTime: 2 }) - const after = new Date() - - await processViewersStats(servers) - - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID }) - - expect(stats.viewersPeak).to.equal(2) - expect(new Date(stats.viewersPeakDate)).to.be.above(before2Watchers).and.below(after) - }) - - it('Should filter peak viewers stats by date', async function () { - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate: new Date().toISOString() }) - expect(stats.viewersPeak).to.equal(0) - expect(stats.viewersPeakDate).to.not.exist - } - - { - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, endDate: before2Watchers.toISOString() }) - expect(stats.viewersPeak).to.equal(1) - expect(new Date(stats.viewersPeakDate)).to.be.below(before2Watchers) - } - }) - - it('Should complex filter peak viewers by date', async function () { - this.timeout(60000) - - const { startDate, endDate } = await simulateComplexViewers(servers, videoUUID) - - const expectCorrect = (stats: VideoStatsOverall) => { - expect(stats.viewersPeak).to.equal(3) - expect(new Date(stats.viewersPeakDate)).to.be.above(new Date(startDate)).and.below(new Date(endDate)) - } - - expectCorrect(await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate, endDate })) - expectCorrect(await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate })) - expectCorrect(await servers[0].videoStats.getOverallStats({ videoId: videoUUID, endDate })) - expectCorrect(await servers[0].videoStats.getOverallStats({ videoId: videoUUID })) - }) - }) - - describe('Test countries', function () { - let videoUUID: string - - it('Should not report countries if geoip is disabled', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - await waitJobs(servers) - - await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 }) - - await processViewersStats(servers) - - const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid }) - expect(stats.countries).to.have.lengthOf(0) - }) - - it('Should report countries if geoip is enabled', async function () { - this.timeout(240000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - videoUUID = uuid - await waitJobs(servers) - - await Promise.all([ - servers[0].kill(), - servers[1].kill() - ]) - - const config = { geo_ip: { enabled: true } } - await Promise.all([ - servers[0].run(config), - servers[1].run(config) - ]) - - await servers[0].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 }) - await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.4,127.0.0.1', currentTime: 3 }) - await servers[1].views.view({ id: uuid, xForwardedFor: '80.67.169.12,127.0.0.1', currentTime: 2 }) - - await processViewersStats(servers) - - const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid }) - expect(stats.countries).to.have.lengthOf(2) - - expect(stats.countries[0].isoCode).to.equal('US') - expect(stats.countries[0].viewers).to.equal(2) - - expect(stats.countries[1].isoCode).to.equal('FR') - expect(stats.countries[1].viewers).to.equal(1) - }) - - it('Should filter countries stats by date', async function () { - const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate: new Date().toISOString() }) - expect(stats.countries).to.have.lengthOf(0) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/views/video-views-retention-stats.ts b/server/tests/api/views/video-views-retention-stats.ts deleted file mode 100644 index 5b9ce4c92..000000000 --- a/server/tests/api/views/video-views-retention-stats.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared' -import { cleanupTests, PeerTubeServer } from '@shared/server-commands' - -describe('Test views retention stats', function () { - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(120000) - - servers = await prepareViewsServers() - }) - - describe('Test retention stats on VOD', function () { - let vodVideoId: string - - before(async function () { - this.timeout(240000); - - ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) - }) - - it('Should display empty retention', async function () { - const { data } = await servers[0].videoStats.getRetentionStats({ videoId: vodVideoId }) - expect(data).to.have.lengthOf(6) - - for (let i = 0; i < 6; i++) { - expect(data[i].second).to.equal(i) - expect(data[i].retentionPercent).to.equal(0) - } - }) - - it('Should display appropriate retention metrics', async function () { - await servers[0].views.simulateViewer({ xForwardedFor: '127.0.0.2,127.0.0.1', id: vodVideoId, currentTimes: [ 0, 1 ] }) - await servers[0].views.simulateViewer({ xForwardedFor: '127.0.0.3,127.0.0.1', id: vodVideoId, currentTimes: [ 1, 3 ] }) - await servers[1].views.simulateViewer({ xForwardedFor: '127.0.0.2,127.0.0.1', id: vodVideoId, currentTimes: [ 4 ] }) - await servers[1].views.simulateViewer({ xForwardedFor: '127.0.0.3,127.0.0.1', id: vodVideoId, currentTimes: [ 0, 1 ] }) - - await processViewersStats(servers) - - const { data } = await servers[0].videoStats.getRetentionStats({ videoId: vodVideoId }) - expect(data).to.have.lengthOf(6) - - expect(data.map(d => d.retentionPercent)).to.deep.equal([ 50, 75, 25, 25, 25, 0 ]) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/views/video-views-timeserie-stats.ts b/server/tests/api/views/video-views-timeserie-stats.ts deleted file mode 100644 index 2d991d7ea..000000000 --- a/server/tests/api/views/video-views-timeserie-stats.ts +++ /dev/null @@ -1,253 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { FfmpegCommand } from 'fluent-ffmpeg' -import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared' -import { VideoStatsTimeserie, VideoStatsTimeserieMetric } from '@shared/models' -import { cleanupTests, PeerTubeServer, stopFfmpeg } from '@shared/server-commands' - -function buildOneMonthAgo () { - const monthAgo = new Date() - monthAgo.setHours(0, 0, 0, 0) - - monthAgo.setDate(monthAgo.getDate() - 29) - - return monthAgo -} - -describe('Test views timeserie stats', function () { - const availableMetrics: VideoStatsTimeserieMetric[] = [ 'viewers' ] - - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(120000) - - servers = await prepareViewsServers() - }) - - describe('Common metric tests', function () { - let vodVideoId: string - - before(async function () { - this.timeout(240000); - - ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) - }) - - it('Should display empty metric stats', async function () { - for (const metric of availableMetrics) { - const { data } = await servers[0].videoStats.getTimeserieStats({ videoId: vodVideoId, metric }) - - expect(data).to.have.length.at.least(1) - - for (const d of data) { - expect(d.value).to.equal(0) - } - } - }) - }) - - describe('Test viewer and watch time metrics on live and VOD', function () { - let vodVideoId: string - let liveVideoId: string - let command: FfmpegCommand - - function expectTodayLastValue (result: VideoStatsTimeserie, lastValue?: number) { - const { data } = result - - const last = data[data.length - 1] - const today = new Date().getDate() - expect(new Date(last.date).getDate()).to.equal(today) - - if (lastValue) expect(last.value).to.equal(lastValue) - } - - function expectTimeserieData (result: VideoStatsTimeserie, lastValue: number) { - const { data } = result - expect(data).to.have.length.at.least(25) - - expectTodayLastValue(result, lastValue) - - for (let i = 0; i < data.length - 2; i++) { - expect(data[i].value).to.equal(0) - } - } - - function expectInterval (result: VideoStatsTimeserie, intervalMs: number) { - const first = result.data[0] - const second = result.data[1] - expect(new Date(second.date).getTime() - new Date(first.date).getTime()).to.equal(intervalMs) - } - - before(async function () { - this.timeout(240000); - - ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) - }) - - it('Should display appropriate viewers metrics', async function () { - for (const videoId of [ vodVideoId, liveVideoId ]) { - await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 3 ] }) - await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 5 ] }) - } - - await processViewersStats(servers) - - for (const videoId of [ vodVideoId, liveVideoId ]) { - const result = await servers[0].videoStats.getTimeserieStats({ - videoId, - startDate: buildOneMonthAgo(), - endDate: new Date(), - metric: 'viewers' - }) - expectTimeserieData(result, 2) - } - }) - - it('Should display appropriate watch time metrics', async function () { - for (const videoId of [ vodVideoId, liveVideoId ]) { - const result = await servers[0].videoStats.getTimeserieStats({ - videoId, - startDate: buildOneMonthAgo(), - endDate: new Date(), - metric: 'aggregateWatchTime' - }) - expectTimeserieData(result, 8) - - await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] }) - } - - await processViewersStats(servers) - - for (const videoId of [ vodVideoId, liveVideoId ]) { - const result = await servers[0].videoStats.getTimeserieStats({ - videoId, - startDate: buildOneMonthAgo(), - endDate: new Date(), - metric: 'aggregateWatchTime' - }) - expectTimeserieData(result, 9) - } - }) - - it('Should use a custom start/end date', async function () { - const now = new Date() - const twentyDaysAgo = new Date() - twentyDaysAgo.setDate(twentyDaysAgo.getDate() - 19) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: twentyDaysAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('1 day') - expect(result.data).to.have.lengthOf(20) - - const first = result.data[0] - expect(new Date(first.date).toLocaleDateString()).to.equal(twentyDaysAgo.toLocaleDateString()) - - expectInterval(result, 24 * 3600 * 1000) - expectTodayLastValue(result, 9) - }) - - it('Should automatically group by months', async function () { - const now = new Date() - const heightYearsAgo = new Date() - heightYearsAgo.setFullYear(heightYearsAgo.getFullYear() - 7) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: heightYearsAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('6 months') - expect(result.data).to.have.length.above(10).and.below(200) - }) - - it('Should automatically group by days', async function () { - const now = new Date() - const threeMonthsAgo = new Date() - threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: threeMonthsAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('2 days') - expect(result.data).to.have.length.above(10).and.below(200) - }) - - it('Should automatically group by hours', async function () { - const now = new Date() - const twoDaysAgo = new Date() - twoDaysAgo.setDate(twoDaysAgo.getDate() - 1) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: twoDaysAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('1 hour') - expect(result.data).to.have.length.above(24).and.below(50) - - expectInterval(result, 3600 * 1000) - expectTodayLastValue(result, 9) - }) - - it('Should automatically group by ten minutes', async function () { - const now = new Date() - const twoHoursAgo = new Date() - twoHoursAgo.setHours(twoHoursAgo.getHours() - 4) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: twoHoursAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('10 minutes') - expect(result.data).to.have.length.above(20).and.below(30) - - expectInterval(result, 60 * 10 * 1000) - expectTodayLastValue(result) - }) - - it('Should automatically group by one minute', async function () { - const now = new Date() - const thirtyAgo = new Date() - thirtyAgo.setMinutes(thirtyAgo.getMinutes() - 30) - - const result = await servers[0].videoStats.getTimeserieStats({ - videoId: vodVideoId, - metric: 'aggregateWatchTime', - startDate: thirtyAgo, - endDate: now - }) - - expect(result.groupInterval).to.equal('1 minute') - expect(result.data).to.have.length.above(20).and.below(40) - - expectInterval(result, 60 * 1000) - expectTodayLastValue(result) - }) - - after(async function () { - await stopFfmpeg(command) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/api/views/videos-views-cleaner.ts b/server/tests/api/views/videos-views-cleaner.ts deleted file mode 100644 index a84cd43c7..000000000 --- a/server/tests/api/views/videos-views-cleaner.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { SQLCommand } from '@server/tests/shared' -import { wait } from '@shared/core-utils' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Test video views cleaner', function () { - let servers: PeerTubeServer[] - let sqlCommands: SQLCommand[] = [] - - let videoIdServer1: string - let videoIdServer2: string - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - videoIdServer1 = (await servers[0].videos.quickUpload({ name: 'video server 1' })).uuid - videoIdServer2 = (await servers[1].videos.quickUpload({ name: 'video server 2' })).uuid - - await waitJobs(servers) - - await servers[0].views.simulateView({ id: videoIdServer1 }) - await servers[1].views.simulateView({ id: videoIdServer1 }) - await servers[0].views.simulateView({ id: videoIdServer2 }) - await servers[1].views.simulateView({ id: videoIdServer2 }) - - await waitJobs(servers) - - sqlCommands = servers.map(s => new SQLCommand(s)) - }) - - it('Should not clean old video views', async function () { - this.timeout(50000) - - await killallServers([ servers[0] ]) - - await servers[0].run({ views: { videos: { remote: { max_age: '10 days' } } } }) - - await wait(6000) - - // Should still have views - - for (let i = 0; i < servers.length; i++) { - const total = await sqlCommands[i].countVideoViewsOf(videoIdServer1) - expect(total).to.equal(2, 'Server ' + servers[i].serverNumber + ' does not have the correct amount of views') - } - - for (let i = 0; i < servers.length; i++) { - const total = await sqlCommands[i].countVideoViewsOf(videoIdServer2) - expect(total).to.equal(2, 'Server ' + servers[i].serverNumber + ' does not have the correct amount of views') - } - }) - - it('Should clean old video views', async function () { - this.timeout(50000) - - await killallServers([ servers[0] ]) - - await servers[0].run({ views: { videos: { remote: { max_age: '5 seconds' } } } }) - - await wait(6000) - - // Should still have views - - for (let i = 0; i < servers.length; i++) { - const total = await sqlCommands[i].countVideoViewsOf(videoIdServer1) - expect(total).to.equal(2) - } - - const totalServer1 = await sqlCommands[0].countVideoViewsOf(videoIdServer2) - expect(totalServer1).to.equal(0) - - const totalServer2 = await sqlCommands[1].countVideoViewsOf(videoIdServer2) - expect(totalServer2).to.equal(2) - }) - - after(async function () { - for (const sqlCommand of sqlCommands) { - await sqlCommand.cleanup() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/cli/create-generate-storyboard-job.ts b/server/tests/cli/create-generate-storyboard-job.ts deleted file mode 100644 index 02a4be8ae..000000000 --- a/server/tests/cli/create-generate-storyboard-job.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readdir, remove } from 'fs-extra' -import { join } from 'path' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { SQLCommand } from '../shared' - -function listStoryboardFiles (server: PeerTubeServer) { - const storage = server.getDirectoryPath('storyboards') - - return readdir(storage) -} - -describe('Test create generate storyboard job', function () { - let servers: PeerTubeServer[] = [] - const uuids: string[] = [] - let sql: SQLCommand - let existingStoryboardName: string - - before(async function () { - this.timeout(120000) - - // Run server 2 to have transcoding enabled - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - for (let i = 0; i < 3; i++) { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video ' + i }) - uuids.push(uuid) - } - - await waitJobs(servers) - - const storage = servers[0].getDirectoryPath('storyboards') - for (const storyboard of await listStoryboardFiles(servers[0])) { - await remove(join(storage, storyboard)) - } - - sql = new SQLCommand(servers[0]) - await sql.deleteAll('storyboard') - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 4' }) - uuids.push(uuid) - - await waitJobs(servers) - - const storyboards = await listStoryboardFiles(servers[0]) - existingStoryboardName = storyboards[0] - }) - - it('Should create a storyboard of a video', async function () { - this.timeout(120000) - - for (const uuid of [ uuids[0], uuids[3] ]) { - const command = `npm run create-generate-storyboard-job -- -v ${uuid}` - await servers[0].cli.execWithEnv(command) - } - - await waitJobs(servers) - - { - const storyboards = await listStoryboardFiles(servers[0]) - expect(storyboards).to.have.lengthOf(2) - expect(storyboards).to.not.include(existingStoryboardName) - - existingStoryboardName = storyboards[0] - } - - for (const server of servers) { - for (const uuid of [ uuids[0], uuids[3] ]) { - const { storyboards } = await server.storyboard.list({ id: uuid }) - expect(storyboards).to.have.lengthOf(1) - - await makeGetRequest({ url: server.url, path: storyboards[0].storyboardPath, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - - it('Should create missing storyboards', async function () { - this.timeout(120000) - - const command = `npm run create-generate-storyboard-job -- -a` - await servers[0].cli.execWithEnv(command) - - await waitJobs(servers) - - { - const storyboards = await listStoryboardFiles(servers[0]) - expect(storyboards).to.have.lengthOf(4) - expect(storyboards).to.include(existingStoryboardName) - } - - for (const server of servers) { - for (const uuid of uuids) { - const { storyboards } = await server.storyboard.list({ id: uuid }) - expect(storyboards).to.have.lengthOf(1) - - await makeGetRequest({ url: server.url, path: storyboards[0].storyboardPath, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - - after(async function () { - await sql.cleanup() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts deleted file mode 100644 index edd727967..000000000 --- a/server/tests/cli/create-import-video-file-job.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoDetails, VideoFile, VideoInclude } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { expectStartWith } from '../shared' - -function assertVideoProperties (video: VideoFile, resolution: number, extname: string, size?: number) { - expect(video).to.have.nested.property('resolution.id', resolution) - expect(video).to.have.property('torrentUrl').that.includes(`-${resolution}.torrent`) - expect(video).to.have.property('fileUrl').that.includes(`.${extname}`) - expect(video).to.have.property('magnetUri').that.includes(`.${extname}`) - expect(video).to.have.property('size').that.is.above(0) - - if (size) expect(video.size).to.equal(size) -} - -async function checkFiles (video: VideoDetails, objectStorage: ObjectStorageCommand) { - for (const file of video.files) { - if (objectStorage) expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } -} - -function runTests (enableObjectStorage: boolean) { - let video1ShortId: string - let video2UUID: string - - let servers: PeerTubeServer[] = [] - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(90000) - - const config = enableObjectStorage - ? objectStorage.getDefaultMockConfig() - : {} - - // Run server 2 to have transcoding enabled - servers = await createMultipleServers(2, config) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - if (enableObjectStorage) await objectStorage.prepareDefaultMockBuckets() - - // Upload two videos for our needs - { - const { shortUUID } = await servers[0].videos.upload({ attributes: { name: 'video1' } }) - video1ShortId = shortUUID - } - - { - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video2' } }) - video2UUID = uuid - } - - await waitJobs(servers) - - for (const server of servers) { - await server.config.enableTranscoding() - } - }) - - it('Should run a import job on video 1 with a lower resolution', async function () { - const command = `npm run create-import-video-file-job -- -v ${video1ShortId} -i server/tests/fixtures/video_short_480.webm` - await servers[0].cli.execWithEnv(command) - - await waitJobs(servers) - - for (const server of servers) { - const { data: videos } = await server.videos.list() - expect(videos).to.have.lengthOf(2) - - const video = videos.find(({ shortUUID }) => shortUUID === video1ShortId) - const videoDetails = await server.videos.get({ id: video.shortUUID }) - - expect(videoDetails.files).to.have.lengthOf(2) - const [ originalVideo, transcodedVideo ] = videoDetails.files - assertVideoProperties(originalVideo, 720, 'webm', 218910) - assertVideoProperties(transcodedVideo, 480, 'webm', 69217) - - await checkFiles(videoDetails, enableObjectStorage && objectStorage) - } - }) - - it('Should run a import job on video 2 with the same resolution and a different extension', async function () { - const command = `npm run create-import-video-file-job -- -v ${video2UUID} -i server/tests/fixtures/video_short.ogv` - await servers[1].cli.execWithEnv(command) - - await waitJobs(servers) - - for (const server of servers) { - const { data: videos } = await server.videos.listWithToken({ include: VideoInclude.NOT_PUBLISHED_STATE }) - expect(videos).to.have.lengthOf(2) - - const video = videos.find(({ uuid }) => uuid === video2UUID) - const videoDetails = await server.videos.get({ id: video.uuid }) - - expect(videoDetails.files).to.have.lengthOf(4) - const [ originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240 ] = videoDetails.files - assertVideoProperties(originalVideo, 720, 'ogv', 140849) - assertVideoProperties(transcodedVideo420, 480, 'mp4') - assertVideoProperties(transcodedVideo320, 360, 'mp4') - assertVideoProperties(transcodedVideo240, 240, 'mp4') - - await checkFiles(videoDetails, enableObjectStorage && objectStorage) - } - }) - - it('Should run a import job on video 2 with the same resolution and the same extension', async function () { - const command = `npm run create-import-video-file-job -- -v ${video1ShortId} -i server/tests/fixtures/video_short2.webm` - await servers[0].cli.execWithEnv(command) - - await waitJobs(servers) - - for (const server of servers) { - const { data: videos } = await server.videos.listWithToken({ include: VideoInclude.NOT_PUBLISHED_STATE }) - expect(videos).to.have.lengthOf(2) - - const video = videos.find(({ shortUUID }) => shortUUID === video1ShortId) - const videoDetails = await server.videos.get({ id: video.uuid }) - - expect(videoDetails.files).to.have.lengthOf(2) - const [ video720, video480 ] = videoDetails.files - assertVideoProperties(video720, 720, 'webm', 942961) - assertVideoProperties(video480, 480, 'webm', 69217) - - await checkFiles(videoDetails, enableObjectStorage && objectStorage) - } - }) - - it('Should not have run transcoding after an import job', async function () { - const { data } = await servers[0].jobs.list({ jobType: 'video-transcoding' }) - expect(data).to.have.lengthOf(0) - }) - - after(async function () { - await objectStorage.cleanupMock() - - await cleanupTests(servers) - }) -} - -describe('Test create import video jobs', function () { - - describe('On filesystem', function () { - runTests(false) - }) - - describe('On object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - runTests(true) - }) -}) diff --git a/server/tests/cli/create-move-video-storage-job.ts b/server/tests/cli/create-move-video-storage-job.ts deleted file mode 100644 index fc6a8e648..000000000 --- a/server/tests/cli/create-move-video-storage-job.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { join } from 'path' -import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' -import { HttpStatusCode, VideoDetails } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { checkDirectoryIsEmpty, expectStartWith } from '../shared' - -async function checkFiles (origin: PeerTubeServer, video: VideoDetails, objectStorage?: ObjectStorageCommand) { - for (const file of video.files) { - const start = objectStorage - ? objectStorage.getMockWebVideosBaseUrl() - : origin.url - - expectStartWith(file.fileUrl, start) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - - const start = objectStorage - ? objectStorage.getMockPlaylistBaseUrl() - : origin.url - - const hls = video.streamingPlaylists[0] - expectStartWith(hls.playlistUrl, start) - expectStartWith(hls.segmentsSha256Url, start) - - for (const file of hls.files) { - expectStartWith(file.fileUrl, start) - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } -} - -describe('Test create move video storage job', function () { - if (areMockObjectStorageTestsDisabled()) return - - let servers: PeerTubeServer[] = [] - const uuids: string[] = [] - const objectStorage = new ObjectStorageCommand() - - before(async function () { - this.timeout(360000) - - // Run server 2 to have transcoding enabled - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].config.enableTranscoding() - - for (let i = 0; i < 3; i++) { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video' + i } }) - uuids.push(uuid) - } - - await waitJobs(servers) - - await servers[0].kill() - await servers[0].run(objectStorage.getDefaultMockConfig()) - }) - - it('Should move only one file', async function () { - this.timeout(120000) - - const command = `npm run create-move-video-storage-job -- --to-object-storage -v ${uuids[1]}` - await servers[0].cli.execWithEnv(command, objectStorage.getDefaultMockConfig()) - await waitJobs(servers) - - for (const server of servers) { - const video = await server.videos.get({ id: uuids[1] }) - - await checkFiles(servers[0], video, objectStorage) - - for (const id of [ uuids[0], uuids[2] ]) { - const video = await server.videos.get({ id }) - - await checkFiles(servers[0], video) - } - } - }) - - it('Should move all files', async function () { - this.timeout(120000) - - const command = `npm run create-move-video-storage-job -- --to-object-storage --all-videos` - await servers[0].cli.execWithEnv(command, objectStorage.getDefaultMockConfig()) - await waitJobs(servers) - - for (const server of servers) { - for (const id of [ uuids[0], uuids[2] ]) { - const video = await server.videos.get({ id }) - - await checkFiles(servers[0], video, objectStorage) - } - } - }) - - it('Should not have files on disk anymore', async function () { - await checkDirectoryIsEmpty(servers[0], 'web-videos', [ 'private' ]) - await checkDirectoryIsEmpty(servers[0], join('web-videos', 'private')) - - await checkDirectoryIsEmpty(servers[0], join('streaming-playlists', 'hls'), [ 'private' ]) - await checkDirectoryIsEmpty(servers[0], join('streaming-playlists', 'hls', 'private')) - }) - - after(async function () { - await objectStorage.cleanupMock() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/cli/index.ts b/server/tests/cli/index.ts deleted file mode 100644 index 94444ace3..000000000 --- a/server/tests/cli/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Order of the tests we want to execute -import './create-import-video-file-job' -import './create-generate-storyboard-job' -import './create-move-video-storage-job' -import './peertube' -import './plugins' -import './prune-storage' -import './regenerate-thumbnails' -import './reset-password' -import './update-host' diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts deleted file mode 100644 index ad14fde91..000000000 --- a/server/tests/cli/peertube.ts +++ /dev/null @@ -1,331 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { areHttpImportTestsDisabled, buildAbsoluteFixturePath } from '@shared/core-utils' -import { - cleanupTests, - CLICommand, - createSingleServer, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { FIXTURE_URLS, testHelloWorldRegisteredSettings } from '../shared' - -describe('Test CLI wrapper', function () { - let server: PeerTubeServer - let userAccessToken: string - - let cliCommand: CLICommand - - const cmd = 'node ./dist/server/tools/peertube.js' - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { - rates_limit: { - login: { - max: 30 - } - } - }) - await setAccessTokensToServers([ server ]) - - await server.users.create({ username: 'user_1', password: 'super_password' }) - - userAccessToken = await server.login.getAccessToken({ username: 'user_1', password: 'super_password' }) - - { - const attributes = { name: 'user_channel', displayName: 'User channel', support: 'super support text' } - await server.channels.create({ token: userAccessToken, attributes }) - } - - cliCommand = server.cli - }) - - describe('Authentication and instance selection', function () { - - it('Should get an access token', async function () { - const stdout = await cliCommand.execWithEnv(`${cmd} token --url ${server.url} --username user_1 --password super_password`) - const token = stdout.trim() - - const body = await server.users.getMyInfo({ token }) - expect(body.username).to.equal('user_1') - }) - - it('Should display no selected instance', async function () { - this.timeout(60000) - - const stdout = await cliCommand.execWithEnv(`${cmd} --help`) - expect(stdout).to.contain('no instance selected') - }) - - it('Should add a user', async function () { - this.timeout(60000) - - await cliCommand.execWithEnv(`${cmd} auth add -u ${server.url} -U user_1 -p super_password`) - }) - - it('Should not fail to add a user if there is a slash at the end of the instance URL', async function () { - this.timeout(60000) - - let fullServerURL = server.url + '/' - - await cliCommand.execWithEnv(`${cmd} auth add -u ${fullServerURL} -U user_1 -p super_password`) - - fullServerURL = server.url + '/asdfasdf' - await cliCommand.execWithEnv(`${cmd} auth add -u ${fullServerURL} -U user_1 -p super_password`) - }) - - it('Should default to this user', async function () { - this.timeout(60000) - - const stdout = await cliCommand.execWithEnv(`${cmd} --help`) - expect(stdout).to.contain(`instance ${server.url} selected`) - }) - - it('Should remember the user', async function () { - this.timeout(60000) - - const stdout = await cliCommand.execWithEnv(`${cmd} auth list`) - expect(stdout).to.contain(server.url) - }) - }) - - describe('Video upload/import', function () { - - it('Should upload a video', async function () { - this.timeout(60000) - - const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4') - const params = `-f ${fixture} --video-name 'test upload' --channel-name user_channel --support 'support_text'` - - await cliCommand.execWithEnv(`${cmd} upload ${params}`) - }) - - it('Should have the video uploaded', async function () { - const { total, data } = await server.videos.list() - expect(total).to.equal(1) - - const video = await server.videos.get({ id: data[0].uuid }) - expect(video.name).to.equal('test upload') - expect(video.support).to.equal('support_text') - expect(video.channel.name).to.equal('user_channel') - }) - - it('Should import a video', async function () { - if (areHttpImportTestsDisabled()) return - - this.timeout(60000) - - const params = `--target-url ${FIXTURE_URLS.youtube} --channel-name user_channel` - await cliCommand.execWithEnv(`${cmd} import ${params}`) - }) - - it('Should have imported the video', async function () { - if (areHttpImportTestsDisabled()) return - - this.timeout(60000) - - await waitJobs([ server ]) - - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - - const video = data.find(v => v.name === 'small video - youtube') - expect(video).to.not.be.undefined - - const videoDetails = await server.videos.get({ id: video.id }) - expect(videoDetails.channel.name).to.equal('user_channel') - expect(videoDetails.support).to.equal('super support text') - expect(videoDetails.nsfw).to.be.false - }) - - it('Should not import again the same video', async function () { - if (areHttpImportTestsDisabled()) return - - this.timeout(60000) - - const params = `--target-url ${FIXTURE_URLS.youtube} --channel-name user_channel` - await cliCommand.execWithEnv(`${cmd} import ${params}`) - - await waitJobs([ server ]) - - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - - const videos = data.filter(v => v.name === 'small video - youtube') - expect(videos).to.have.lengthOf(1) - - // So we can reimport it - await server.videos.remove({ token: userAccessToken, id: videos[0].id }) - }) - - it('Should import and override some imported attributes', async function () { - if (areHttpImportTestsDisabled()) return - - this.timeout(60000) - - const params = `--target-url ${FIXTURE_URLS.youtube} ` + - `--channel-name user_channel --video-name toto --nsfw --support support` - await cliCommand.execWithEnv(`${cmd} import ${params}`) - - await waitJobs([ server ]) - - { - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - - const video = data.find(v => v.name === 'toto') - expect(video).to.not.be.undefined - - const videoDetails = await server.videos.get({ id: video.id }) - expect(videoDetails.channel.name).to.equal('user_channel') - expect(videoDetails.support).to.equal('support') - expect(videoDetails.nsfw).to.be.true - expect(videoDetails.commentsEnabled).to.be.true - } - }) - }) - - describe('Admin auth', function () { - - it('Should remove the auth user', async function () { - await cliCommand.execWithEnv(`${cmd} auth del ${server.url}`) - - const stdout = await cliCommand.execWithEnv(`${cmd} --help`) - expect(stdout).to.contain('no instance selected') - }) - - it('Should add the admin user', async function () { - await cliCommand.execWithEnv(`${cmd} auth add -u ${server.url} -U root -p test${server.internalServerNumber}`) - }) - }) - - describe('Manage plugins', function () { - - it('Should install a plugin', async function () { - this.timeout(60000) - - await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world`) - }) - - it('Should have registered settings', async function () { - await testHelloWorldRegisteredSettings(server) - }) - - it('Should list installed plugins', async function () { - const res = await cliCommand.execWithEnv(`${cmd} plugins list`) - - expect(res).to.contain('peertube-plugin-hello-world') - }) - - it('Should uninstall the plugin', async function () { - const res = await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`) - - expect(res).to.not.contain('peertube-plugin-hello-world') - }) - - it('Should install a plugin in requested version', async function () { - this.timeout(60000) - - await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.17`) - }) - - it('Should list installed plugins, in correct version', async function () { - const res = await cliCommand.execWithEnv(`${cmd} plugins list`) - - expect(res).to.contain('peertube-plugin-hello-world') - expect(res).to.contain('0.0.17') - }) - - it('Should uninstall the plugin again', async function () { - const res = await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`) - - expect(res).to.not.contain('peertube-plugin-hello-world') - }) - - it('Should install a plugin in requested beta version', async function () { - this.timeout(60000) - - await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.21-beta.1`) - - const res = await cliCommand.execWithEnv(`${cmd} plugins list`) - - expect(res).to.contain('peertube-plugin-hello-world') - expect(res).to.contain('0.0.21-beta.1') - - await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`) - }) - }) - - describe('Manage video redundancies', function () { - let anotherServer: PeerTubeServer - let video1Server2: number - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(120000) - - anotherServer = await createSingleServer(2) - await setAccessTokensToServers([ anotherServer ]) - - await doubleFollow(server, anotherServer) - - servers = [ server, anotherServer ] - await waitJobs(servers) - - const { uuid } = await anotherServer.videos.quickUpload({ name: 'super video' }) - await waitJobs(servers) - - video1Server2 = await server.videos.getId({ uuid }) - }) - - it('Should add a redundancy', async function () { - this.timeout(60000) - - const params = `add --video ${video1Server2}` - await cliCommand.execWithEnv(`${cmd} redundancy ${params}`) - - await waitJobs(servers) - }) - - it('Should list redundancies', async function () { - this.timeout(60000) - - { - const params = 'list-my-redundancies' - const stdout = await cliCommand.execWithEnv(`${cmd} redundancy ${params}`) - - expect(stdout).to.contain('super video') - expect(stdout).to.contain(server.host) - } - }) - - it('Should remove a redundancy', async function () { - this.timeout(60000) - - const params = `remove --video ${video1Server2}` - await cliCommand.execWithEnv(`${cmd} redundancy ${params}`) - - await waitJobs(servers) - - { - const params = 'list-my-redundancies' - const stdout = await cliCommand.execWithEnv(`${cmd} redundancy ${params}`) - - expect(stdout).to.not.contain('super video') - } - }) - - after(async function () { - await cleanupTests([ anotherServer ]) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/cli/plugins.ts b/server/tests/cli/plugins.ts deleted file mode 100644 index c646e20d9..000000000 --- a/server/tests/cli/plugins.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - killallServers, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test plugin scripts', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - }) - - it('Should install a plugin from stateless CLI', async function () { - this.timeout(60000) - - const packagePath = PluginsCommand.getPluginTestPath() - - await server.cli.execWithEnv(`npm run plugin:install -- --plugin-path ${packagePath}`) - }) - - it('Should install a theme from stateless CLI', async function () { - this.timeout(60000) - - await server.cli.execWithEnv(`npm run plugin:install -- --npm-name peertube-theme-background-red`) - }) - - it('Should have the theme and the plugin registered when we restart peertube', async function () { - this.timeout(30000) - - await killallServers([ server ]) - await server.run() - - const config = await server.config.getConfig() - - const plugin = config.plugin.registered - .find(p => p.name === 'test') - expect(plugin).to.not.be.undefined - - const theme = config.theme.registered - .find(t => t.name === 'background-red') - expect(theme).to.not.be.undefined - }) - - it('Should uninstall a plugin from stateless CLI', async function () { - this.timeout(60000) - - await server.cli.execWithEnv(`npm run plugin:uninstall -- --npm-name peertube-plugin-test`) - }) - - it('Should have removed the plugin on another peertube restart', async function () { - this.timeout(30000) - - await killallServers([ server ]) - await server.run() - - const config = await server.config.getConfig() - - const plugin = config.plugin.registered - .find(p => p.name === 'test') - expect(plugin).to.be.undefined - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts deleted file mode 100644 index 72a4b1332..000000000 --- a/server/tests/cli/prune-storage.ts +++ /dev/null @@ -1,223 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { createFile, readdir } from 'fs-extra' -import { join } from 'path' -import { wait } from '@shared/core-utils' -import { buildUUID } from '@shared/extra-utils' -import { HttpStatusCode, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - CLICommand, - createMultipleServers, - doubleFollow, - killallServers, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -async function assertNotExists (server: PeerTubeServer, directory: string, substring: string) { - const files = await readdir(server.servers.buildDirectory(directory)) - - for (const f of files) { - expect(f).to.not.contain(substring) - } -} - -async function assertCountAreOkay (servers: PeerTubeServer[]) { - for (const server of servers) { - const videosCount = await server.servers.countFiles('web-videos') - expect(videosCount).to.equal(9) // 2 videos with 4 resolutions + private directory - - const privateVideosCount = await server.servers.countFiles('web-videos/private') - expect(privateVideosCount).to.equal(4) - - const torrentsCount = await server.servers.countFiles('torrents') - expect(torrentsCount).to.equal(24) - - const previewsCount = await server.servers.countFiles('previews') - expect(previewsCount).to.equal(3) - - const thumbnailsCount = await server.servers.countFiles('thumbnails') - expect(thumbnailsCount).to.equal(5) // 3 local videos, 1 local playlist, 2 remotes videos (lazy downloaded) and 1 remote playlist - - const avatarsCount = await server.servers.countFiles('avatars') - expect(avatarsCount).to.equal(4) - - const hlsRootCount = await server.servers.countFiles(join('streaming-playlists', 'hls')) - expect(hlsRootCount).to.equal(3) // 2 videos + private directory - - const hlsPrivateRootCount = await server.servers.countFiles(join('streaming-playlists', 'hls', 'private')) - expect(hlsPrivateRootCount).to.equal(1) - } -} - -describe('Test prune storage scripts', function () { - let servers: PeerTubeServer[] - const badNames: { [directory: string]: string[] } = {} - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2, { transcoding: { enabled: true } }) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - for (const server of servers) { - await server.videos.upload({ attributes: { name: 'video 1', privacy: VideoPrivacy.PUBLIC } }) - await server.videos.upload({ attributes: { name: 'video 2', privacy: VideoPrivacy.PUBLIC } }) - - await server.videos.upload({ attributes: { name: 'video 3', privacy: VideoPrivacy.PRIVATE } }) - - await server.users.updateMyAvatar({ fixture: 'avatar.png' }) - - await server.playlists.create({ - attributes: { - displayName: 'playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: server.store.channel.id, - thumbnailfile: 'custom-thumbnail.jpg' - } - }) - } - - await doubleFollow(servers[0], servers[1]) - - // Lazy load the remote avatars - { - const account = await servers[0].accounts.get({ accountName: 'root@' + servers[1].host }) - - for (const avatar of account.avatars) { - await makeGetRequest({ - url: servers[0].url, - path: avatar.path, - expectedStatus: HttpStatusCode.OK_200 - }) - } - } - - { - const account = await servers[1].accounts.get({ accountName: 'root@' + servers[0].host }) - for (const avatar of account.avatars) { - await makeGetRequest({ - url: servers[1].url, - path: avatar.path, - expectedStatus: HttpStatusCode.OK_200 - }) - } - } - - await wait(1000) - - await waitJobs(servers) - await killallServers(servers) - - await wait(1000) - }) - - it('Should have the files on the disk', async function () { - await assertCountAreOkay(servers) - }) - - it('Should create some dirty files', async function () { - for (let i = 0; i < 2; i++) { - { - const basePublic = servers[0].servers.buildDirectory('web-videos') - const basePrivate = servers[0].servers.buildDirectory(join('web-videos', 'private')) - - const n1 = buildUUID() + '.mp4' - const n2 = buildUUID() + '.webm' - - await createFile(join(basePublic, n1)) - await createFile(join(basePublic, n2)) - await createFile(join(basePrivate, n1)) - await createFile(join(basePrivate, n2)) - - badNames['web-videos'] = [ n1, n2 ] - } - - { - const base = servers[0].servers.buildDirectory('torrents') - - const n1 = buildUUID() + '-240.torrent' - const n2 = buildUUID() + '-480.torrent' - - await createFile(join(base, n1)) - await createFile(join(base, n2)) - - badNames['torrents'] = [ n1, n2 ] - } - - { - const base = servers[0].servers.buildDirectory('thumbnails') - - const n1 = buildUUID() + '.jpg' - const n2 = buildUUID() + '.jpg' - - await createFile(join(base, n1)) - await createFile(join(base, n2)) - - badNames['thumbnails'] = [ n1, n2 ] - } - - { - const base = servers[0].servers.buildDirectory('previews') - - const n1 = buildUUID() + '.jpg' - const n2 = buildUUID() + '.jpg' - - await createFile(join(base, n1)) - await createFile(join(base, n2)) - - badNames['previews'] = [ n1, n2 ] - } - - { - const base = servers[0].servers.buildDirectory('avatars') - - const n1 = buildUUID() + '.png' - const n2 = buildUUID() + '.jpg' - - await createFile(join(base, n1)) - await createFile(join(base, n2)) - - badNames['avatars'] = [ n1, n2 ] - } - - { - const directory = join('streaming-playlists', 'hls') - const basePublic = servers[0].servers.buildDirectory(directory) - const basePrivate = servers[0].servers.buildDirectory(join(directory, 'private')) - - const n1 = buildUUID() - await createFile(join(basePublic, n1)) - await createFile(join(basePrivate, n1)) - badNames[directory] = [ n1 ] - } - } - }) - - it('Should run prune storage', async function () { - this.timeout(30000) - - const env = servers[0].cli.getEnv() - await CLICommand.exec(`echo y | ${env} npm run prune-storage`) - }) - - it('Should have removed files', async function () { - await assertCountAreOkay(servers) - - for (const directory of Object.keys(badNames)) { - for (const name of badNames[directory]) { - await assertNotExists(servers[0], directory, name) - } - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/cli/regenerate-thumbnails.ts b/server/tests/cli/regenerate-thumbnails.ts deleted file mode 100644 index 66de7f79c..000000000 --- a/server/tests/cli/regenerate-thumbnails.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { expect } from 'chai' -import { writeFile } from 'fs-extra' -import { basename, join } from 'path' -import { HttpStatusCode, Video } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '../../../shared/server-commands' - -async function testThumbnail (server: PeerTubeServer, videoId: number | string) { - const video = await server.videos.get({ id: videoId }) - - const requests = [ - makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }), - makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - ] - - for (const req of requests) { - const res = await req - expect(res.body).to.not.have.lengthOf(0) - } -} - -describe('Test regenerate thumbnails script', function () { - let servers: PeerTubeServer[] - - let video1: Video - let video2: Video - let remoteVideo: Video - - let thumbnail1Path: string - let thumbnailRemotePath: string - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - { - const videoUUID1 = (await servers[0].videos.quickUpload({ name: 'video 1' })).uuid - video1 = await servers[0].videos.get({ id: videoUUID1 }) - - thumbnail1Path = join(servers[0].servers.buildDirectory('thumbnails'), basename(video1.thumbnailPath)) - - const videoUUID2 = (await servers[0].videos.quickUpload({ name: 'video 2' })).uuid - video2 = await servers[0].videos.get({ id: videoUUID2 }) - } - - { - const videoUUID = (await servers[1].videos.quickUpload({ name: 'video 3' })).uuid - await waitJobs(servers) - - remoteVideo = await servers[0].videos.get({ id: videoUUID }) - - // Load remote thumbnail on disk - await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - - thumbnailRemotePath = join(servers[0].servers.buildDirectory('thumbnails'), basename(remoteVideo.thumbnailPath)) - } - - await writeFile(thumbnail1Path, '') - await writeFile(thumbnailRemotePath, '') - }) - - it('Should have empty thumbnails', async function () { - { - const res = await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.have.lengthOf(0) - } - - { - const res = await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.not.have.lengthOf(0) - } - - { - const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.have.lengthOf(0) - } - }) - - it('Should regenerate local thumbnails from the CLI', async function () { - this.timeout(15000) - - await servers[0].cli.execWithEnv(`npm run regenerate-thumbnails`) - }) - - it('Should have generated new thumbnail files', async function () { - await testThumbnail(servers[0], video1.uuid) - await testThumbnail(servers[0], video2.uuid) - - const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.have.lengthOf(0) - }) - - it('Should have deleted old thumbnail files', async function () { - { - await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - - { - await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - } - - { - const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.body).to.have.lengthOf(0) - } - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/cli/reset-password.ts b/server/tests/cli/reset-password.ts deleted file mode 100644 index 79892173b..000000000 --- a/server/tests/cli/reset-password.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { cleanupTests, CLICommand, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test reset password scripts', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(30000) - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.users.create({ username: 'user_1', password: 'super password' }) - }) - - it('Should change the user password from CLI', async function () { - this.timeout(60000) - - const env = server.cli.getEnv() - await CLICommand.exec(`echo coucou | ${env} npm run reset-password -- -u user_1`) - - await server.login.login({ user: { username: 'user_1', password: 'coucou' } }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts deleted file mode 100644 index 386c384e6..000000000 --- a/server/tests/cli/update-host.ts +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { getAllFiles } from '@shared/core-utils' -import { - cleanupTests, - createSingleServer, - killallServers, - makeActivityPubGetRequest, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { parseTorrentVideo } from '../shared' - -describe('Test update host scripts', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(60000) - - const overrideConfig = { - webserver: { - port: 9256 - } - } - // Run server 2 to have transcoding enabled - server = await createSingleServer(2, overrideConfig) - await setAccessTokensToServers([ server ]) - - // Upload two videos for our needs - const { uuid: video1UUID } = await server.videos.upload() - await server.videos.upload() - - // Create a user - await server.users.create({ username: 'toto', password: 'coucou' }) - - // Create channel - const videoChannel = { - name: 'second_channel', - displayName: 'second video channel', - description: 'super video channel description' - } - await server.channels.create({ attributes: videoChannel }) - - // Create comments - const text = 'my super first comment' - await server.comments.createThread({ videoId: video1UUID, text }) - - await waitJobs(server) - }) - - it('Should run update host', async function () { - this.timeout(30000) - - await killallServers([ server ]) - // Run server with standard configuration - await server.run() - - await server.cli.execWithEnv(`npm run update-host`) - }) - - it('Should have updated videos url', async function () { - const { total, data } = await server.videos.list() - expect(total).to.equal(2) - - for (const video of data) { - const { body } = await makeActivityPubGetRequest(server.url, '/videos/watch/' + video.uuid) - - expect(body.id).to.equal('http://127.0.0.1:9002/videos/watch/' + video.uuid) - - const videoDetails = await server.videos.get({ id: video.uuid }) - - expect(videoDetails.trackerUrls[0]).to.include(server.host) - expect(videoDetails.streamingPlaylists[0].playlistUrl).to.include(server.host) - expect(videoDetails.streamingPlaylists[0].segmentsSha256Url).to.include(server.host) - } - }) - - it('Should have updated video channels url', async function () { - const { data, total } = await server.channels.list({ sort: '-name' }) - expect(total).to.equal(3) - - for (const channel of data) { - const { body } = await makeActivityPubGetRequest(server.url, '/video-channels/' + channel.name) - - expect(body.id).to.equal('http://127.0.0.1:9002/video-channels/' + channel.name) - } - }) - - it('Should have updated accounts url', async function () { - const body = await server.accounts.list() - expect(body.total).to.equal(3) - - for (const account of body.data) { - const usernameWithDomain = account.name - const { body } = await makeActivityPubGetRequest(server.url, '/accounts/' + usernameWithDomain) - - expect(body.id).to.equal('http://127.0.0.1:9002/accounts/' + usernameWithDomain) - } - }) - - it('Should have updated torrent hosts', async function () { - this.timeout(30000) - - const { data } = await server.videos.list() - expect(data).to.have.lengthOf(2) - - for (const video of data) { - const videoDetails = await server.videos.get({ id: video.id }) - const files = getAllFiles(videoDetails) - - expect(files).to.have.lengthOf(8) - - for (const file of files) { - expect(file.magnetUri).to.contain('127.0.0.1%3A9002%2Ftracker%2Fsocket') - expect(file.magnetUri).to.contain('127.0.0.1%3A9002%2Fstatic%2F') - - const torrent = await parseTorrentVideo(server, file) - const announceWS = torrent.announce.find(a => a === 'ws://127.0.0.1:9002/tracker/socket') - expect(announceWS).to.not.be.undefined - - const announceHttp = torrent.announce.find(a => a === 'http://127.0.0.1:9002/tracker/announce') - expect(announceHttp).to.not.be.undefined - - expect(torrent.urlList[0]).to.contain('http://127.0.0.1:9002/static/') - } - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/client.ts b/server/tests/client.ts deleted file mode 100644 index 68f3a1d14..000000000 --- a/server/tests/client.ts +++ /dev/null @@ -1,556 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { omit } from '@shared/core-utils' -import { - Account, - HTMLServerConfig, - HttpStatusCode, - ServerConfig, - VideoPlaylistCreateResult, - VideoPlaylistPrivacy, - VideoPrivacy -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - makeHTMLRequest, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '../../shared/server-commands' - -function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) { - expect(html).to.contain('' + title + '') - expect(html).to.contain('') - expect(html).to.contain('') - - const htmlConfig: HTMLServerConfig = omit(config, [ 'signup' ]) - const configObjectString = JSON.stringify(htmlConfig) - const configEscapedString = JSON.stringify(configObjectString) - - expect(html).to.contain(``) -} - -describe('Test a client controllers', function () { - let servers: PeerTubeServer[] = [] - let account: Account - - const videoName = 'my super name for server 1' - const videoDescription = 'my
super __description__ for *server* 1

' - const videoDescriptionPlainText = 'my super description for server 1' - - const playlistName = 'super playlist name' - const playlistDescription = 'super playlist description' - let playlist: VideoPlaylistCreateResult - - const channelDescription = 'my super channel description' - - const watchVideoBasePaths = [ '/videos/watch/', '/w/' ] - const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ] - - let videoIds: (string | number)[] = [] - let privateVideoId: string - let internalVideoId: string - let unlistedVideoId: string - let passwordProtectedVideoId: string - - let playlistIds: (string | number)[] = [] - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - await setDefaultVideoChannel(servers) - - await servers[0].channels.update({ - channelName: servers[0].store.channel.name, - attributes: { description: channelDescription } - }) - - // Public video - - { - const attributes = { name: videoName, description: videoDescription } - await servers[0].videos.upload({ attributes }) - - const { data } = await servers[0].videos.list() - expect(data.length).to.equal(1) - - const video = data[0] - servers[0].store.video = video - videoIds = [ video.id, video.uuid, video.shortUUID ] - } - - { - ({ uuid: privateVideoId } = await servers[0].videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })); - ({ uuid: unlistedVideoId } = await servers[0].videos.quickUpload({ name: 'unlisted', privacy: VideoPrivacy.UNLISTED })); - ({ uuid: internalVideoId } = await servers[0].videos.quickUpload({ name: 'internal', privacy: VideoPrivacy.INTERNAL })); - ({ uuid: passwordProtectedVideoId } = await servers[0].videos.quickUpload({ - name: 'password protected', - privacy: VideoPrivacy.PASSWORD_PROTECTED, - videoPasswords: [ 'password' ] - })) - } - - // Playlist - - { - const attributes = { - displayName: playlistName, - description: playlistDescription, - privacy: VideoPlaylistPrivacy.PUBLIC, - videoChannelId: servers[0].store.channel.id - } - - playlist = await servers[0].playlists.create({ attributes }) - playlistIds = [ playlist.id, playlist.shortUUID, playlist.uuid ] - - await servers[0].playlists.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: servers[0].store.video.id } }) - } - - // Account - - { - await servers[0].users.updateMe({ description: 'my account description' }) - - account = await servers[0].accounts.get({ accountName: `${servers[0].store.user.username}@${servers[0].host}` }) - } - - await waitJobs(servers) - }) - - describe('oEmbed', function () { - - it('Should have valid oEmbed discovery tags for videos', async function () { - for (const basePath of watchVideoBasePaths) { - for (const id of videoIds) { - const res = await makeGetRequest({ - url: servers[0].url, - path: basePath + id, - accept: 'text/html', - expectedStatus: HttpStatusCode.OK_200 - }) - - const expectedLink = `` - - expect(res.text).to.contain(expectedLink) - } - } - }) - - it('Should have valid oEmbed discovery tags for a playlist', async function () { - for (const basePath of watchPlaylistBasePaths) { - for (const id of playlistIds) { - const res = await makeGetRequest({ - url: servers[0].url, - path: basePath + id, - accept: 'text/html', - expectedStatus: HttpStatusCode.OK_200 - }) - - const expectedLink = `` - - expect(res.text).to.contain(expectedLink) - } - } - }) - }) - - describe('Open Graph', function () { - - async function accountPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain(``) - expect(text).to.contain(``) - expect(text).to.contain('') - expect(text).to.contain(``) - } - - async function channelPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain(``) - expect(text).to.contain(``) - expect(text).to.contain('') - expect(text).to.contain(``) - } - - async function watchVideoPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain(``) - expect(text).to.contain(``) - expect(text).to.contain('') - expect(text).to.contain(``) - } - - async function watchPlaylistPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain(``) - expect(text).to.contain(``) - expect(text).to.contain('') - expect(text).to.contain(``) - } - - it('Should have valid Open Graph tags on the account page', async function () { - await accountPageTest('/accounts/' + servers[0].store.user.username) - await accountPageTest('/a/' + servers[0].store.user.username) - await accountPageTest('/@' + servers[0].store.user.username) - }) - - it('Should have valid Open Graph tags on the channel page', async function () { - await channelPageTest('/video-channels/' + servers[0].store.channel.name) - await channelPageTest('/c/' + servers[0].store.channel.name) - await channelPageTest('/@' + servers[0].store.channel.name) - }) - - it('Should have valid Open Graph tags on the watch page', async function () { - for (const path of watchVideoBasePaths) { - for (const id of videoIds) { - await watchVideoPageTest(path + id) - } - } - }) - - it('Should have valid Open Graph tags on the watch page with thread id Angular param', async function () { - for (const path of watchVideoBasePaths) { - for (const id of videoIds) { - await watchVideoPageTest(path + id + ';threadId=1') - } - } - }) - - it('Should have valid Open Graph tags on the watch playlist page', async function () { - for (const path of watchPlaylistBasePaths) { - for (const id of playlistIds) { - await watchPlaylistPageTest(path + id) - } - } - }) - }) - - describe('Twitter card', async function () { - - describe('Not whitelisted', function () { - - async function accountPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - expect(text).to.contain(``) - expect(text).to.contain(``) - } - - async function channelPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - expect(text).to.contain(``) - expect(text).to.contain(``) - } - - async function watchVideoPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - expect(text).to.contain(``) - expect(text).to.contain(``) - } - - async function watchPlaylistPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - expect(text).to.contain(``) - expect(text).to.contain(``) - } - - it('Should have valid twitter card on the watch video page', async function () { - for (const path of watchVideoBasePaths) { - for (const id of videoIds) { - await watchVideoPageTest(path + id) - } - } - }) - - it('Should have valid twitter card on the watch playlist page', async function () { - for (const path of watchPlaylistBasePaths) { - for (const id of playlistIds) { - await watchPlaylistPageTest(path + id) - } - } - }) - - it('Should have valid twitter card on the account page', async function () { - await accountPageTest('/accounts/' + account.name) - await accountPageTest('/a/' + account.name) - await accountPageTest('/@' + account.name) - }) - - it('Should have valid twitter card on the channel page', async function () { - await channelPageTest('/video-channels/' + servers[0].store.channel.name) - await channelPageTest('/c/' + servers[0].store.channel.name) - await channelPageTest('/@' + servers[0].store.channel.name) - }) - }) - - describe('Whitelisted', function () { - - before(async function () { - const config = await servers[0].config.getCustomConfig() - config.services.twitter = { - username: '@Kuja', - whitelisted: true - } - - await servers[0].config.updateCustomConfig({ newCustomConfig: config }) - }) - - async function accountPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - } - - async function channelPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - } - - async function watchVideoPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - } - - async function watchPlaylistPageTest (path: string) { - const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', expectedStatus: HttpStatusCode.OK_200 }) - const text = res.text - - expect(text).to.contain('') - expect(text).to.contain('') - } - - it('Should have valid twitter card on the watch video page', async function () { - for (const path of watchVideoBasePaths) { - for (const id of videoIds) { - await watchVideoPageTest(path + id) - } - } - }) - - it('Should have valid twitter card on the watch playlist page', async function () { - for (const path of watchPlaylistBasePaths) { - for (const id of playlistIds) { - await watchPlaylistPageTest(path + id) - } - } - }) - - it('Should have valid twitter card on the account page', async function () { - await accountPageTest('/accounts/' + account.name) - await accountPageTest('/a/' + account.name) - await accountPageTest('/@' + account.name) - }) - - it('Should have valid twitter card on the channel page', async function () { - await channelPageTest('/video-channels/' + servers[0].store.channel.name) - await channelPageTest('/c/' + servers[0].store.channel.name) - await channelPageTest('/@' + servers[0].store.channel.name) - }) - }) - }) - - describe('Index HTML', function () { - - it('Should have valid index html tags (title, description...)', async function () { - const config = await servers[0].config.getConfig() - const res = await makeHTMLRequest(servers[0].url, '/videos/trending') - - const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' - checkIndexTags(res.text, 'PeerTube', description, '', config) - }) - - it('Should update the customized configuration and have the correct index html tags', async function () { - await servers[0].config.updateCustomSubConfig({ - newConfig: { - instance: { - name: 'PeerTube updated', - shortDescription: 'my short description', - description: 'my super description', - terms: 'my super terms', - defaultNSFWPolicy: 'blur', - defaultClientRoute: '/videos/recently-added', - customizations: { - javascript: 'alert("coucou")', - css: 'body { background-color: red; }' - } - } - } - }) - - const config = await servers[0].config.getConfig() - const res = await makeHTMLRequest(servers[0].url, '/videos/trending') - - checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) - }) - - it('Should have valid index html updated tags (title, description...)', async function () { - const config = await servers[0].config.getConfig() - const res = await makeHTMLRequest(servers[0].url, '/videos/trending') - - checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) - }) - - it('Should use the original video URL for the canonical tag', async function () { - for (const basePath of watchVideoBasePaths) { - for (const id of videoIds) { - const res = await makeHTMLRequest(servers[1].url, basePath + id) - expect(res.text).to.contain(``) - } - } - }) - - it('Should use the original account URL for the canonical tag', async function () { - const accountURLtest = res => { - expect(res.text).to.contain(``) - } - - accountURLtest(await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)) - accountURLtest(await makeHTMLRequest(servers[1].url, '/a/root@' + servers[0].host)) - accountURLtest(await makeHTMLRequest(servers[1].url, '/@root@' + servers[0].host)) - }) - - it('Should use the original channel URL for the canonical tag', async function () { - const channelURLtests = res => { - expect(res.text).to.contain(``) - } - - channelURLtests(await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)) - channelURLtests(await makeHTMLRequest(servers[1].url, '/c/root_channel@' + servers[0].host)) - channelURLtests(await makeHTMLRequest(servers[1].url, '/@root_channel@' + servers[0].host)) - }) - - it('Should use the original playlist URL for the canonical tag', async function () { - for (const basePath of watchPlaylistBasePaths) { - for (const id of playlistIds) { - const res = await makeHTMLRequest(servers[1].url, basePath + id) - expect(res.text).to.contain(``) - } - } - }) - - it('Should add noindex meta tag for remote accounts', async function () { - const handle = 'root@' + servers[0].host - const paths = [ '/accounts/', '/a/', '/@' ] - - for (const path of paths) { - { - const { text } = await makeHTMLRequest(servers[1].url, path + handle) - expect(text).to.contain('') - } - - { - const { text } = await makeHTMLRequest(servers[0].url, path + handle) - expect(text).to.not.contain('') - } - } - }) - - it('Should add noindex meta tag for remote channels', async function () { - const handle = 'root_channel@' + servers[0].host - const paths = [ '/video-channels/', '/c/', '/@' ] - - for (const path of paths) { - { - const { text } = await makeHTMLRequest(servers[1].url, path + handle) - expect(text).to.contain('') - } - - { - const { text } = await makeHTMLRequest(servers[0].url, path + handle) - expect(text).to.not.contain('') - } - } - }) - - it('Should not display internal/private/password protected video', async function () { - for (const basePath of watchVideoBasePaths) { - for (const id of [ privateVideoId, internalVideoId, passwordProtectedVideoId ]) { - const res = await makeGetRequest({ - url: servers[0].url, - path: basePath + id, - accept: 'text/html', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - - expect(res.text).to.not.contain('internal') - expect(res.text).to.not.contain('private') - expect(res.text).to.not.contain('password protected') - } - } - }) - - it('Should add noindex meta tag for unlisted video', async function () { - for (const basePath of watchVideoBasePaths) { - const res = await makeGetRequest({ - url: servers[0].url, - path: basePath + unlistedVideoId, - accept: 'text/html', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('unlisted') - expect(res.text).to.contain('') - } - }) - }) - - describe('Embed HTML', function () { - - it('Should have the correct embed html tags', async function () { - const config = await servers[0].config.getConfig() - const res = await makeHTMLRequest(servers[0].url, servers[0].store.video.embedPath) - - checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', config) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/external-plugins/akismet.ts b/server/tests/external-plugins/akismet.ts deleted file mode 100644 index e964bf0c2..000000000 --- a/server/tests/external-plugins/akismet.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' - -describe('Official plugin Akismet', function () { - let servers: PeerTubeServer[] - let videoUUID: string - - before(async function () { - this.timeout(30000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await servers[0].plugins.install({ - npmName: 'peertube-plugin-akismet' - }) - - if (!process.env.AKISMET_KEY) throw new Error('Missing AKISMET_KEY from env') - - await servers[0].plugins.updateSettings({ - npmName: 'peertube-plugin-akismet', - settings: { - 'akismet-api-key': process.env.AKISMET_KEY - } - }) - - await doubleFollow(servers[0], servers[1]) - }) - - describe('Local threads/replies', function () { - - before(async function () { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) - videoUUID = uuid - }) - - it('Should not detect a thread as spam', async function () { - await servers[0].comments.createThread({ videoId: videoUUID, text: 'comment' }) - }) - - it('Should not detect a reply as spam', async function () { - await servers[0].comments.addReplyToLastThread({ text: 'reply' }) - }) - - it('Should detect a thread as spam', async function () { - await servers[0].comments.createThread({ - videoId: videoUUID, - text: 'akismet-guaranteed-spam', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should detect a thread as spam', async function () { - await servers[0].comments.createThread({ videoId: videoUUID, text: 'comment' }) - await servers[0].comments.addReplyToLastThread({ text: 'akismet-guaranteed-spam', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - }) - - describe('Remote threads/replies', function () { - - before(async function () { - this.timeout(60000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) - videoUUID = uuid - - await waitJobs(servers) - }) - - it('Should not detect a thread as spam', async function () { - this.timeout(30000) - - await servers[1].comments.createThread({ videoId: videoUUID, text: 'remote comment 1' }) - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - expect(data).to.have.lengthOf(1) - }) - - it('Should not detect a reply as spam', async function () { - this.timeout(30000) - - await servers[1].comments.addReplyToLastThread({ text: 'I agree with you' }) - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - expect(data).to.have.lengthOf(1) - - const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId: data[0].id }) - expect(tree.children).to.have.lengthOf(1) - }) - - it('Should detect a thread as spam', async function () { - this.timeout(30000) - - await servers[1].comments.createThread({ videoId: videoUUID, text: 'akismet-guaranteed-spam' }) - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - expect(data).to.have.lengthOf(1) - }) - - it('Should detect a thread as spam', async function () { - this.timeout(30000) - - await servers[1].comments.addReplyToLastThread({ text: 'akismet-guaranteed-spam' }) - await waitJobs(servers) - - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) - expect(data).to.have.lengthOf(1) - - const thread = data[0] - const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId: thread.id }) - expect(tree.children).to.have.lengthOf(1) - }) - }) - - describe('Signup', function () { - - before(async function () { - await servers[0].config.updateExistingSubConfig({ - newConfig: { - signup: { - enabled: true - } - } - }) - }) - - it('Should allow signup', async function () { - await servers[0].registrations.register({ - username: 'user1', - displayName: 'user 1' - }) - }) - - it('Should detect a signup as SPAM', async function () { - await servers[0].registrations.register({ - username: 'user2', - displayName: 'user 2', - email: 'akismet-guaranteed-spam@example.com', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/external-plugins/auth-ldap.ts b/server/tests/external-plugins/auth-ldap.ts deleted file mode 100644 index d51d337be..000000000 --- a/server/tests/external-plugins/auth-ldap.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Official plugin auth-ldap', function () { - let server: PeerTubeServer - let accessToken: string - let userId: number - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ npmName: 'peertube-plugin-auth-ldap' }) - }) - - it('Should not login with without LDAP settings', async function () { - await server.login.login({ user: { username: 'fry', password: 'fry' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not login with bad LDAP settings', async function () { - await server.plugins.updateSettings({ - npmName: 'peertube-plugin-auth-ldap', - settings: { - 'bind-credentials': 'GoodNewsEveryone', - 'bind-dn': 'cn=admin,dc=planetexpress,dc=com', - 'insecure-tls': false, - 'mail-property': 'mail', - 'search-base': 'ou=people,dc=planetexpress,dc=com', - 'search-filter': '(|(mail={{username}})(uid={{username}}))', - 'url': 'ldap://127.0.0.1:390', - 'username-property': 'uid' - } - }) - - await server.login.login({ user: { username: 'fry', password: 'fry' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not login with good LDAP settings but wrong username/password', async function () { - await server.plugins.updateSettings({ - npmName: 'peertube-plugin-auth-ldap', - settings: { - 'bind-credentials': 'GoodNewsEveryone', - 'bind-dn': 'cn=admin,dc=planetexpress,dc=com', - 'insecure-tls': false, - 'mail-property': 'mail', - 'search-base': 'ou=people,dc=planetexpress,dc=com', - 'search-filter': '(|(mail={{username}})(uid={{username}}))', - 'url': 'ldap://127.0.0.1:10389', - 'username-property': 'uid' - } - }) - - await server.login.login({ user: { username: 'fry', password: 'bad password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.login.login({ user: { username: 'fryr', password: 'fry' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should login with the appropriate username/password', async function () { - accessToken = await server.login.getAccessToken({ username: 'fry', password: 'fry' }) - }) - - it('Should login with the appropriate email/password', async function () { - accessToken = await server.login.getAccessToken({ username: 'fry@planetexpress.com', password: 'fry' }) - }) - - it('Should login get my profile', async function () { - const body = await server.users.getMyInfo({ token: accessToken }) - expect(body.username).to.equal('fry') - expect(body.email).to.equal('fry@planetexpress.com') - - userId = body.id - }) - - it('Should upload a video', async function () { - await server.videos.upload({ token: accessToken, attributes: { name: 'my super video' } }) - }) - - it('Should not be able to login if the user is banned', async function () { - await server.users.banUser({ userId }) - - await server.login.login({ - user: { username: 'fry@planetexpress.com', password: 'fry' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should be able to login if the user is unbanned', async function () { - await server.users.unbanUser({ userId }) - - await server.login.login({ user: { username: 'fry@planetexpress.com', password: 'fry' } }) - }) - - it('Should not be able to ask password reset', async function () { - await server.users.askResetPassword({ email: 'fry@planetexpress.com', expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should not be able to ask email verification', async function () { - await server.users.askSendVerifyEmail({ email: 'fry@planetexpress.com', expectedStatus: HttpStatusCode.CONFLICT_409 }) - }) - - it('Should not login if the plugin is uninstalled', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-auth-ldap' }) - - await server.login.login({ - user: { username: 'fry@planetexpress.com', password: 'fry' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/external-plugins/auto-block-videos.ts b/server/tests/external-plugins/auto-block-videos.ts deleted file mode 100644 index 95d7a4b58..000000000 --- a/server/tests/external-plugins/auto-block-videos.ts +++ /dev/null @@ -1,167 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { Video } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' -import { MockBlocklist } from '../shared' - -async function check (server: PeerTubeServer, videoUUID: string, exists = true) { - const { data } = await server.videos.list() - - const video = data.find(v => v.uuid === videoUUID) - - if (exists) expect(video).to.not.be.undefined - else expect(video).to.be.undefined -} - -describe('Official plugin auto-block videos', function () { - let servers: PeerTubeServer[] - let blocklistServer: MockBlocklist - let server1Videos: Video[] = [] - let server2Videos: Video[] = [] - let port: number - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - for (const server of servers) { - await server.plugins.install({ npmName: 'peertube-plugin-auto-block-videos' }) - } - - blocklistServer = new MockBlocklist() - port = await blocklistServer.initialize() - - await servers[0].videos.quickUpload({ name: 'video server 1' }) - await servers[1].videos.quickUpload({ name: 'video server 2' }) - await servers[1].videos.quickUpload({ name: 'video 2 server 2' }) - await servers[1].videos.quickUpload({ name: 'video 3 server 2' }) - - { - const { data } = await servers[0].videos.list() - server1Videos = data.map(v => Object.assign(v, { url: servers[0].url + '/videos/watch/' + v.uuid })) - } - - { - const { data } = await servers[1].videos.list() - server2Videos = data.map(v => Object.assign(v, { url: servers[1].url + '/videos/watch/' + v.uuid })) - } - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should update plugin settings', async function () { - await servers[0].plugins.updateSettings({ - npmName: 'peertube-plugin-auto-block-videos', - settings: { - 'blocklist-urls': `http://127.0.0.1:${port}/blocklist`, - 'check-seconds-interval': 1 - } - }) - }) - - it('Should auto block a video', async function () { - await check(servers[0], server2Videos[0].uuid, true) - - blocklistServer.replace({ - data: [ - { - value: server2Videos[0].url - } - ] - }) - - await wait(2000) - - await check(servers[0], server2Videos[0].uuid, false) - }) - - it('Should have video in blacklists', async function () { - const body = await servers[0].blacklist.list() - - const videoBlacklists = body.data - expect(videoBlacklists).to.have.lengthOf(1) - expect(videoBlacklists[0].reason).to.contains('Automatically blocked from auto block plugin') - expect(videoBlacklists[0].video.name).to.equal(server2Videos[0].name) - }) - - it('Should not block a local video', async function () { - await check(servers[0], server1Videos[0].uuid, true) - - blocklistServer.replace({ - data: [ - { - value: server1Videos[0].url - } - ] - }) - - await wait(2000) - - await check(servers[0], server1Videos[0].uuid, true) - }) - - it('Should remove a video block', async function () { - await check(servers[0], server2Videos[0].uuid, false) - - blocklistServer.replace({ - data: [ - { - value: server2Videos[0].url, - action: 'remove' - } - ] - }) - - await wait(2000) - - await check(servers[0], server2Videos[0].uuid, true) - }) - - it('Should auto block a video, manually unblock it and do not reblock it automatically', async function () { - this.timeout(20000) - - const video = server2Videos[1] - - await check(servers[0], video.uuid, true) - - blocklistServer.replace({ - data: [ - { - value: video.url, - updatedAt: new Date().toISOString() - } - ] - }) - - await wait(2000) - - await check(servers[0], video.uuid, false) - - await servers[0].blacklist.remove({ videoId: video.uuid }) - - await check(servers[0], video.uuid, true) - - await killallServers([ servers[0] ]) - await servers[0].run() - await wait(2000) - - await check(servers[0], video.uuid, true) - }) - - after(async function () { - await blocklistServer.terminate() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/external-plugins/auto-mute.ts b/server/tests/external-plugins/auto-mute.ts deleted file mode 100644 index a9bf3c173..000000000 --- a/server/tests/external-plugins/auto-mute.ts +++ /dev/null @@ -1,216 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - makeGetRequest, - PeerTubeServer, - setAccessTokensToServers -} from '@shared/server-commands' -import { MockBlocklist } from '../shared' - -describe('Official plugin auto-mute', function () { - const autoMuteListPath = '/plugins/auto-mute/router/api/v1/mute-list' - let servers: PeerTubeServer[] - let blocklistServer: MockBlocklist - let port: number - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - for (const server of servers) { - await server.plugins.install({ npmName: 'peertube-plugin-auto-mute' }) - } - - blocklistServer = new MockBlocklist() - port = await blocklistServer.initialize() - - await servers[0].videos.quickUpload({ name: 'video server 1' }) - await servers[1].videos.quickUpload({ name: 'video server 2' }) - - await doubleFollow(servers[0], servers[1]) - }) - - it('Should update plugin settings', async function () { - await servers[0].plugins.updateSettings({ - npmName: 'peertube-plugin-auto-mute', - settings: { - 'blocklist-urls': `http://127.0.0.1:${port}/blocklist`, - 'check-seconds-interval': 1 - } - }) - }) - - it('Should add a server blocklist', async function () { - blocklistServer.replace({ - data: [ - { - value: servers[1].host - } - ] - }) - - await wait(2000) - - const { total } = await servers[0].videos.list() - expect(total).to.equal(1) - }) - - it('Should remove a server blocklist', async function () { - blocklistServer.replace({ - data: [ - { - value: servers[1].host, - action: 'remove' - } - ] - }) - - await wait(2000) - - const { total } = await servers[0].videos.list() - expect(total).to.equal(2) - }) - - it('Should add an account blocklist', async function () { - blocklistServer.replace({ - data: [ - { - value: 'root@' + servers[1].host - } - ] - }) - - await wait(2000) - - const { total } = await servers[0].videos.list() - expect(total).to.equal(1) - }) - - it('Should remove an account blocklist', async function () { - blocklistServer.replace({ - data: [ - { - value: 'root@' + servers[1].host, - action: 'remove' - } - ] - }) - - await wait(2000) - - const { total } = await servers[0].videos.list() - expect(total).to.equal(2) - }) - - it('Should auto mute an account, manually unmute it and do not remute it automatically', async function () { - this.timeout(20000) - - const account = 'root@' + servers[1].host - - blocklistServer.replace({ - data: [ - { - value: account, - updatedAt: new Date().toISOString() - } - ] - }) - - await wait(2000) - - { - const { total } = await servers[0].videos.list() - expect(total).to.equal(1) - } - - await servers[0].blocklist.removeFromServerBlocklist({ account }) - - { - const { total } = await servers[0].videos.list() - expect(total).to.equal(2) - } - - await killallServers([ servers[0] ]) - await servers[0].run() - await wait(2000) - - { - const { total } = await servers[0].videos.list() - expect(total).to.equal(2) - } - }) - - it('Should not expose the auto mute list', async function () { - await makeGetRequest({ - url: servers[0].url, - path: '/plugins/auto-mute/router/api/v1/mute-list', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should enable auto mute list', async function () { - await servers[0].plugins.updateSettings({ - npmName: 'peertube-plugin-auto-mute', - settings: { - 'blocklist-urls': '', - 'check-seconds-interval': 1, - 'expose-mute-list': true - } - }) - - await makeGetRequest({ - url: servers[0].url, - path: '/plugins/auto-mute/router/api/v1/mute-list', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should mute an account on server 1, and server 2 auto mutes it', async function () { - this.timeout(20000) - - await servers[1].plugins.updateSettings({ - npmName: 'peertube-plugin-auto-mute', - settings: { - 'blocklist-urls': 'http://' + servers[0].host + autoMuteListPath, - 'check-seconds-interval': 1, - 'expose-mute-list': false - } - }) - - await servers[0].blocklist.addToServerBlocklist({ account: 'root@' + servers[1].host }) - await servers[0].blocklist.addToMyBlocklist({ server: servers[1].host }) - - const res = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/auto-mute/router/api/v1/mute-list', - expectedStatus: HttpStatusCode.OK_200 - }) - - const data = res.body.data - expect(data).to.have.lengthOf(1) - expect(data[0].updatedAt).to.exist - expect(data[0].value).to.equal('root@' + servers[1].host) - - await wait(2000) - - for (const server of servers) { - const { total } = await server.videos.list() - expect(total).to.equal(1) - } - }) - - after(async function () { - await blocklistServer.terminate() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/external-plugins/index.ts b/server/tests/external-plugins/index.ts deleted file mode 100644 index 815bbf1da..000000000 --- a/server/tests/external-plugins/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import './akismet' -import './auth-ldap' -import './auto-block-videos' -import './auto-mute' diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts deleted file mode 100644 index 1754ac466..000000000 --- a/server/tests/feeds/feeds.ts +++ /dev/null @@ -1,695 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import * as chai from 'chai' -import { XMLParser, XMLValidator } from 'fast-xml-parser' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - createSingleServer, - doubleFollow, - makeGetRequest, - makeRawRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers, - setDefaultChannelAvatar, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -chai.use(require('chai-xml')) -chai.use(require('chai-json-schema')) -chai.config.includeStack = true - -const expect = chai.expect - -describe('Test syndication feeds', () => { - let servers: PeerTubeServer[] = [] - let serverHLSOnly: PeerTubeServer - - let userAccessToken: string - let rootAccountId: number - let rootChannelId: number - - let userAccountId: number - let userChannelId: number - let userFeedToken: string - - let liveId: string - - before(async function () { - this.timeout(120000) - - // Run servers - servers = await createMultipleServers(2) - serverHLSOnly = await createSingleServer(3, { - transcoding: { - enabled: true, - web_videos: { enabled: false }, - hls: { enabled: true } - } - }) - - await setAccessTokensToServers([ ...servers, serverHLSOnly ]) - await setDefaultChannelAvatar(servers[0]) - await setDefaultVideoChannel(servers) - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableLive({ allowReplay: false, transcoding: false }) - - { - const user = await servers[0].users.getMyInfo() - rootAccountId = user.account.id - rootChannelId = user.videoChannels[0].id - } - - { - userAccessToken = await servers[0].users.generateUserAndToken('john') - - const user = await servers[0].users.getMyInfo({ token: userAccessToken }) - userAccountId = user.account.id - userChannelId = user.videoChannels[0].id - - const token = await servers[0].users.getMyScopedTokens({ token: userAccessToken }) - userFeedToken = token.feedToken - } - - { - await servers[0].videos.upload({ token: userAccessToken, attributes: { name: 'user video' } }) - } - - { - const attributes = { - name: 'my super name for server 1', - description: 'my super description for server 1', - fixture: 'video_short.webm' - } - const { id } = await servers[0].videos.upload({ attributes }) - - await servers[0].comments.createThread({ videoId: id, text: 'super comment 1' }) - await servers[0].comments.createThread({ videoId: id, text: 'super comment 2' }) - } - - { - const attributes = { name: 'unlisted video', privacy: VideoPrivacy.UNLISTED } - const { id } = await servers[0].videos.upload({ attributes }) - - await servers[0].comments.createThread({ videoId: id, text: 'comment on unlisted video' }) - } - - { - const attributes = { name: 'password protected video', privacy: VideoPrivacy.PASSWORD_PROTECTED, videoPasswords: [ 'password' ] } - const { id } = await servers[0].videos.upload({ attributes }) - - await servers[0].comments.createThread({ videoId: id, text: 'comment on password protected video' }) - } - - await serverHLSOnly.videos.upload({ attributes: { name: 'hls only video' } }) - - await waitJobs([ ...servers, serverHLSOnly ]) - - await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath('-podcast-custom-tags') }) - }) - - describe('All feed', function () { - - it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { - for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { - const rss = await servers[0].feed.getXML({ feed, ignoreCache: true }) - expect(rss).xml.to.be.valid() - - const atom = await servers[0].feed.getXML({ feed, format: 'atom', ignoreCache: true }) - expect(atom).xml.to.be.valid() - } - }) - - it('Should be well formed XML (covers Podcast endpoint)', async function () { - const podcast = await servers[0].feed.getPodcastXML({ ignoreCache: true, channelId: rootChannelId }) - expect(podcast).xml.to.be.valid() - }) - - it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { - for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { - const jsonText = await servers[0].feed.getJSON({ feed, ignoreCache: true }) - expect(JSON.parse(jsonText)).to.be.jsonSchema({ type: 'object' }) - } - }) - - it('Should serve the endpoint with a classic request', async function () { - await makeGetRequest({ - url: servers[0].url, - path: '/feeds/videos.xml', - accept: 'application/xml', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should refuse to serve the endpoint without accept header', async function () { - await makeGetRequest({ url: servers[0].url, path: '/feeds/videos.xml', expectedStatus: HttpStatusCode.NOT_ACCEPTABLE_406 }) - }) - }) - - describe('Videos feed', function () { - - describe('Podcast feed', function () { - - it('Should contain a valid podcast:alternateEnclosure', async function () { - // Since podcast feeds should only work on the server they originate on, - // only test the first server where the videos reside - const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) - expect(XMLValidator.validate(rss)).to.be.true - - const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) - const xmlDoc = parser.parse(rss) - - const itemGuid = xmlDoc.rss.channel.item.guid - expect(itemGuid).to.exist - expect(itemGuid['@_isPermaLink']).to.equal(true) - - const enclosure = xmlDoc.rss.channel.item.enclosure - expect(enclosure).to.exist - const alternateEnclosure = xmlDoc.rss.channel.item['podcast:alternateEnclosure'] - expect(alternateEnclosure).to.exist - - expect(alternateEnclosure['@_type']).to.equal('video/webm') - expect(alternateEnclosure['@_length']).to.equal(218910) - expect(alternateEnclosure['@_lang']).to.equal('zh') - expect(alternateEnclosure['@_title']).to.equal('720p') - expect(alternateEnclosure['@_default']).to.equal(true) - - expect(alternateEnclosure['podcast:source'][0]['@_uri']).to.contain('-720.webm') - expect(alternateEnclosure['podcast:source'][0]['@_uri']).to.equal(enclosure['@_url']) - expect(alternateEnclosure['podcast:source'][1]['@_uri']).to.contain('-720.torrent') - expect(alternateEnclosure['podcast:source'][1]['@_contentType']).to.equal('application/x-bittorrent') - expect(alternateEnclosure['podcast:source'][2]['@_uri']).to.contain('magnet:?') - }) - - it('Should contain a valid podcast:alternateEnclosure with HLS only', async function () { - const rss = await serverHLSOnly.feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) - expect(XMLValidator.validate(rss)).to.be.true - - const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) - const xmlDoc = parser.parse(rss) - - const itemGuid = xmlDoc.rss.channel.item.guid - expect(itemGuid).to.exist - expect(itemGuid['@_isPermaLink']).to.equal(true) - - const enclosure = xmlDoc.rss.channel.item.enclosure - const alternateEnclosure = xmlDoc.rss.channel.item['podcast:alternateEnclosure'] - expect(alternateEnclosure).to.exist - - expect(alternateEnclosure['@_type']).to.equal('application/x-mpegURL') - expect(alternateEnclosure['@_lang']).to.equal('zh') - expect(alternateEnclosure['@_title']).to.equal('HLS') - expect(alternateEnclosure['@_default']).to.equal(true) - - expect(alternateEnclosure['podcast:source']['@_uri']).to.contain('-master.m3u8') - expect(alternateEnclosure['podcast:source']['@_uri']).to.equal(enclosure['@_url']) - }) - - it('Should contain a valid podcast:socialInteract', async function () { - const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) - expect(XMLValidator.validate(rss)).to.be.true - - const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) - const xmlDoc = parser.parse(rss) - - const item = xmlDoc.rss.channel.item - const socialInteract = item['podcast:socialInteract'] - expect(socialInteract).to.exist - expect(socialInteract['@_protocol']).to.equal('activitypub') - expect(socialInteract['@_uri']).to.exist - expect(socialInteract['@_accountUrl']).to.exist - }) - - it('Should contain a valid support custom tags for plugins', async function () { - const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: userChannelId }) - expect(XMLValidator.validate(rss)).to.be.true - - const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) - const xmlDoc = parser.parse(rss) - - const fooTag = xmlDoc.rss.channel.fooTag - expect(fooTag).to.exist - expect(fooTag['@_bar']).to.equal('baz') - expect(fooTag['#text']).to.equal(42) - - const bizzBuzzItem = xmlDoc.rss.channel['biz:buzzItem'] - expect(bizzBuzzItem).to.exist - - let nestedTag = bizzBuzzItem.nestedTag - expect(nestedTag).to.exist - expect(nestedTag).to.equal('example nested tag') - - const item = xmlDoc.rss.channel.item - const fizzTag = item.fizzTag - expect(fizzTag).to.exist - expect(fizzTag['@_bar']).to.equal('baz') - expect(fizzTag['#text']).to.equal(21) - - const bizzBuzz = item['biz:buzz'] - expect(bizzBuzz).to.exist - - nestedTag = bizzBuzz.nestedTag - expect(nestedTag).to.exist - expect(nestedTag).to.equal('example nested tag') - }) - - it('Should contain a valid podcast:liveItem for live streams', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].live.create({ - fields: { - name: 'live-0', - privacy: VideoPrivacy.PUBLIC, - channelId: rootChannelId, - permanentLive: false - } - }) - liveId = uuid - - const ffmpeg = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveId, copyCodecs: true, fixtureName: 'video_short.mp4' }) - await servers[0].live.waitUntilPublished({ videoId: liveId }) - - const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) - expect(XMLValidator.validate(rss)).to.be.true - - const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) - const xmlDoc = parser.parse(rss) - const liveItem = xmlDoc.rss.channel['podcast:liveItem'] - expect(liveItem.title).to.equal('live-0') - expect(liveItem.guid['@_isPermaLink']).to.equal(false) - expect(liveItem.guid['#text']).to.contain(`${uuid}_`) - expect(liveItem['@_status']).to.equal('live') - - const enclosure = liveItem.enclosure - const alternateEnclosure = liveItem['podcast:alternateEnclosure'] - expect(alternateEnclosure).to.exist - expect(alternateEnclosure['@_type']).to.equal('application/x-mpegURL') - expect(alternateEnclosure['@_title']).to.equal('HLS live stream') - expect(alternateEnclosure['@_default']).to.equal(true) - - expect(alternateEnclosure['podcast:source']['@_uri']).to.contain('/master.m3u8') - expect(alternateEnclosure['podcast:source']['@_uri']).to.equal(enclosure['@_url']) - - await stopFfmpeg(ffmpeg) - - await servers[0].live.waitUntilEnded({ videoId: liveId }) - - await waitJobs(servers) - }) - }) - - describe('JSON feed', function () { - - it('Should contain a valid \'attachments\' object', async function () { - for (const server of servers) { - const json = await server.feed.getJSON({ feed: 'videos', ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(2) - expect(jsonObj.items[0].attachments).to.exist - expect(jsonObj.items[0].attachments.length).to.be.eq(1) - expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent') - expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910) - expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent') - } - }) - - it('Should filter by account', async function () { - { - const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: rootAccountId }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('my super name for server 1') - expect(jsonObj.items[0].author.name).to.equal('Main root channel') - } - - { - const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: userAccountId }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('user video') - expect(jsonObj.items[0].author.name).to.equal('Main john channel') - } - - for (const server of servers) { - { - const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'root@' + servers[0].host }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('my super name for server 1') - } - - { - const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'john@' + servers[0].host }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('user video') - } - } - }) - - it('Should filter by video channel', async function () { - { - const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('my super name for server 1') - expect(jsonObj.items[0].author.name).to.equal('Main root channel') - } - - { - const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: userChannelId }, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('user video') - expect(jsonObj.items[0].author.name).to.equal('Main john channel') - } - - for (const server of servers) { - { - const query = { videoChannelName: 'root_channel@' + servers[0].host } - const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('my super name for server 1') - } - - { - const query = { videoChannelName: 'john_channel@' + servers[0].host } - const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].title).to.equal('user video') - } - } - }) - - it('Should correctly have videos feed with HLS only', async function () { - this.timeout(120000) - - const json = await serverHLSOnly.feed.getJSON({ feed: 'videos', ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) - expect(jsonObj.items[0].attachments).to.exist - expect(jsonObj.items[0].attachments.length).to.be.eq(4) - - for (let i = 0; i < 4; i++) { - expect(jsonObj.items[0].attachments[i].mime_type).to.be.eq('application/x-bittorrent') - expect(jsonObj.items[0].attachments[i].size_in_bytes).to.be.greaterThan(0) - expect(jsonObj.items[0].attachments[i].url).to.exist - } - }) - - it('Should not display waiting live videos', async function () { - const { uuid } = await servers[0].live.create({ - fields: { - name: 'live', - privacy: VideoPrivacy.PUBLIC, - channelId: rootChannelId - } - }) - liveId = uuid - - const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) - - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(2) - expect(jsonObj.items[0].title).to.equal('my super name for server 1') - expect(jsonObj.items[1].title).to.equal('user video') - }) - - it('Should display published live videos', async function () { - this.timeout(120000) - - const ffmpeg = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveId, copyCodecs: true, fixtureName: 'video_short.mp4' }) - await servers[0].live.waitUntilPublished({ videoId: liveId }) - - const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) - - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(3) - expect(jsonObj.items[0].title).to.equal('live') - expect(jsonObj.items[1].title).to.equal('my super name for server 1') - expect(jsonObj.items[2].title).to.equal('user video') - - await stopFfmpeg(ffmpeg) - }) - - it('Should have the channel avatar as feed icon', async function () { - const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) - - const jsonObj = JSON.parse(json) - const imageUrl = jsonObj.icon - expect(imageUrl).to.include('/lazy-static/avatars/') - await makeRawRequest({ url: imageUrl, expectedStatus: HttpStatusCode.OK_200 }) - }) - }) - }) - - describe('Video comments feed', function () { - - it('Should contain valid comments (covers JSON feed 1.0 endpoint) and not from unlisted/password protected videos', async function () { - for (const server of servers) { - const json = await server.feed.getJSON({ feed: 'video-comments', ignoreCache: true }) - - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(2) - expect(jsonObj.items[0].content_html).to.contain('

super comment 2

') - expect(jsonObj.items[1].content_html).to.contain('

super comment 1

') - } - }) - - it('Should not list comments from muted accounts or instances', async function () { - this.timeout(30000) - - const remoteHandle = 'root@' + servers[0].host - - await servers[1].blocklist.addToServerBlocklist({ account: remoteHandle }) - - { - const json = await servers[1].feed.getJSON({ feed: 'video-comments', ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(0) - } - - await servers[1].blocklist.removeFromServerBlocklist({ account: remoteHandle }) - - { - const videoUUID = (await servers[1].videos.quickUpload({ name: 'server 2' })).uuid - await waitJobs(servers) - await servers[0].comments.createThread({ videoId: videoUUID, text: 'super comment' }) - await waitJobs(servers) - - const json = await servers[1].feed.getJSON({ feed: 'video-comments', ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(3) - } - - await servers[1].blocklist.addToMyBlocklist({ account: remoteHandle }) - - { - const json = await servers[1].feed.getJSON({ feed: 'video-comments', ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(2) - } - }) - }) - - describe('Video feed from my subscriptions', function () { - let feeduserAccountId: number - let feeduserFeedToken: string - - it('Should list no videos for a user with no videos and no subscriptions', async function () { - const attr = { username: 'feeduser', password: 'password' } - await servers[0].users.create({ username: attr.username, password: attr.password }) - const feeduserAccessToken = await servers[0].login.getAccessToken(attr) - - { - const user = await servers[0].users.getMyInfo({ token: feeduserAccessToken }) - feeduserAccountId = user.account.id - } - - { - const token = await servers[0].users.getMyScopedTokens({ token: feeduserAccessToken }) - feeduserFeedToken = token.feedToken - } - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: feeduserAccessToken }) - expect(body.total).to.equal(0) - - const query = { accountId: feeduserAccountId, token: feeduserFeedToken } - const json = await servers[0].feed.getJSON({ feed: 'subscriptions', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(0) // no subscription, it should not list the instance's videos but list 0 videos - } - }) - - it('Should fail with an invalid token', async function () { - const query = { accountId: feeduserAccountId, token: 'toto' } - await servers[0].feed.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403, ignoreCache: true }) - }) - - it('Should fail with a token of another user', async function () { - const query = { accountId: feeduserAccountId, token: userFeedToken } - await servers[0].feed.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403, ignoreCache: true }) - }) - - it('Should list no videos for a user with videos but no subscriptions', async function () { - const body = await servers[0].videos.listMySubscriptionVideos({ token: userAccessToken }) - expect(body.total).to.equal(0) - - const query = { accountId: userAccountId, token: userFeedToken } - const json = await servers[0].feed.getJSON({ feed: 'subscriptions', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(0) // no subscription, it should not list the instance's videos but list 0 videos - }) - - it('Should list self videos for a user with a subscription to themselves', async function () { - this.timeout(30000) - - await servers[0].subscriptions.add({ token: userAccessToken, targetUri: 'john_channel@' + servers[0].host }) - await waitJobs(servers) - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: userAccessToken }) - expect(body.total).to.equal(1) - expect(body.data[0].name).to.equal('user video') - - const query = { accountId: userAccountId, token: userFeedToken } - const json = await servers[0].feed.getJSON({ feed: 'subscriptions', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(1) // subscribed to self, it should not list the instance's videos but list john's - } - }) - - it('Should list videos of a user\'s subscription', async function () { - this.timeout(30000) - - await servers[0].subscriptions.add({ token: userAccessToken, targetUri: 'root_channel@' + servers[0].host }) - await waitJobs(servers) - - { - const body = await servers[0].videos.listMySubscriptionVideos({ token: userAccessToken }) - expect(body.total).to.equal(2, 'there should be 2 videos part of the subscription') - - const query = { accountId: userAccountId, token: userFeedToken } - const json = await servers[0].feed.getJSON({ feed: 'subscriptions', query, ignoreCache: true }) - const jsonObj = JSON.parse(json) - expect(jsonObj.items.length).to.be.equal(2) // subscribed to root, it should not list the instance's videos but list root/john's - } - }) - - it('Should renew the token, and so have an invalid old token', async function () { - await servers[0].users.renewMyScopedTokens({ token: userAccessToken }) - - const query = { accountId: userAccountId, token: userFeedToken } - await servers[0].feed.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403, ignoreCache: true }) - }) - - it('Should succeed with the new token', async function () { - const token = await servers[0].users.getMyScopedTokens({ token: userAccessToken }) - userFeedToken = token.feedToken - - const query = { accountId: userAccountId, token: userFeedToken } - await servers[0].feed.getJSON({ feed: 'subscriptions', query, ignoreCache: true }) - }) - - }) - - describe('Cache', function () { - const uuids: string[] = [] - - function doPodcastRequest () { - return makeGetRequest({ - url: servers[0].url, - path: '/feeds/podcast/videos.xml', - query: { videoChannelId: servers[0].store.channel.id }, - accept: 'application/xml', - expectedStatus: HttpStatusCode.OK_200 - }) - } - - function doVideosRequest (query: { [id: string]: string } = {}) { - return makeGetRequest({ - url: servers[0].url, - path: '/feeds/videos.xml', - query, - accept: 'application/xml', - expectedStatus: HttpStatusCode.OK_200 - }) - } - - before(async function () { - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'cache 1' }) - uuids.push(uuid) - } - - { - const { uuid } = await servers[0].videos.quickUpload({ name: 'cache 2' }) - uuids.push(uuid) - } - }) - - it('Should serve the videos endpoint as a cached request', async function () { - await doVideosRequest() - - const res = await doVideosRequest() - - expect(res.headers['x-api-cache-cached']).to.equal('true') - }) - - it('Should not serve the videos endpoint as a cached request', async function () { - const res = await doVideosRequest({ v: '186' }) - - expect(res.headers['x-api-cache-cached']).to.not.exist - }) - - it('Should invalidate the podcast feed cache after video deletion', async function () { - await doPodcastRequest() - - { - const res = await doPodcastRequest() - expect(res.headers['x-api-cache-cached']).to.exist - } - - await servers[0].videos.remove({ id: uuids[0] }) - - { - const res = await doPodcastRequest() - expect(res.headers['x-api-cache-cached']).to.not.exist - } - }) - - it('Should invalidate the podcast feed cache after video deletion, even after server restart', async function () { - this.timeout(120000) - - await doPodcastRequest() - - { - const res = await doPodcastRequest() - expect(res.headers['x-api-cache-cached']).to.exist - } - - await servers[0].kill() - await servers[0].run() - - await servers[0].videos.remove({ id: uuids[1] }) - - const res = await doPodcastRequest() - expect(res.headers['x-api-cache-cached']).to.not.exist - }) - - }) - - after(async function () { - await servers[0].plugins.uninstall({ npmName: 'peertube-plugin-test-podcast-custom-tags' }) - - await cleanupTests([ ...servers, serverHLSOnly ]) - }) -}) diff --git a/server/tests/feeds/index.ts b/server/tests/feeds/index.ts deleted file mode 100644 index aa6236a91..000000000 --- a/server/tests/feeds/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './feeds' diff --git a/server/tests/fixtures/60fps_720p_small.mp4 b/server/tests/fixtures/60fps_720p_small.mp4 deleted file mode 100644 index 74bf968a4..000000000 Binary files a/server/tests/fixtures/60fps_720p_small.mp4 and /dev/null differ diff --git a/server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json b/server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json deleted file mode 100644 index 4e7bc3af5..000000000 --- a/server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "headers": { - "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", - "host": "localhost", - "date": "Mon, 22 Oct 2018 13:34:22 GMT", - "accept-encoding": "gzip", - "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", - "content-type": "application/activity+json", - "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl5wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", - "content-length": "2815" - }, - "body": { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", - "type": "Create", - "actor": "http://localhost:3000/users/ronan2", - "published": "2018-10-22T13:34:18Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "object": { - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "type": "Note", - "summary": null, - "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "published": "2018-10-22T13:34:18Z", - "url": "http://localhost:3000/@ronan2/100939547203370948", - "attributedTo": "http://localhost:3000/users/ronan2", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "sensitive": false, - "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", - "content": "

@ronan zergzerg

", - "contentMap": { - "en": "

@ronan zergzerg

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "http://localhost:9000/accounts/ronan", - "name": "@ronan@localhost:9000" - } - ] - }, - "signature": { - "type": "RsaSignature2017", - "creator": "http://localhost:3000/users/ronan2#main-key", - "created": "2018-10-22T13:34:19Z", - "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" - } - } -} diff --git a/server/tests/fixtures/ap-json/mastodon/bad-http-signature.json b/server/tests/fixtures/ap-json/mastodon/bad-http-signature.json deleted file mode 100644 index 098597db0..000000000 --- a/server/tests/fixtures/ap-json/mastodon/bad-http-signature.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "headers": { - "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", - "host": "localhost", - "date": "Mon, 22 Oct 2018 13:34:22 GMT", - "accept-encoding": "gzip", - "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", - "content-type": "application/activity+json", - "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl4wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", - "content-length": "2815" - }, - "body": { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", - "type": "Create", - "actor": "http://localhost:3000/users/ronan2", - "published": "2018-10-22T13:34:18Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "object": { - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "type": "Note", - "summary": null, - "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "published": "2018-10-22T13:34:18Z", - "url": "http://localhost:3000/@ronan2/100939547203370948", - "attributedTo": "http://localhost:3000/users/ronan2", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "sensitive": false, - "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", - "content": "

@ronan zergzerg

", - "contentMap": { - "en": "

@ronan zergzerg

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "http://localhost:9000/accounts/ronan", - "name": "@ronan@localhost:9000" - } - ] - }, - "signature": { - "type": "RsaSignature2017", - "creator": "http://localhost:3000/users/ronan2#main-key", - "created": "2018-10-22T13:34:19Z", - "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" - } - } -} diff --git a/server/tests/fixtures/ap-json/mastodon/bad-public-key.json b/server/tests/fixtures/ap-json/mastodon/bad-public-key.json deleted file mode 100644 index 73d18b3ad..000000000 --- a/server/tests/fixtures/ap-json/mastodon/bad-public-key.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YyuthHtWWgDe0Fdgdp2\ndC5dTJsRqW6pFw5omIYYYjoES/WRewhVxEA54BhmxD3L1zChfx131N1TS8jVowhW\nm999jpUffKCCvLgYKIXETJDHiDeMONVx8wp7v9fS1HiFXo/E5und39gUMs14CMFZ\n6PE5jRV3r4XIKQJHQl7/X5n5FOb2934K+1TKUeBkbft/AushlKatYQakt3qHxpwx\nFvE+JjGo7QTnzdjaOx/e5QvojdGi2Kx4+jl77j2WVcSo5lOBz04OAVJtChtn82vS\nulPdDh3hZcDn+WK67yAhGP6AnzvOybZZS4zowlKiQ3kqjVVXKdl8gAsL4Y7MZ40R\nJQIDAQAB\n-----END PUBLIC KEY-----\n" -} diff --git a/server/tests/fixtures/ap-json/mastodon/create-bad-signature.json b/server/tests/fixtures/ap-json/mastodon/create-bad-signature.json deleted file mode 100644 index 2cd037241..000000000 --- a/server/tests/fixtures/ap-json/mastodon/create-bad-signature.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698/activity", - "type": "Create", - "actor": "http://localhost:3000/users/ronan2", - "published": "2018-10-22T12:43:07Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "object": { - "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698", - "type": "Note", - "summary": null, - "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "published": "2018-10-22T12:43:07Z", - "url": "http://localhost:3000/@ronan2/100939345950887698", - "attributedTo": "http://localhost:3000/users/ronan2", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "sensitive": false, - "atomUri": "http://localhost:3000/users/ronan2/statuses/100939345950887698", - "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", - "content": "

@ronan zerg

", - "contentMap": { - "en": "

@ronan zerg

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "http://localhost:9000/accounts/ronan", - "name": "@ronan@localhost:9000" - } - ] - }, - "signature": { - "type": "RsaSignature2017", - "creator": "http://localhost:3000/users/ronan2#main-key", - "created": "2018-10-22T12:43:08Z", - "signatureValue": "Vgr8nA0agPr9TcA4BlX+MWhmuE+rBcoIJLpnPbm3E5SnOCXbgjEfEaTLqfuzzkKNsR3PBbkvi3YWK4/DxJ0zmpzSB7yy4NRzluQMVQHqJiFKXAX3Sr3fIrK24xkWW9/F207c1NpFajSGbgnFKBdtFE0e5VqwSrSoOJkZukZW/2ATSnsyzblieuUmvTWpD0PqpUOsynPjw+RqZnqPn0cjw1z2Dm7ZRt3trnyMTXFYZw5U/YuqMY2kpadD6vq780md8kXlJIylxG6ZrlO2jz9fJdnfuVq43d4QFNsBm1K1r2WtNqX+i+wiqh+u3PjF4pzXtl/a3hJOH18IfZnK7I21mQ==" - } -} diff --git a/server/tests/fixtures/ap-json/mastodon/create.json b/server/tests/fixtures/ap-json/mastodon/create.json deleted file mode 100644 index 0be271bb8..000000000 --- a/server/tests/fixtures/ap-json/mastodon/create.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698/activity", - "type": "Create", - "actor": "http://localhost:3000/users/ronan2", - "published": "2018-10-22T12:43:07Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "object": { - "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698", - "type": "Note", - "summary": null, - "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "published": "2018-10-22T12:43:07Z", - "url": "http://localhost:3000/@ronan2/100939345950887698", - "attributedTo": "http://localhost:3000/users/ronan2", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "sensitive": false, - "atomUri": "http://localhost:3000/users/ronan2/statuses/100939345950887698", - "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", - "content": "

@ronan zerg

", - "contentMap": { - "en": "

@ronan zerg

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "http://localhost:9000/accounts/ronan", - "name": "@ronan@localhost:9000" - } - ] - }, - "signature": { - "type": "RsaSignature2017", - "creator": "http://localhost:3000/users/ronan2#main-key", - "created": "2018-10-22T12:43:08Z", - "signatureValue": "VgR8nA0agPr9TcA4BlX+MWhmuE+rBcoIJLpnPbm3E5SnOCXbgjEfEaTLqfuzzkKNsR3PBbkvi3YWK4/DxJ0zmpzSB7yy4NRzluQMVQHqJiFKXAX3Sr3fIrK24xkWW9/F207c1NpFajSGbgnFKBdtFE0e5VqwSrSoOJkZukZW/2ATSnsyzblieuUmvTWpD0PqpUOsynPjw+RqZnqPn0cjw1z2Dm7ZRt3trnyMTXFYZw5U/YuqMY2kpadD6vq780md8kXlJIylxG6ZrlO2jz9fJdnfuVq43d4QFNsBm1K1r2WtNqX+i+wiqh+u3PjF4pzXtl/a3hJOH18IfZnK7I21mQ==" - } -} diff --git a/server/tests/fixtures/ap-json/mastodon/http-signature.json b/server/tests/fixtures/ap-json/mastodon/http-signature.json deleted file mode 100644 index 4e7bc3af5..000000000 --- a/server/tests/fixtures/ap-json/mastodon/http-signature.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "headers": { - "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", - "host": "localhost", - "date": "Mon, 22 Oct 2018 13:34:22 GMT", - "accept-encoding": "gzip", - "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", - "content-type": "application/activity+json", - "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl5wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", - "content-length": "2815" - }, - "body": { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", - "type": "Create", - "actor": "http://localhost:3000/users/ronan2", - "published": "2018-10-22T13:34:18Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "object": { - "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "type": "Note", - "summary": null, - "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "published": "2018-10-22T13:34:18Z", - "url": "http://localhost:3000/@ronan2/100939547203370948", - "attributedTo": "http://localhost:3000/users/ronan2", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "http://localhost:3000/users/ronan2/followers", - "http://localhost:9000/accounts/ronan" - ], - "sensitive": false, - "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", - "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", - "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", - "content": "

@ronan zergzerg

", - "contentMap": { - "en": "

@ronan zergzerg

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "http://localhost:9000/accounts/ronan", - "name": "@ronan@localhost:9000" - } - ] - }, - "signature": { - "type": "RsaSignature2017", - "creator": "http://localhost:3000/users/ronan2#main-key", - "created": "2018-10-22T13:34:19Z", - "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" - } - } -} diff --git a/server/tests/fixtures/ap-json/mastodon/public-key.json b/server/tests/fixtures/ap-json/mastodon/public-key.json deleted file mode 100644 index b7b9b8308..000000000 --- a/server/tests/fixtures/ap-json/mastodon/public-key.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YyuthHtWWgDe0Fdgdp2\ndC5dTJsRqW6pFw5omIYYYjoES/WRewhVxEA54BhmxD3L1zChfx131N1TS8jVowhW\nm999jpUffKCCvLgYKIXETJDHiDeMONVx8wp7v9fS1HiFXo/E5und39gUMs14CMFZ\n6PE5jRV3r4XIKQJHQl7/X5n5FOb2934K+1TKUeBkbft/AushlKatYQakt3qHxpwx\nFvE+JjGo7QTnzdjaOx/e5QvojdGi2Kx4+jl87j2WVcSo5lOBz04OAVJtChtn82vS\nulPdDh3hZcDn+WK67yAhGP6AnzvOybZZS4zowlKiQ3kqjVVXKdl8gAsL4Y7MZ40R\nJQIDAQAB\n-----END PUBLIC KEY-----\n" -} diff --git a/server/tests/fixtures/ap-json/peertube/announce-without-context.json b/server/tests/fixtures/ap-json/peertube/announce-without-context.json deleted file mode 100644 index cda1c514c..000000000 --- a/server/tests/fixtures/ap-json/peertube/announce-without-context.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "Announce", - "id": "http://127.0.0.1:9002/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05/announces/1", - "actor": "http://127.0.0.1:9002/accounts/peertube", - "object": "http://127.0.0.1:9002/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05", - "to": [ - "https://www.w3.org/ns/activitystreams#Public", - "http://127.0.0.1:9002/accounts/peertube/followers", - "http://127.0.0.1:9002/video-channels/root_channel/followers", - "http://127.0.0.1:9002/accounts/root/followers" - ], - "cc": [] -} diff --git a/server/tests/fixtures/ap-json/peertube/invalid-keys.json b/server/tests/fixtures/ap-json/peertube/invalid-keys.json deleted file mode 100644 index 0544e96b9..000000000 --- a/server/tests/fixtures/ap-json/peertube/invalid-keys.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw2Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n", - "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----" -} - - diff --git a/server/tests/fixtures/ap-json/peertube/keys.json b/server/tests/fixtures/ap-json/peertube/keys.json deleted file mode 100644 index 1a7700865..000000000 --- a/server/tests/fixtures/ap-json/peertube/keys.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n", - "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----" -} diff --git a/server/tests/fixtures/avatar-big.png b/server/tests/fixtures/avatar-big.png deleted file mode 100644 index e593e40da..000000000 Binary files a/server/tests/fixtures/avatar-big.png and /dev/null differ diff --git a/server/tests/fixtures/avatar-resized-120x120.gif b/server/tests/fixtures/avatar-resized-120x120.gif deleted file mode 100644 index 81a82189e..000000000 Binary files a/server/tests/fixtures/avatar-resized-120x120.gif and /dev/null differ diff --git a/server/tests/fixtures/avatar-resized-120x120.png b/server/tests/fixtures/avatar-resized-120x120.png deleted file mode 100644 index 9d84151f8..000000000 Binary files a/server/tests/fixtures/avatar-resized-120x120.png and /dev/null differ diff --git a/server/tests/fixtures/avatar-resized-48x48.gif b/server/tests/fixtures/avatar-resized-48x48.gif deleted file mode 100644 index 5900ff12e..000000000 Binary files a/server/tests/fixtures/avatar-resized-48x48.gif and /dev/null differ diff --git a/server/tests/fixtures/avatar-resized-48x48.png b/server/tests/fixtures/avatar-resized-48x48.png deleted file mode 100644 index 9e5f3b490..000000000 Binary files a/server/tests/fixtures/avatar-resized-48x48.png and /dev/null differ diff --git a/server/tests/fixtures/avatar.gif b/server/tests/fixtures/avatar.gif deleted file mode 100644 index f29707760..000000000 Binary files a/server/tests/fixtures/avatar.gif and /dev/null differ diff --git a/server/tests/fixtures/avatar.png b/server/tests/fixtures/avatar.png deleted file mode 100644 index 4b7fd2c0a..000000000 Binary files a/server/tests/fixtures/avatar.png and /dev/null differ diff --git a/server/tests/fixtures/avatar2-resized-120x120.png b/server/tests/fixtures/avatar2-resized-120x120.png deleted file mode 100644 index 44149facb..000000000 Binary files a/server/tests/fixtures/avatar2-resized-120x120.png and /dev/null differ diff --git a/server/tests/fixtures/avatar2-resized-48x48.png b/server/tests/fixtures/avatar2-resized-48x48.png deleted file mode 100644 index bb3939b1a..000000000 Binary files a/server/tests/fixtures/avatar2-resized-48x48.png and /dev/null differ diff --git a/server/tests/fixtures/avatar2.png b/server/tests/fixtures/avatar2.png deleted file mode 100644 index dae702190..000000000 Binary files a/server/tests/fixtures/avatar2.png and /dev/null differ diff --git a/server/tests/fixtures/banner-resized.jpg b/server/tests/fixtures/banner-resized.jpg deleted file mode 100644 index 952732d61..000000000 Binary files a/server/tests/fixtures/banner-resized.jpg and /dev/null differ diff --git a/server/tests/fixtures/banner.jpg b/server/tests/fixtures/banner.jpg deleted file mode 100644 index e5f284f59..000000000 Binary files a/server/tests/fixtures/banner.jpg and /dev/null differ diff --git a/server/tests/fixtures/custom-preview-big.png b/server/tests/fixtures/custom-preview-big.png deleted file mode 100644 index 03d171af3..000000000 Binary files a/server/tests/fixtures/custom-preview-big.png and /dev/null differ diff --git a/server/tests/fixtures/custom-preview.jpg b/server/tests/fixtures/custom-preview.jpg deleted file mode 100644 index 5a039d830..000000000 Binary files a/server/tests/fixtures/custom-preview.jpg and /dev/null differ diff --git a/server/tests/fixtures/custom-thumbnail-big.jpg b/server/tests/fixtures/custom-thumbnail-big.jpg deleted file mode 100644 index 08375e425..000000000 Binary files a/server/tests/fixtures/custom-thumbnail-big.jpg and /dev/null differ diff --git a/server/tests/fixtures/custom-thumbnail.jpg b/server/tests/fixtures/custom-thumbnail.jpg deleted file mode 100644 index ef818442d..000000000 Binary files a/server/tests/fixtures/custom-thumbnail.jpg and /dev/null differ diff --git a/server/tests/fixtures/custom-thumbnail.png b/server/tests/fixtures/custom-thumbnail.png deleted file mode 100644 index 9f34daec1..000000000 Binary files a/server/tests/fixtures/custom-thumbnail.png and /dev/null differ diff --git a/server/tests/fixtures/exif.jpg b/server/tests/fixtures/exif.jpg deleted file mode 100644 index 2997b38e9..000000000 Binary files a/server/tests/fixtures/exif.jpg and /dev/null differ diff --git a/server/tests/fixtures/exif.png b/server/tests/fixtures/exif.png deleted file mode 100644 index a1a0113f8..000000000 Binary files a/server/tests/fixtures/exif.png and /dev/null differ diff --git a/server/tests/fixtures/live/0-000067.ts b/server/tests/fixtures/live/0-000067.ts deleted file mode 100644 index a59f41a63..000000000 Binary files a/server/tests/fixtures/live/0-000067.ts and /dev/null differ diff --git a/server/tests/fixtures/live/0-000068.ts b/server/tests/fixtures/live/0-000068.ts deleted file mode 100644 index 83dcbbb4c..000000000 Binary files a/server/tests/fixtures/live/0-000068.ts and /dev/null differ diff --git a/server/tests/fixtures/live/0-000069.ts b/server/tests/fixtures/live/0-000069.ts deleted file mode 100644 index cafd4e978..000000000 Binary files a/server/tests/fixtures/live/0-000069.ts and /dev/null differ diff --git a/server/tests/fixtures/live/0-000070.ts b/server/tests/fixtures/live/0-000070.ts deleted file mode 100644 index 0936199ea..000000000 Binary files a/server/tests/fixtures/live/0-000070.ts and /dev/null differ diff --git a/server/tests/fixtures/live/0.m3u8 b/server/tests/fixtures/live/0.m3u8 deleted file mode 100644 index c3be19d26..000000000 --- a/server/tests/fixtures/live/0.m3u8 +++ /dev/null @@ -1,14 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:6 -#EXT-X-TARGETDURATION:2 -#EXT-X-MEDIA-SEQUENCE:68 -#EXT-X-INDEPENDENT-SEGMENTS -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:39.019+0200 -0-000068.ts -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:41.019+0200 -0-000069.ts -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:43.019+0200 -0-000070. diff --git a/server/tests/fixtures/live/1-000067.ts b/server/tests/fixtures/live/1-000067.ts deleted file mode 100644 index 17db8f81e..000000000 Binary files a/server/tests/fixtures/live/1-000067.ts and /dev/null differ diff --git a/server/tests/fixtures/live/1-000068.ts b/server/tests/fixtures/live/1-000068.ts deleted file mode 100644 index f7bb97040..000000000 Binary files a/server/tests/fixtures/live/1-000068.ts and /dev/null differ diff --git a/server/tests/fixtures/live/1-000069.ts b/server/tests/fixtures/live/1-000069.ts deleted file mode 100644 index 64c791337..000000000 Binary files a/server/tests/fixtures/live/1-000069.ts and /dev/null differ diff --git a/server/tests/fixtures/live/1-000070.ts b/server/tests/fixtures/live/1-000070.ts deleted file mode 100644 index a5f04f109..000000000 Binary files a/server/tests/fixtures/live/1-000070.ts and /dev/null differ diff --git a/server/tests/fixtures/live/1.m3u8 b/server/tests/fixtures/live/1.m3u8 deleted file mode 100644 index 26d7fa6b0..000000000 --- a/server/tests/fixtures/live/1.m3u8 +++ /dev/null @@ -1,14 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:6 -#EXT-X-TARGETDURATION:2 -#EXT-X-MEDIA-SEQUENCE:68 -#EXT-X-INDEPENDENT-SEGMENTS -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:39.019+0200 -1-000068.ts -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:41.019+0200 -1-000069.ts -#EXTINF:2.000000, -#EXT-X-PROGRAM-DATE-TIME:2023-04-18T13:38:43.019+0200 -1-000070.ts diff --git a/server/tests/fixtures/live/master.m3u8 b/server/tests/fixtures/live/master.m3u8 deleted file mode 100644 index 7e52f33cf..000000000 --- a/server/tests/fixtures/live/master.m3u8 +++ /dev/null @@ -1,8 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:6 -#EXT-X-STREAM-INF:BANDWIDTH=1287342,RESOLUTION=640x360,CODECS="avc1.64001f,mp4a.40.2" -0.m3u8 - -#EXT-X-STREAM-INF:BANDWIDTH=3051742,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2" -1.m3u8 - diff --git a/server/tests/fixtures/low-bitrate.mp4 b/server/tests/fixtures/low-bitrate.mp4 deleted file mode 100644 index 69004eccc..000000000 Binary files a/server/tests/fixtures/low-bitrate.mp4 and /dev/null differ diff --git a/server/tests/fixtures/peertube-plugin-test-broken/main.js b/server/tests/fixtures/peertube-plugin-test-broken/main.js deleted file mode 100644 index afdb6f7a0..000000000 --- a/server/tests/fixtures/peertube-plugin-test-broken/main.js +++ /dev/null @@ -1,12 +0,0 @@ -async function register (options) { - options.unknownFunction() -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-broken/package.json b/server/tests/fixtures/peertube-plugin-test-broken/package.json deleted file mode 100644 index fd03df216..000000000 --- a/server/tests/fixtures/peertube-plugin-test-broken/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-broken", - "version": "0.0.1", - "description": "Plugin test broken", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js b/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js deleted file mode 100644 index 58bc27661..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js +++ /dev/null @@ -1,85 +0,0 @@ -async function register ({ - registerExternalAuth, - peertubeHelpers, - settingsManager, - unregisterExternalAuth -}) { - { - const result = registerExternalAuth({ - authName: 'external-auth-1', - authDisplayName: () => 'External Auth 1', - onLogout: user => peertubeHelpers.logger.info('On logout %s', user.username), - onAuthRequest: (req, res) => { - const username = req.query.username - - result.userAuthenticated({ - req, - res, - username, - email: username + '@example.com' - }) - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-2', - authDisplayName: () => 'External Auth 2', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'kefka', - email: 'kefka@example.com', - role: 0, - displayName: 'Kefka Palazzo', - adminFlags: 1, - videoQuota: 42000, - videoQuotaDaily: 42100, - - // Always use new value except for videoQuotaDaily field - userUpdater: ({ fieldName, currentValue, newValue }) => { - if (fieldName === 'videoQuotaDaily') return currentValue - - return newValue - } - }) - }, - hookTokenValidity: (options) => { - if (options.type === 'refresh') { - return { valid: false } - } - - if (options.type === 'access') { - const token = options.token - const now = new Date() - now.setTime(now.getTime() - 5000) - - const createdAt = new Date(token.createdAt) - - return { valid: createdAt.getTime() >= now.getTime() } - } - - return { valid: true } - } - }) - } - - settingsManager.onSettingsChange(settings => { - if (settings.disableKefka) { - unregisterExternalAuth('external-auth-2') - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-one/package.json b/server/tests/fixtures/peertube-plugin-test-external-auth-one/package.json deleted file mode 100644 index 22814b047..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-one/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-external-auth-one", - "version": "0.0.1", - "description": "External auth one", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-three/main.js b/server/tests/fixtures/peertube-plugin-test-external-auth-three/main.js deleted file mode 100644 index 30cedccc6..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-three/main.js +++ /dev/null @@ -1,53 +0,0 @@ -async function register ({ - registerExternalAuth, - peertubeHelpers -}) { - { - const result = registerExternalAuth({ - authName: 'external-auth-7', - authDisplayName: () => 'External Auth 7', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'cid', - email: 'cid@example.com', - displayName: 'Cid Marquez' - }) - }, - onLogout: (user, req) => { - return 'https://example.com/redirectUrl' - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-8', - authDisplayName: () => 'External Auth 8', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'cid', - email: 'cid@example.com', - displayName: 'Cid Marquez' - }) - }, - onLogout: (user, req) => { - return 'https://example.com/redirectUrl?access_token=' + req.headers['authorization'].split(' ')[1] - } - }) - } -} - -async function unregister () { - -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-three/package.json b/server/tests/fixtures/peertube-plugin-test-external-auth-three/package.json deleted file mode 100644 index f323d189d..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-three/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-external-auth-three", - "version": "0.0.1", - "description": "External auth three", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-two/main.js b/server/tests/fixtures/peertube-plugin-test-external-auth-two/main.js deleted file mode 100644 index 755dbb62b..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-two/main.js +++ /dev/null @@ -1,95 +0,0 @@ -async function register ({ - registerExternalAuth, - peertubeHelpers -}) { - { - const result = registerExternalAuth({ - authName: 'external-auth-3', - authDisplayName: () => 'External Auth 3', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'cid', - email: 'cid@example.com', - displayName: 'Cid Marquez' - }) - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-4', - authDisplayName: () => 'External Auth 4', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'kefka2', - email: 'kefka@example.com', - displayName: 'Kefka duplication' - }) - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-5', - authDisplayName: () => 'External Auth 5', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'kefka', - email: 'kefka@example.com', - displayName: 'Kefka duplication' - }) - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-6', - authDisplayName: () => 'External Auth 6', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'existing_user', - email: 'existing_user@example.com', - displayName: 'Existing user' - }) - } - }) - } - - { - const result = registerExternalAuth({ - authName: 'external-auth-7', - authDisplayName: () => 'External Auth 7', - onAuthRequest: (req, res) => { - result.userAuthenticated({ - req, - res, - username: 'existing_user2', - email: 'custom_email_existing_user2@example.com', - displayName: 'Existing user 2' - }) - } - }) - } -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-two/package.json b/server/tests/fixtures/peertube-plugin-test-external-auth-two/package.json deleted file mode 100644 index a5ca4d07a..000000000 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-two/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-external-auth-two", - "version": "0.0.1", - "description": "External auth two", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json deleted file mode 100644 index 52d8313df..000000000 --- a/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Hello world": "Bonjour le monde" -} diff --git a/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json deleted file mode 100644 index 9e187d83b..000000000 --- a/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Hello world": "Ciao, mondo!" -} diff --git a/server/tests/fixtures/peertube-plugin-test-filter-translations/main.js b/server/tests/fixtures/peertube-plugin-test-filter-translations/main.js deleted file mode 100644 index 71c11b2ba..000000000 --- a/server/tests/fixtures/peertube-plugin-test-filter-translations/main.js +++ /dev/null @@ -1,21 +0,0 @@ -async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) { - registerHook({ - target: 'filter:api.videos.list.params', - handler: obj => addToCount(obj) - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ############################################################################ - -function addToCount (obj) { - return Object.assign({}, obj, { count: obj.count + 1 }) -} diff --git a/server/tests/fixtures/peertube-plugin-test-filter-translations/package.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/package.json deleted file mode 100644 index 2adce4743..000000000 --- a/server/tests/fixtures/peertube-plugin-test-filter-translations/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "peertube-plugin-test-filter-translations", - "version": "0.0.1", - "description": "Plugin test filter and translations", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": { - "fr-FR": "./languages/fr.json", - "it-IT": "./languages/it.json" - } -} diff --git a/server/tests/fixtures/peertube-plugin-test-five/main.js b/server/tests/fixtures/peertube-plugin-test-five/main.js deleted file mode 100644 index 07dd18654..000000000 --- a/server/tests/fixtures/peertube-plugin-test-five/main.js +++ /dev/null @@ -1,23 +0,0 @@ -async function register ({ - getRouter -}) { - const router = getRouter() - router.get('/ping', (req, res) => res.json({ message: 'pong' })) - - router.get('/is-authenticated', (req, res) => res.json({ isAuthenticated: res.locals.authenticated })) - - router.post('/form/post/mirror', (req, res) => { - res.json(req.body) - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-five/package.json b/server/tests/fixtures/peertube-plugin-test-five/package.json deleted file mode 100644 index 1f5d65d9d..000000000 --- a/server/tests/fixtures/peertube-plugin-test-five/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-five", - "version": "0.0.1", - "description": "Plugin test 5", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-four/main.js b/server/tests/fixtures/peertube-plugin-test-four/main.js deleted file mode 100644 index b10177b45..000000000 --- a/server/tests/fixtures/peertube-plugin-test-four/main.js +++ /dev/null @@ -1,201 +0,0 @@ -async function register ({ - peertubeHelpers, - registerHook, - getRouter -}) { - const logger = peertubeHelpers.logger - - logger.info('Hello world from plugin four') - - { - const username = 'root' - const results = await peertubeHelpers.database.query( - 'SELECT "email" from "user" WHERE "username" = $username', - { - type: 'SELECT', - bind: { username } - } - ) - - logger.info('root email is ' + results[0]['email']) - } - - { - registerHook({ - target: 'action:api.video.viewed', - handler: async ({ video }) => { - const videoFromDB1 = await peertubeHelpers.videos.loadByUrl(video.url) - const videoFromDB2 = await peertubeHelpers.videos.loadByIdOrUUID(video.id) - const videoFromDB3 = await peertubeHelpers.videos.loadByIdOrUUID(video.uuid) - - if (videoFromDB1.uuid !== videoFromDB2.uuid || videoFromDB2.uuid !== videoFromDB3.uuid) return - - logger.info('video from DB uuid is %s.', videoFromDB1.uuid) - - await peertubeHelpers.videos.removeVideo(video.id) - - logger.info('Video deleted by plugin four.') - } - }) - } - - { - const serverActor = await peertubeHelpers.server.getServerActor() - logger.info('server actor name is %s', serverActor.preferredUsername) - } - - { - logger.info('server url is %s', peertubeHelpers.config.getWebserverUrl()) - } - - { - const actions = { - blockServer, - unblockServer, - blockAccount, - unblockAccount, - blacklist, - unblacklist - } - - const router = getRouter() - router.post('/commander', async (req, res) => { - try { - await actions[req.body.command](peertubeHelpers, req.body) - - res.sendStatus(204) - } catch (err) { - logger.error('Error in commander.', { err }) - res.sendStatus(500) - } - }) - - router.get('/server-config', async (req, res) => { - const serverConfig = await peertubeHelpers.config.getServerConfig() - - return res.json({ serverConfig }) - }) - - router.get('/server-listening-config', async (req, res) => { - const config = await peertubeHelpers.config.getServerListeningConfig() - - return res.json({ config }) - }) - - router.get('/static-route', async (req, res) => { - const staticRoute = peertubeHelpers.plugin.getBaseStaticRoute() - - return res.json({ staticRoute }) - }) - - router.get('/router-route', async (req, res) => { - const routerRoute = peertubeHelpers.plugin.getBaseRouterRoute() - - return res.json({ routerRoute }) - }) - - router.get('/user/:id', async (req, res) => { - const user = await peertubeHelpers.user.loadById(req.params.id) - if (!user) return res.status(404).end() - - return res.json({ - username: user.username - }) - }) - - router.get('/user', async (req, res) => { - const user = await peertubeHelpers.user.getAuthUser(res) - if (!user) return res.sendStatus(404) - - const isAdmin = user.role === 0 - const isModerator = user.role === 1 - const isUser = user.role === 2 - - return res.json({ - id: user.id, - username: user.username, - displayName: user.Account.name, - isAdmin, - isModerator, - isUser - }) - }) - - router.get('/video-files/:id', async (req, res) => { - const details = await peertubeHelpers.videos.getFiles(req.params.id) - if (!details) return res.sendStatus(404) - - return res.json(details) - }) - - router.get('/ffprobe', async (req, res) => { - const result = await peertubeHelpers.videos.ffprobe(req.query.path) - if (!result) return res.sendStatus(404) - - return res.json(result) - }) - - router.post('/send-notification', async (req, res) => { - peertubeHelpers.socket.sendNotification(req.body.userId, { - type: 1, - userId: req.body.userId - }) - - return res.sendStatus(201) - }) - - router.post('/send-video-live-new-state/:uuid', async (req, res) => { - const video = await peertubeHelpers.videos.loadByIdOrUUID(req.params.uuid) - peertubeHelpers.socket.sendVideoLiveNewState(video) - - return res.sendStatus(201) - }) - } - -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### - -async function blockServer (peertubeHelpers, body) { - const serverActor = await peertubeHelpers.server.getServerActor() - - await peertubeHelpers.moderation.blockServer({ byAccountId: serverActor.Account.id, hostToBlock: body.hostToBlock }) -} - -async function unblockServer (peertubeHelpers, body) { - const serverActor = await peertubeHelpers.server.getServerActor() - - await peertubeHelpers.moderation.unblockServer({ byAccountId: serverActor.Account.id, hostToUnblock: body.hostToUnblock }) -} - -async function blockAccount (peertubeHelpers, body) { - const serverActor = await peertubeHelpers.server.getServerActor() - - await peertubeHelpers.moderation.blockAccount({ byAccountId: serverActor.Account.id, handleToBlock: body.handleToBlock }) -} - -async function unblockAccount (peertubeHelpers, body) { - const serverActor = await peertubeHelpers.server.getServerActor() - - await peertubeHelpers.moderation.unblockAccount({ byAccountId: serverActor.Account.id, handleToUnblock: body.handleToUnblock }) -} - -async function blacklist (peertubeHelpers, body) { - await peertubeHelpers.moderation.blacklistVideo({ - videoIdOrUUID: body.videoUUID, - createOptions: body - }) -} - -async function unblacklist (peertubeHelpers, body) { - await peertubeHelpers.moderation.unblacklistVideo({ videoIdOrUUID: body.videoUUID }) -} diff --git a/server/tests/fixtures/peertube-plugin-test-four/package.json b/server/tests/fixtures/peertube-plugin-test-four/package.json deleted file mode 100644 index dda3c7f37..000000000 --- a/server/tests/fixtures/peertube-plugin-test-four/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-four", - "version": "0.0.1", - "description": "Plugin test 4", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/main.js b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/main.js deleted file mode 100644 index f58faa847..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/main.js +++ /dev/null @@ -1,69 +0,0 @@ -async function register ({ - registerIdAndPassAuth, - peertubeHelpers, - settingsManager, - unregisterIdAndPassAuth -}) { - registerIdAndPassAuth({ - authName: 'spyro-auth', - - onLogout: () => { - peertubeHelpers.logger.info('On logout for auth 1 - 1') - }, - - getWeight: () => 15, - - login (body) { - if (body.id === 'spyro' && body.password === 'spyro password') { - return Promise.resolve({ - username: 'spyro', - email: 'spyro@example.com', - role: 2, - displayName: 'Spyro the Dragon' - }) - } - - return null - } - }) - - registerIdAndPassAuth({ - authName: 'crash-auth', - - onLogout: () => { - peertubeHelpers.logger.info('On logout for auth 1 - 2') - }, - - getWeight: () => 50, - - login (body) { - if (body.id === 'crash' && body.password === 'crash password') { - return Promise.resolve({ - username: 'crash', - email: 'crash@example.com', - role: 1, - displayName: 'Crash Bandicoot' - }) - } - - return null - } - }) - - settingsManager.onSettingsChange(settings => { - if (settings.disableSpyro) { - unregisterIdAndPassAuth('spyro-auth') - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/package.json b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/package.json deleted file mode 100644 index f8ad18a90..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-one/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-id-pass-auth-one", - "version": "0.0.1", - "description": "Id and pass auth one", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/main.js b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/main.js deleted file mode 100644 index 1200acfbd..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/main.js +++ /dev/null @@ -1,106 +0,0 @@ -async function register ({ - registerIdAndPassAuth, - peertubeHelpers -}) { - registerIdAndPassAuth({ - authName: 'laguna-bad-auth', - - onLogout: () => { - peertubeHelpers.logger.info('On logout for auth 3 - 1') - }, - - getWeight: () => 5, - - login (body) { - if (body.id === 'laguna' && body.password === 'laguna password') { - return Promise.resolve({ - username: 'laguna', - email: 'laguna@example.com', - displayName: 'Laguna Loire' - }) - } - - return null - } - }) - - registerIdAndPassAuth({ - authName: 'ward-auth', - - getWeight: () => 5, - - login (body) { - if (body.id === 'ward') { - return Promise.resolve({ - username: '-ward-42', - email: 'ward@example.com' - }) - } - - return null - } - }) - - registerIdAndPassAuth({ - authName: 'kiros-auth', - - getWeight: () => 5, - - login (body) { - if (body.id === 'kiros') { - return Promise.resolve({ - username: 'kiros', - email: 'kiros@example.com', - displayName: 'a'.repeat(5000) - }) - } - - return null - } - }) - - registerIdAndPassAuth({ - authName: 'raine-auth', - - getWeight: () => 5, - - login (body) { - if (body.id === 'raine') { - return Promise.resolve({ - username: 'raine', - email: 'raine@example.com', - role: 42 - }) - } - - return null - } - }) - - registerIdAndPassAuth({ - authName: 'ellone-auth', - - getWeight: () => 5, - - login (body) { - if (body.id === 'ellone') { - return Promise.resolve({ - username: 'ellone' - }) - } - - return null - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/package.json b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/package.json deleted file mode 100644 index f9f107b1a..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-three/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-id-pass-auth-three", - "version": "0.0.1", - "description": "Id and pass auth three", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/main.js b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/main.js deleted file mode 100644 index fad5abf60..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/main.js +++ /dev/null @@ -1,65 +0,0 @@ -async function register ({ - registerIdAndPassAuth, - peertubeHelpers -}) { - registerIdAndPassAuth({ - authName: 'laguna-auth', - - onLogout: () => { - peertubeHelpers.logger.info('On logout for auth 2 - 1') - }, - - getWeight: () => 30, - - hookTokenValidity: (options) => { - if (options.type === 'refresh') { - return { valid: false } - } - - if (options.type === 'access') { - const token = options.token - const now = new Date() - now.setTime(now.getTime() - 5000) - - const createdAt = new Date(token.createdAt) - - return { valid: createdAt.getTime() >= now.getTime() } - } - - return { valid: true } - }, - - login (body) { - if (body.id === 'laguna' && body.password === 'laguna password') { - return Promise.resolve({ - username: 'laguna', - email: 'laguna@example.com', - displayName: 'Laguna Loire', - adminFlags: 1, - videoQuota: 42000, - videoQuotaDaily: 42100, - - // Always use new value except for videoQuotaDaily field - userUpdater: ({ fieldName, currentValue, newValue }) => { - if (fieldName === 'videoQuotaDaily') return currentValue - - return newValue - } - }) - } - - return null - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/package.json b/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/package.json deleted file mode 100644 index 5df15fac1..000000000 --- a/server/tests/fixtures/peertube-plugin-test-id-pass-auth-two/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-id-pass-auth-two", - "version": "0.0.1", - "description": "Id and pass auth two", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-native/main.js b/server/tests/fixtures/peertube-plugin-test-native/main.js deleted file mode 100644 index 0390faea9..000000000 --- a/server/tests/fixtures/peertube-plugin-test-native/main.js +++ /dev/null @@ -1,21 +0,0 @@ -const print = require('a-native-example') - -async function register ({ getRouter }) { - print('hello world') - - const router = getRouter() - - router.get('/', (req, res) => { - print('hello world') - res.sendStatus(204) - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-native/package.json b/server/tests/fixtures/peertube-plugin-test-native/package.json deleted file mode 100644 index a6525720b..000000000 --- a/server/tests/fixtures/peertube-plugin-test-native/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "peertube-plugin-test-native", - "version": "0.0.1", - "description": "Plugin test-native", - "engine": { - "peertube": ">=4.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {}, - "dependencies": { - "a-native-example": "^1.0.0" - } -} 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 deleted file mode 100644 index ada4a70fe..000000000 --- a/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js +++ /dev/null @@ -1,82 +0,0 @@ -async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) { - registerHook({ - target: 'filter:feed.podcast.rss.create-custom-xmlns.result', - handler: (result, params) => { - return result.concat([ - { - name: "biz", - value: "https://example.com/biz-xmlns", - }, - ]) - } - }) - - registerHook({ - target: 'filter:feed.podcast.channel.create-custom-tags.result', - handler: (result, params) => { - const { videoChannel } = params - return result.concat([ - { - name: "fooTag", - attributes: { "bar": "baz" }, - value: "42", - }, - { - name: "biz:videoChannel", - attributes: { "name": videoChannel.name, "id": videoChannel.id }, - }, - { - name: "biz:buzzItem", - value: [ - { - name: "nestedTag", - value: "example nested tag", - }, - ], - }, - ]) - } - }) - - registerHook({ - target: 'filter:feed.podcast.video.create-custom-tags.result', - handler: (result, params) => { - const { video, liveItem } = params - return result.concat([ - { - name: "fizzTag", - attributes: { "bar": "baz" }, - value: "21", - }, - { - name: "biz:video", - attributes: { "name": video.name, "id": video.id, "isLive": liveItem }, - }, - { - name: "biz:buzz", - value: [ - { - name: "nestedTag", - value: "example nested tag", - }, - ], - } - ]) - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ############################################################################ - -function addToCount (obj) { - return Object.assign({}, obj, { count: obj.count + 1 }) -} 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 deleted file mode 100644 index 0f5a05a79..000000000 --- a/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "peertube-plugin-test-podcast-custom-tags", - "version": "0.0.1", - "description": "Plugin test custom tags in Podcast RSS feeds", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [] -} diff --git a/server/tests/fixtures/peertube-plugin-test-six/main.js b/server/tests/fixtures/peertube-plugin-test-six/main.js deleted file mode 100644 index 243b041e7..000000000 --- a/server/tests/fixtures/peertube-plugin-test-six/main.js +++ /dev/null @@ -1,46 +0,0 @@ -const fs = require('fs') -const path = require('path') - -async function register ({ - storageManager, - peertubeHelpers, - getRouter -}) { - const { logger } = peertubeHelpers - - { - await storageManager.storeData('superkey', { value: 'toto' }) - await storageManager.storeData('anotherkey', { value: 'toto2' }) - await storageManager.storeData('storedArrayKey', ['toto', 'toto2']) - - const result = await storageManager.getData('superkey') - logger.info('superkey stored value is %s', result.value) - - const storedArrayValue = await storageManager.getData('storedArrayKey') - logger.info('storedArrayKey isArray is %s', Array.isArray(storedArrayValue) ? 'true' : 'false') - logger.info('storedArrayKey stored value is %s', storedArrayValue.join(', ')) - } - - { - getRouter().get('/create-file', async (req, res) => { - const basePath = peertubeHelpers.plugin.getDataDirectoryPath() - - fs.writeFile(path.join(basePath, 'Aladdin.txt'), 'Prince Ali', function (err) { - if (err) return res.sendStatus(500) - - res.sendStatus(200) - }) - }) - } -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-six/package.json b/server/tests/fixtures/peertube-plugin-test-six/package.json deleted file mode 100644 index 8c97826b0..000000000 --- a/server/tests/fixtures/peertube-plugin-test-six/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-six", - "version": "0.0.1", - "description": "Plugin test 6", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-transcoding-one/main.js b/server/tests/fixtures/peertube-plugin-test-transcoding-one/main.js deleted file mode 100644 index c4ae777f5..000000000 --- a/server/tests/fixtures/peertube-plugin-test-transcoding-one/main.js +++ /dev/null @@ -1,92 +0,0 @@ -async function register ({ transcodingManager }) { - - // Output options - { - { - const builder = () => { - return { - outputOptions: [ - '-r 10' - ] - } - } - - transcodingManager.addVODProfile('libx264', 'low-vod', builder) - } - - { - const builder = (options) => { - return { - outputOptions: [ - '-r:' + options.streamNum + ' 50' - ] - } - } - - transcodingManager.addLiveProfile('libx264', 'high-live', builder) - } - } - - // Input options - { - { - const builder = () => { - return { - inputOptions: [ - '-r 5' - ] - } - } - - transcodingManager.addVODProfile('libx264', 'input-options-vod', builder) - } - - { - const builder = () => { - return { - inputOptions: [ - '-r 50' - ] - } - } - - transcodingManager.addLiveProfile('libx264', 'input-options-live', builder) - } - } - - // Scale filters - { - { - const builder = () => { - return { - scaleFilter: { - name: 'Glomgold' - } - } - } - - transcodingManager.addVODProfile('libx264', 'bad-scale-vod', builder) - } - - { - const builder = () => { - return { - scaleFilter: { - name: 'Flintheart' - } - } - } - - transcodingManager.addLiveProfile('libx264', 'bad-scale-live', builder) - } - } -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-transcoding-one/package.json b/server/tests/fixtures/peertube-plugin-test-transcoding-one/package.json deleted file mode 100644 index bedbfa051..000000000 --- a/server/tests/fixtures/peertube-plugin-test-transcoding-one/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-transcoding-one", - "version": "0.0.1", - "description": "Plugin test transcoding 1", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-transcoding-two/main.js b/server/tests/fixtures/peertube-plugin-test-transcoding-two/main.js deleted file mode 100644 index a914bce49..000000000 --- a/server/tests/fixtures/peertube-plugin-test-transcoding-two/main.js +++ /dev/null @@ -1,38 +0,0 @@ -async function register ({ transcodingManager }) { - - { - const builder = () => { - return { - outputOptions: [] - } - } - - transcodingManager.addVODProfile('libopus', 'test-vod-profile', builder) - transcodingManager.addVODProfile('libvpx-vp9', 'test-vod-profile', builder) - - transcodingManager.addVODEncoderPriority('audio', 'libopus', 1000) - transcodingManager.addVODEncoderPriority('video', 'libvpx-vp9', 1000) - } - - { - const builder = (options) => { - return { - outputOptions: [ - '-b:' + options.streamNum + ' 10K' - ] - } - } - - transcodingManager.addLiveProfile('libopus', 'test-live-profile', builder) - transcodingManager.addLiveEncoderPriority('audio', 'libopus', 1000) - } -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-transcoding-two/package.json b/server/tests/fixtures/peertube-plugin-test-transcoding-two/package.json deleted file mode 100644 index 34be0454b..000000000 --- a/server/tests/fixtures/peertube-plugin-test-transcoding-two/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-transcoding-two", - "version": "0.0.1", - "description": "Plugin test transcoding 2", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-unloading/lib.js b/server/tests/fixtures/peertube-plugin-test-unloading/lib.js deleted file mode 100644 index f57e7cb01..000000000 --- a/server/tests/fixtures/peertube-plugin-test-unloading/lib.js +++ /dev/null @@ -1,2 +0,0 @@ -const d = new Date() -exports.value = d.getTime() diff --git a/server/tests/fixtures/peertube-plugin-test-unloading/main.js b/server/tests/fixtures/peertube-plugin-test-unloading/main.js deleted file mode 100644 index 5c8457cef..000000000 --- a/server/tests/fixtures/peertube-plugin-test-unloading/main.js +++ /dev/null @@ -1,14 +0,0 @@ -const lib = require('./lib') - -async function register ({ getRouter }) { - const router = getRouter() - router.get('/get', (req, res) => res.json({ message: lib.value })) -} - -async function unregister () { -} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-unloading/package.json b/server/tests/fixtures/peertube-plugin-test-unloading/package.json deleted file mode 100644 index 7076d4b6f..000000000 --- a/server/tests/fixtures/peertube-plugin-test-unloading/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-unloading", - "version": "0.0.1", - "description": "Plugin test (modules unloading)", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-video-constants/main.js b/server/tests/fixtures/peertube-plugin-test-video-constants/main.js deleted file mode 100644 index 06527bd35..000000000 --- a/server/tests/fixtures/peertube-plugin-test-video-constants/main.js +++ /dev/null @@ -1,46 +0,0 @@ -async function register ({ - videoCategoryManager, - videoLicenceManager, - videoLanguageManager, - videoPrivacyManager, - playlistPrivacyManager, - getRouter -}) { - videoLanguageManager.addConstant('al_bhed', 'Al Bhed') - videoLanguageManager.addLanguage('al_bhed2', 'Al Bhed 2') - videoLanguageManager.addConstant('al_bhed3', 'Al Bhed 3') - videoLanguageManager.deleteConstant('en') - videoLanguageManager.deleteLanguage('fr') - videoLanguageManager.deleteConstant('al_bhed3') - - videoCategoryManager.addCategory(42, 'Best category') - videoCategoryManager.addConstant(43, 'High best category') - videoCategoryManager.deleteConstant(1) // Music - videoCategoryManager.deleteCategory(2) // Films - - videoLicenceManager.addLicence(42, 'Best licence') - videoLicenceManager.addConstant(43, 'High best licence') - videoLicenceManager.deleteConstant(1) // Attribution - videoLicenceManager.deleteConstant(7) // Public domain - - videoPrivacyManager.deleteConstant(2) - videoPrivacyManager.deletePrivacy(2) - playlistPrivacyManager.deleteConstant(3) - playlistPrivacyManager.deletePlaylistPrivacy(3) - - { - const router = getRouter() - router.get('/reset-categories', (req, res) => { - videoCategoryManager.resetConstants() - - res.sendStatus(204) - }) - } -} - -async function unregister () {} - -module.exports = { - register, - unregister -} diff --git a/server/tests/fixtures/peertube-plugin-test-video-constants/package.json b/server/tests/fixtures/peertube-plugin-test-video-constants/package.json deleted file mode 100644 index 0fcf39933..000000000 --- a/server/tests/fixtures/peertube-plugin-test-video-constants/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-video-constants", - "version": "0.0.1", - "description": "Plugin test video constants", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test-websocket/main.js b/server/tests/fixtures/peertube-plugin-test-websocket/main.js deleted file mode 100644 index 3fde76cfe..000000000 --- a/server/tests/fixtures/peertube-plugin-test-websocket/main.js +++ /dev/null @@ -1,36 +0,0 @@ -const WebSocketServer = require('ws').WebSocketServer - -async function register ({ - registerWebSocketRoute -}) { - const wss = new WebSocketServer({ noServer: true }) - - wss.on('connection', function connection(ws) { - ws.on('message', function message(data) { - if (data.toString() === 'ping') { - ws.send('pong') - } - }) - }) - - registerWebSocketRoute({ - route: '/toto', - - handler: (request, socket, head) => { - wss.handleUpgrade(request, socket, head, ws => { - wss.emit('connection', ws, request) - }) - } - }) -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ########################################################################### diff --git a/server/tests/fixtures/peertube-plugin-test-websocket/package.json b/server/tests/fixtures/peertube-plugin-test-websocket/package.json deleted file mode 100644 index 89c8baa04..000000000 --- a/server/tests/fixtures/peertube-plugin-test-websocket/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "peertube-plugin-test-websocket", - "version": "0.0.1", - "description": "Plugin test websocket", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": {} -} diff --git a/server/tests/fixtures/peertube-plugin-test/languages/fr.json b/server/tests/fixtures/peertube-plugin-test/languages/fr.json deleted file mode 100644 index 9e52f7065..000000000 --- a/server/tests/fixtures/peertube-plugin-test/languages/fr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Hi": "Coucou" -} diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js deleted file mode 100644 index e16bf0ca3..000000000 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ /dev/null @@ -1,477 +0,0 @@ -async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) { - { - const actionHooks = [ - 'action:application.listening', - 'action:notifier.notification.created', - - 'action:api.video.updated', - 'action:api.video.deleted', - 'action:api.video.uploaded', - 'action:api.video.viewed', - - 'action:api.video.file-updated', - - 'action:api.video-channel.created', - 'action:api.video-channel.updated', - 'action:api.video-channel.deleted', - - 'action:api.live-video.created', - 'action:live.video.state.updated', - - 'action:api.video-thread.created', - 'action:api.video-comment-reply.created', - 'action:api.video-comment.deleted', - - 'action:api.video-caption.created', - 'action:api.video-caption.deleted', - - 'action:api.user.blocked', - 'action:api.user.unblocked', - 'action:api.user.registered', - 'action:api.user.created', - 'action:api.user.deleted', - 'action:api.user.updated', - 'action:api.user.oauth2-got-token', - - 'action:api.video-playlist-element.created' - ] - - for (const h of actionHooks) { - registerHook({ - target: h, - handler: () => peertubeHelpers.logger.debug('Run hook %s.', h) - }) - } - - for (const h of [ 'action:activity-pub.remote-video.created', 'action:activity-pub.remote-video.updated' ]) { - registerHook({ - target: h, - handler: ({ video, videoAPObject }) => { - peertubeHelpers.logger.debug('Run hook %s - AP %s - video %s.', h, video.name, videoAPObject.name ) - } - }) - } - } - - registerHook({ - target: 'filter:api.videos.list.params', - handler: obj => addToCount(obj) - }) - - registerHook({ - target: 'filter:api.videos.list.result', - handler: obj => addToTotal(obj) - }) - - registerHook({ - target: 'filter:api.video-playlist.videos.list.params', - handler: obj => addToCount(obj) - }) - - registerHook({ - target: 'filter:api.video-playlist.videos.list.result', - handler: obj => addToTotal(obj) - }) - - registerHook({ - target: 'filter:api.accounts.videos.list.params', - handler: obj => addToCount(obj) - }) - - registerHook({ - target: 'filter:api.accounts.videos.list.result', - handler: obj => addToTotal(obj, 2) - }) - - registerHook({ - target: 'filter:api.video-channels.videos.list.params', - handler: obj => addToCount(obj, 3) - }) - - registerHook({ - target: 'filter:api.video-channels.videos.list.result', - handler: obj => addToTotal(obj, 3) - }) - - registerHook({ - target: 'filter:api.user.me.videos.list.params', - handler: obj => addToCount(obj, 4) - }) - - registerHook({ - target: 'filter:api.user.me.videos.list.result', - handler: obj => addToTotal(obj, 4) - }) - - registerHook({ - target: 'filter:api.user.me.subscription-videos.list.params', - handler: obj => addToCount(obj) - }) - - registerHook({ - target: 'filter:api.user.me.subscription-videos.list.result', - handler: obj => addToTotal(obj, 4) - }) - - registerHook({ - target: 'filter:api.video.get.result', - handler: video => { - video.name += ' <3' - - return video - } - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:api.video-channels.list.params', - handler: obj => addToCount(obj, 1) - }) - - registerHook({ - target: 'filter:api.video-channels.list.result', - handler: obj => addToTotal(obj, 1) - }) - - registerHook({ - target: 'filter:api.video-channel.get.result', - handler: channel => { - channel.name += ' <3' - - return channel - } - }) - - // --------------------------------------------------------------------------- - - for (const hook of [ 'filter:api.video.upload.accept.result', 'filter:api.live-video.create.accept.result' ]) { - registerHook({ - target: hook, - handler: ({ accepted }, { videoBody, liveVideoBody }) => { - if (!accepted) return { accepted: false } - - const name = videoBody - ? videoBody.name - : liveVideoBody.name - - if (name.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word' } - - return { accepted: true } - } - }) - } - - registerHook({ - target: 'filter:api.video.update-file.accept.result', - handler: ({ accepted }, { videoFile }) => { - if (!accepted) return { accepted: false } - if (videoFile.filename.includes('webm')) return { accepted: false, errorMessage: 'no webm' } - - return { accepted: true } - } - }) - - registerHook({ - target: 'filter:api.video.pre-import-url.accept.result', - handler: ({ accepted }, { videoImportBody }) => { - if (!accepted) return { accepted: false } - if (videoImportBody.targetUrl.includes('bad')) return { accepted: false, errorMessage: 'bad target url' } - - return { accepted: true } - } - }) - - registerHook({ - target: 'filter:api.video.pre-import-torrent.accept.result', - handler: ({ accepted }, { videoImportBody }) => { - if (!accepted) return { accepted: false } - if (videoImportBody.name.includes('bad torrent')) return { accepted: false, errorMessage: 'bad torrent' } - - return { accepted: true } - } - }) - - registerHook({ - target: 'filter:api.video.post-import-url.accept.result', - handler: ({ accepted }, { video }) => { - if (!accepted) return { accepted: false } - if (video.name.includes('bad word')) return { accepted: false, errorMessage: 'bad word' } - - return { accepted: true } - } - }) - - registerHook({ - target: 'filter:api.video.post-import-torrent.accept.result', - handler: ({ accepted }, { video }) => { - if (!accepted) return { accepted: false } - if (video.name.includes('bad word')) return { accepted: false, errorMessage: 'bad word' } - - return { accepted: true } - } - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:api.video-thread.create.accept.result', - handler: ({ accepted }, { commentBody }) => checkCommentBadWord(accepted, commentBody) - }) - - registerHook({ - target: 'filter:api.video-comment-reply.create.accept.result', - handler: ({ accepted }, { commentBody }) => checkCommentBadWord(accepted, commentBody) - }) - - registerHook({ - target: 'filter:activity-pub.remote-video-comment.create.accept.result', - handler: ({ accepted }, { comment }) => checkCommentBadWord(accepted, comment) - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:activity-pub.activity.context.build.result', - handler: context => context.concat([ { recordedAt: 'https://schema.org/recordedAt' } ]) - }) - - registerHook({ - target: 'filter:activity-pub.video.json-ld.build.result', - handler: (jsonld, { video }) => ({ ...jsonld, videoName: video.name }) - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:api.video-threads.list.params', - handler: obj => addToCount(obj) - }) - - registerHook({ - target: 'filter:api.video-threads.list.result', - handler: obj => addToTotal(obj) - }) - - registerHook({ - target: 'filter:api.video-thread-comments.list.result', - handler: obj => { - obj.data.forEach(c => c.text += ' <3') - - return obj - } - }) - - registerHook({ - target: 'filter:video.auto-blacklist.result', - handler: (blacklisted, { video }) => { - if (blacklisted) return true - if (video.name.includes('please blacklist me')) return true - - return false - } - }) - - { - registerHook({ - target: 'filter:api.user.signup.allowed.result', - handler: (result, params) => { - if (params && params.body && params.body.email && params.body.email.includes('jma 1')) { - return { allowed: false, errorMessage: 'No jma 1' } - } - - return result - } - }) - - registerHook({ - target: 'filter:api.user.request-signup.allowed.result', - handler: (result, params) => { - if (params && params.body && params.body.email && params.body.email.includes('jma 2')) { - return { allowed: false, errorMessage: 'No jma 2' } - } - - return result - } - }) - } - - registerHook({ - target: 'filter:api.download.torrent.allowed.result', - handler: (result, params) => { - if (params && params.downloadName.includes('bad torrent')) { - return { allowed: false, errorMessage: 'Liu Bei' } - } - - return result - } - }) - - registerHook({ - target: 'filter:api.download.video.allowed.result', - handler: async (result, params) => { - const loggedInUser = await peertubeHelpers.user.getAuthUser(params.res) - if (loggedInUser) return { allowed: true } - - if (params && !params.streamingPlaylist && params.video.name.includes('bad file')) { - return { allowed: false, errorMessage: 'Cao Cao' } - } - - if (params && params.streamingPlaylist && params.video.name.includes('bad playlist file')) { - return { allowed: false, errorMessage: 'Sun Jian' } - } - - return result - } - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:html.embed.video.allowed.result', - handler: (result, params) => { - return { - allowed: false, - html: 'Lu Bu' - } - } - }) - - registerHook({ - target: 'filter:html.embed.video-playlist.allowed.result', - handler: (result, params) => { - return { - allowed: false, - html: 'Diao Chan' - } - } - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:html.client.json-ld.result', - handler: (jsonld, context) => { - if (!context || !context.video) return jsonld - - return Object.assign(jsonld, { recordedAt: 'http://example.com/recordedAt' }) - } - }) - - // --------------------------------------------------------------------------- - - registerHook({ - target: 'filter:api.server.stats.get.result', - handler: (result) => { - return { ...result, customStats: 14 } - } - }) - - registerHook({ - target: 'filter:job-queue.process.params', - handler: (object, context) => { - if (context.type !== 'video-studio-edition') return object - - object.data.tasks = [ - { - name: 'cut', - options: { - start: 0, - end: 1 - } - } - ] - - return object - } - }) - - registerHook({ - target: 'filter:transcoding.auto.resolutions-to-transcode.result', - handler: (object, context) => { - if (context.video.name.includes('transcode-filter')) { - object = [ 100 ] - } - - return object - } - }) - - // Upload/import/live attributes - for (const target of [ - 'filter:api.video.upload.video-attribute.result', - 'filter:api.video.import-url.video-attribute.result', - 'filter:api.video.import-torrent.video-attribute.result', - 'filter:api.video.live.video-attribute.result' - ]) { - registerHook({ - target, - handler: (result) => { - return { ...result, description: result.description + ' - ' + target } - } - }) - } - - { - const filterHooks = [ - 'filter:api.search.videos.local.list.params', - 'filter:api.search.videos.local.list.result', - 'filter:api.search.videos.index.list.params', - 'filter:api.search.videos.index.list.result', - 'filter:api.search.video-channels.local.list.params', - 'filter:api.search.video-channels.local.list.result', - 'filter:api.search.video-channels.index.list.params', - 'filter:api.search.video-channels.index.list.result', - 'filter:api.search.video-playlists.local.list.params', - 'filter:api.search.video-playlists.local.list.result', - 'filter:api.search.video-playlists.index.list.params', - 'filter:api.search.video-playlists.index.list.result', - - 'filter:api.overviews.videos.list.params', - 'filter:api.overviews.videos.list.result', - - 'filter:job-queue.process.params', - 'filter:job-queue.process.result' - ] - - for (const h of filterHooks) { - registerHook({ - target: h, - handler: (obj) => { - peertubeHelpers.logger.debug('Run hook %s.', h) - - return obj - } - }) - } - } -} - -async function unregister () { - return -} - -module.exports = { - register, - unregister -} - -// ############################################################################ - -function addToCount (obj, amount = 1) { - return Object.assign({}, obj, { count: obj.count + amount }) -} - -function addToTotal (result, amount = 1) { - return { - data: result.data, - total: result.total + amount - } -} - -function checkCommentBadWord (accepted, commentBody) { - if (!accepted) return { accepted: false } - if (commentBody.text.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word '} - - return { accepted: true } -} diff --git a/server/tests/fixtures/peertube-plugin-test/package.json b/server/tests/fixtures/peertube-plugin-test/package.json deleted file mode 100644 index 108f21fd6..000000000 --- a/server/tests/fixtures/peertube-plugin-test/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "peertube-plugin-test", - "version": "0.0.1", - "description": "Plugin test", - "engine": { - "peertube": ">=1.3.0" - }, - "keywords": [ - "peertube", - "plugin" - ], - "homepage": "https://github.com/Chocobozzz/PeerTube", - "author": "Chocobozzz", - "bugs": "https://github.com/Chocobozzz/PeerTube/issues", - "library": "./main.js", - "staticDirs": {}, - "css": [], - "clientScripts": [], - "translations": { - "fr-FR": "./languages/fr.json" - } -} diff --git a/server/tests/fixtures/rtmps.cert b/server/tests/fixtures/rtmps.cert deleted file mode 100644 index 3ef606c52..000000000 --- a/server/tests/fixtures/rtmps.cert +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDazCCAlOgAwIBAgIUKNycLAZUs2jFsWUW+zZhBkpLB2wwDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTExMDUxMDA4MzhaFw0yMTEy -MDUxMDA4MzhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDak20d81KG/9mVLU6Qw/uRniC935yf9Rlp8FVCDxUd -zLbfHjrnIOv8kqinUI0nuEQC4DnF7Rbafe88WDU33Q8ixU/R0czUGq1AEwIjyN30 -5NjokCb26xWIly7RCfc/Ot6tjguHwKvcxqJMNC0Lit9Go9MDVnGFLkgHia68P72T -ZDVV44YpzwYDicwQs5C4nZ4yzAeclia07qfUY0VAEZlxJ/9zjwYHCT0AKaEPH35E -dUvjuvJ1OSHSN1S4acR+TPR3FwKQh3H/M/GWIqoiIOpdjFUBLs80QOM2aNrLmlyP -JtyFJLxCP7Ery9fGY/yzHeSxpgOKwZopD6uHZKi5yazNAgMBAAGjUzBRMB0GA1Ud -DgQWBBSSjhRQdWsybNQMLMhkwV+xiP2uoDAfBgNVHSMEGDAWgBSSjhRQdWsybNQM -LMhkwV+xiP2uoDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC8 -rJu3J5sqVKNQaXOmLPd49RM7KG3Y1KPqbQi1lh+sW6aefZ9daeh3JDYGBZGPG/Fi -IMMP+LhGG0WqDm4ClK00wyNhBuNPEyzvuN/WMRX5djPxO1IZi+KogFwXsn853Ov9 -oV3nxArNNjDu2n92FiB7RTlXRXPIoRo2zEBcLvveGySn9XUazRzlqx6FAxYe2xsw -U3cZ6/wwU1YsEZa5bwIQk+gkFj3zDsTyEkn2ntcE2NlR+AhCHKa/yAxgPFycAVPX -2o+wNnc6H4syP98mMGj9hEE3RSJyCPgGBlgi7Swl64G3YygFPJzfLX9YTuxwr/eI -oitEjF9ljtmdEnf0RdOj ------END CERTIFICATE----- diff --git a/server/tests/fixtures/rtmps.key b/server/tests/fixtures/rtmps.key deleted file mode 100644 index 14a85e70a..000000000 --- a/server/tests/fixtures/rtmps.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDak20d81KG/9mV -LU6Qw/uRniC935yf9Rlp8FVCDxUdzLbfHjrnIOv8kqinUI0nuEQC4DnF7Rbafe88 -WDU33Q8ixU/R0czUGq1AEwIjyN305NjokCb26xWIly7RCfc/Ot6tjguHwKvcxqJM -NC0Lit9Go9MDVnGFLkgHia68P72TZDVV44YpzwYDicwQs5C4nZ4yzAeclia07qfU -Y0VAEZlxJ/9zjwYHCT0AKaEPH35EdUvjuvJ1OSHSN1S4acR+TPR3FwKQh3H/M/GW -IqoiIOpdjFUBLs80QOM2aNrLmlyPJtyFJLxCP7Ery9fGY/yzHeSxpgOKwZopD6uH -ZKi5yazNAgMBAAECggEAND7C+UK8+jnTl13CBsZhrnfemaQGexGJ5pGkv2p9gKb7 -Gy/Nooty/OdNWtjdNJ5N22YfSRkXulgZxBHNfrHfOU9yedOtIxHRUZx5iXYs36mH -02cJeUHN3t1MOnkoWTvIGDH4vZUnP1lXV+Gs1rJ2Fht4h7a04cGjQ/H8C1EtDjqX -kzH2T/gwo5hdGrxifRTs5wCVoP/iUwNtBI4WrY2rfC6sV+NOICgp0xX0NvGWZ8UT -K1Ntpl8IxnxmeBd26d+Gbjc9d9fIRDtyXby4YOIlDZxnIiZEI0I452JqGl/jrXaP -F3Troet4OBj5uH5s374d6ubKq66XogiLMIjEj2tYfQKBgQDtuaOu+y549bFJKVc9 -TCiWSOl/0j2kKKG8UG23zMC//AT13WqZDT5ObfOAuMhy70au/PD84D9RU/+gRVWb -ptfybD9ugRNC8PkmdT82uYtZpS4+Xw4qyWVRgqQFmjSYz63cLcULVi8kiG8XmG5u -QGgT/tNv5mxhOMUGSxhClOpLBwKBgQDrYO9UrLs+gDVKbHF4Dh+YJpaLnwwF+TFA -j3ZbkE0XEeeXp/YDgyClmWwEkteJeNljtreCZ9gMkx3JdR9i8uecUQ2tFDBg3cN0 -BZAex2jFwSb0QbfzHNnE07I+aEIfHHjYXjzABl+1Yt95giKjce0Ke+8Zzahue0+9 -lYcAHemQiwKBgQCs9JAbIdJo3NBUW0iGZ19sH7YKciq4wXsSaC27OLPPugrd2m7Q -1arMIwCzWT01KdLyQ0MNqBVJFWT49RjYuuWIEauAuVYLMQkEKu+H4Cx7V0syw7Op -+4bEa9jr3op/1zE17PLcUaLQ4JZ6w0Ms4Z0XVyH72thlT4lBD+ehoXhohwKBgEtJ -LAPnY9Sv6Vuup/SAf/aIkSqDarMWa3x85pyO4Tl5zpuha3zgGjcdhYFI/ovIDbBp -JvUdBeuvup1PSwS5MP+8pSUxCfBRvkyD4v8VRRvLlgwWYSHvnm/oTmDLtCqDTtvV -+JRq9X3s7BHPYAjrTahGz8lvEGqWIoE/LHkLGEPVAoGAaF3VHuqDfmD9PJUAlsU1 -qxN7yfOd2ve0+66Ghus24DVqUFqwp5f2AxZXYUtSaNUp8fVbqIi+Yq3YDTU2KfId -5QNA/AiKi4VUNLElsG5DZlbszsE5KNp9fWQoggdQ5LND7AGEKeFERHOVQ7C5sc/C -omIqK5/PsZmaf4OZLyecxJY= ------END PRIVATE KEY----- diff --git a/server/tests/fixtures/sample.ogg b/server/tests/fixtures/sample.ogg deleted file mode 100644 index 0d7f43eb7..000000000 Binary files a/server/tests/fixtures/sample.ogg and /dev/null differ diff --git a/server/tests/fixtures/subtitle-bad.txt b/server/tests/fixtures/subtitle-bad.txt deleted file mode 100644 index a2a30ae47..000000000 --- a/server/tests/fixtures/subtitle-bad.txt +++ /dev/null @@ -1,11 +0,0 @@ -1 -00:00:01,600 --> 00:00:04,200 -English (US) - -2 -00:00:05,900 --> 00:00:07,999 -This is a subtitle in American English - -3 -00:00:10,000 --> 00:00:14,000 -Adding subtitles is very easy to do \ No newline at end of file diff --git a/server/tests/fixtures/subtitle-good.srt b/server/tests/fixtures/subtitle-good.srt deleted file mode 100644 index a2a30ae47..000000000 --- a/server/tests/fixtures/subtitle-good.srt +++ /dev/null @@ -1,11 +0,0 @@ -1 -00:00:01,600 --> 00:00:04,200 -English (US) - -2 -00:00:05,900 --> 00:00:07,999 -This is a subtitle in American English - -3 -00:00:10,000 --> 00:00:14,000 -Adding subtitles is very easy to do \ No newline at end of file diff --git a/server/tests/fixtures/subtitle-good1.vtt b/server/tests/fixtures/subtitle-good1.vtt deleted file mode 100644 index 04cd23946..000000000 --- a/server/tests/fixtures/subtitle-good1.vtt +++ /dev/null @@ -1,8 +0,0 @@ -WEBVTT - -00:01.000 --> 00:04.000 -Subtitle good 1. - -00:05.000 --> 00:09.000 -- It will perforate your stomach. -- You could die. \ No newline at end of file diff --git a/server/tests/fixtures/subtitle-good2.vtt b/server/tests/fixtures/subtitle-good2.vtt deleted file mode 100644 index 4d3256def..000000000 --- a/server/tests/fixtures/subtitle-good2.vtt +++ /dev/null @@ -1,8 +0,0 @@ -WEBVTT - -00:01.000 --> 00:04.000 -Subtitle good 2. - -00:05.000 --> 00:09.000 -- It will perforate your stomach. -- You could die. \ No newline at end of file diff --git a/server/tests/fixtures/thumbnail-playlist.jpg b/server/tests/fixtures/thumbnail-playlist.jpg deleted file mode 100644 index 12de5817b..000000000 Binary files a/server/tests/fixtures/thumbnail-playlist.jpg and /dev/null differ diff --git a/server/tests/fixtures/video-720p.torrent b/server/tests/fixtures/video-720p.torrent deleted file mode 100644 index 64bfd5220..000000000 Binary files a/server/tests/fixtures/video-720p.torrent and /dev/null differ diff --git a/server/tests/fixtures/video_import_preview.jpg b/server/tests/fixtures/video_import_preview.jpg deleted file mode 100644 index a98da178f..000000000 Binary files a/server/tests/fixtures/video_import_preview.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_import_preview_yt_dlp.jpg b/server/tests/fixtures/video_import_preview_yt_dlp.jpg deleted file mode 100644 index 9e8833bf9..000000000 Binary files a/server/tests/fixtures/video_import_preview_yt_dlp.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_import_thumbnail.jpg b/server/tests/fixtures/video_import_thumbnail.jpg deleted file mode 100644 index 9ee1bc382..000000000 Binary files a/server/tests/fixtures/video_import_thumbnail.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_import_thumbnail_yt_dlp.jpg b/server/tests/fixtures/video_import_thumbnail_yt_dlp.jpg deleted file mode 100644 index a10e07207..000000000 Binary files a/server/tests/fixtures/video_import_thumbnail_yt_dlp.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short.avi b/server/tests/fixtures/video_short.avi deleted file mode 100644 index 88979cab2..000000000 Binary files a/server/tests/fixtures/video_short.avi and /dev/null differ diff --git a/server/tests/fixtures/video_short.mkv b/server/tests/fixtures/video_short.mkv deleted file mode 100644 index a67f4f806..000000000 Binary files a/server/tests/fixtures/video_short.mkv and /dev/null differ diff --git a/server/tests/fixtures/video_short.mp4 b/server/tests/fixtures/video_short.mp4 deleted file mode 100644 index 35678362b..000000000 Binary files a/server/tests/fixtures/video_short.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short.mp4.jpg b/server/tests/fixtures/video_short.mp4.jpg deleted file mode 100644 index 7ac29122c..000000000 Binary files a/server/tests/fixtures/video_short.mp4.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short.ogv b/server/tests/fixtures/video_short.ogv deleted file mode 100644 index 9e253da82..000000000 Binary files a/server/tests/fixtures/video_short.ogv and /dev/null differ diff --git a/server/tests/fixtures/video_short.ogv.jpg b/server/tests/fixtures/video_short.ogv.jpg deleted file mode 100644 index 5bc63969b..000000000 Binary files a/server/tests/fixtures/video_short.ogv.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short.webm b/server/tests/fixtures/video_short.webm deleted file mode 100644 index bf4b0ab6c..000000000 Binary files a/server/tests/fixtures/video_short.webm and /dev/null differ diff --git a/server/tests/fixtures/video_short.webm.jpg b/server/tests/fixtures/video_short.webm.jpg deleted file mode 100644 index 7ac29122c..000000000 Binary files a/server/tests/fixtures/video_short.webm.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short1-preview.webm.jpg b/server/tests/fixtures/video_short1-preview.webm.jpg deleted file mode 100644 index 15454942d..000000000 Binary files a/server/tests/fixtures/video_short1-preview.webm.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short1.webm b/server/tests/fixtures/video_short1.webm deleted file mode 100644 index 70ac0c644..000000000 Binary files a/server/tests/fixtures/video_short1.webm and /dev/null differ diff --git a/server/tests/fixtures/video_short1.webm.jpg b/server/tests/fixtures/video_short1.webm.jpg deleted file mode 100644 index b2740d73d..000000000 Binary files a/server/tests/fixtures/video_short1.webm.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short2.webm b/server/tests/fixtures/video_short2.webm deleted file mode 100644 index 13d72dff7..000000000 Binary files a/server/tests/fixtures/video_short2.webm and /dev/null differ diff --git a/server/tests/fixtures/video_short2.webm.jpg b/server/tests/fixtures/video_short2.webm.jpg deleted file mode 100644 index afe476c7f..000000000 Binary files a/server/tests/fixtures/video_short2.webm.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short3.webm b/server/tests/fixtures/video_short3.webm deleted file mode 100644 index cde5dcd58..000000000 Binary files a/server/tests/fixtures/video_short3.webm and /dev/null differ diff --git a/server/tests/fixtures/video_short3.webm.jpg b/server/tests/fixtures/video_short3.webm.jpg deleted file mode 100644 index b572f676e..000000000 Binary files a/server/tests/fixtures/video_short3.webm.jpg and /dev/null differ diff --git a/server/tests/fixtures/video_short_0p.mp4 b/server/tests/fixtures/video_short_0p.mp4 deleted file mode 100644 index 2069a49b8..000000000 Binary files a/server/tests/fixtures/video_short_0p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_144p.m3u8 b/server/tests/fixtures/video_short_144p.m3u8 deleted file mode 100644 index 96568625b..000000000 --- a/server/tests/fixtures/video_short_144p.m3u8 +++ /dev/null @@ -1,13 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:7 -#EXT-X-TARGETDURATION:4 -#EXT-X-MEDIA-SEQUENCE:0 -#EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4",BYTERANGE="1375@0" -#EXTINF:4.000000, -#EXT-X-BYTERANGE:10518@1375 -3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4 -#EXTINF:1.000000, -#EXT-X-BYTERANGE:3741@11893 -3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4 -#EXT-X-ENDLIST diff --git a/server/tests/fixtures/video_short_144p.mp4 b/server/tests/fixtures/video_short_144p.mp4 deleted file mode 100644 index 047d43c17..000000000 Binary files a/server/tests/fixtures/video_short_144p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_240p.m3u8 b/server/tests/fixtures/video_short_240p.m3u8 deleted file mode 100644 index 96568625b..000000000 --- a/server/tests/fixtures/video_short_240p.m3u8 +++ /dev/null @@ -1,13 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:7 -#EXT-X-TARGETDURATION:4 -#EXT-X-MEDIA-SEQUENCE:0 -#EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4",BYTERANGE="1375@0" -#EXTINF:4.000000, -#EXT-X-BYTERANGE:10518@1375 -3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4 -#EXTINF:1.000000, -#EXT-X-BYTERANGE:3741@11893 -3dd13e27-1ae1-441c-9b77-48c6b95603be-144-fragmented.mp4 -#EXT-X-ENDLIST diff --git a/server/tests/fixtures/video_short_240p.mp4 b/server/tests/fixtures/video_short_240p.mp4 deleted file mode 100644 index 46609e81a..000000000 Binary files a/server/tests/fixtures/video_short_240p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_360p.m3u8 b/server/tests/fixtures/video_short_360p.m3u8 deleted file mode 100644 index f7072dc6d..000000000 --- a/server/tests/fixtures/video_short_360p.m3u8 +++ /dev/null @@ -1,13 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:7 -#EXT-X-TARGETDURATION:4 -#EXT-X-MEDIA-SEQUENCE:0 -#EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="05c40acd-3e94-4d25-ade8-97f7ff2cf0ac-360-fragmented.mp4",BYTERANGE="1376@0" -#EXTINF:4.000000, -#EXT-X-BYTERANGE:19987@1376 -05c40acd-3e94-4d25-ade8-97f7ff2cf0ac-360-fragmented.mp4 -#EXTINF:1.000000, -#EXT-X-BYTERANGE:9147@21363 -05c40acd-3e94-4d25-ade8-97f7ff2cf0ac-360-fragmented.mp4 -#EXT-X-ENDLIST diff --git a/server/tests/fixtures/video_short_360p.mp4 b/server/tests/fixtures/video_short_360p.mp4 deleted file mode 100644 index 7a8189bbc..000000000 Binary files a/server/tests/fixtures/video_short_360p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_480.webm b/server/tests/fixtures/video_short_480.webm deleted file mode 100644 index 3145105e1..000000000 Binary files a/server/tests/fixtures/video_short_480.webm and /dev/null differ diff --git a/server/tests/fixtures/video_short_480p.m3u8 b/server/tests/fixtures/video_short_480p.m3u8 deleted file mode 100644 index 5ff30dfa7..000000000 --- a/server/tests/fixtures/video_short_480p.m3u8 +++ /dev/null @@ -1,13 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:7 -#EXT-X-TARGETDURATION:4 -#EXT-X-MEDIA-SEQUENCE:0 -#EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="f9377e69-d8f2-4de8-8087-ddbca6629829-480-fragmented.mp4",BYTERANGE="1376@0" -#EXTINF:4.000000, -#EXT-X-BYTERANGE:26042@1376 -f9377e69-d8f2-4de8-8087-ddbca6629829-480-fragmented.mp4 -#EXTINF:1.000000, -#EXT-X-BYTERANGE:12353@27418 -f9377e69-d8f2-4de8-8087-ddbca6629829-480-fragmented.mp4 -#EXT-X-ENDLIST diff --git a/server/tests/fixtures/video_short_480p.mp4 b/server/tests/fixtures/video_short_480p.mp4 deleted file mode 100644 index e05b58b6b..000000000 Binary files a/server/tests/fixtures/video_short_480p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_4k.mp4 b/server/tests/fixtures/video_short_4k.mp4 deleted file mode 100644 index 402479743..000000000 Binary files a/server/tests/fixtures/video_short_4k.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_720p.m3u8 b/server/tests/fixtures/video_short_720p.m3u8 deleted file mode 100644 index 7cee94032..000000000 --- a/server/tests/fixtures/video_short_720p.m3u8 +++ /dev/null @@ -1,13 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:7 -#EXT-X-TARGETDURATION:4 -#EXT-X-MEDIA-SEQUENCE:0 -#EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="c1014aa4-d1f4-4b66-927b-c23d283fcae0-720-fragmented.mp4",BYTERANGE="1356@0" -#EXTINF:4.000000, -#EXT-X-BYTERANGE:39260@1356 -c1014aa4-d1f4-4b66-927b-c23d283fcae0-720-fragmented.mp4 -#EXTINF:1.000000, -#EXT-X-BYTERANGE:18493@40616 -c1014aa4-d1f4-4b66-927b-c23d283fcae0-720-fragmented.mp4 -#EXT-X-ENDLIST diff --git a/server/tests/fixtures/video_short_720p.mp4 b/server/tests/fixtures/video_short_720p.mp4 deleted file mode 100644 index 35e8f69a7..000000000 Binary files a/server/tests/fixtures/video_short_720p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_fake.webm b/server/tests/fixtures/video_short_fake.webm deleted file mode 100644 index d85290ae5..000000000 --- a/server/tests/fixtures/video_short_fake.webm +++ /dev/null @@ -1 +0,0 @@ -this is a fake video mouahahah diff --git a/server/tests/fixtures/video_short_mp3_256k.mp4 b/server/tests/fixtures/video_short_mp3_256k.mp4 deleted file mode 100644 index 4c1c7b45e..000000000 Binary files a/server/tests/fixtures/video_short_mp3_256k.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_short_no_audio.mp4 b/server/tests/fixtures/video_short_no_audio.mp4 deleted file mode 100644 index 329d20fba..000000000 Binary files a/server/tests/fixtures/video_short_no_audio.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_very_long_10p.mp4 b/server/tests/fixtures/video_very_long_10p.mp4 deleted file mode 100644 index 852297933..000000000 Binary files a/server/tests/fixtures/video_very_long_10p.mp4 and /dev/null differ diff --git a/server/tests/fixtures/video_very_short_240p.mp4 b/server/tests/fixtures/video_very_short_240p.mp4 deleted file mode 100644 index 95b6be92a..000000000 Binary files a/server/tests/fixtures/video_very_short_240p.mp4 and /dev/null differ diff --git a/server/tests/helpers/comment-model.ts b/server/tests/helpers/comment-model.ts deleted file mode 100644 index e39cae442..000000000 --- a/server/tests/helpers/comment-model.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { VideoCommentModel } from '../../models/video/video-comment' - -class CommentMock { - text: string - - extractMentions = VideoCommentModel.prototype.extractMentions - - isOwned = () => true -} - -describe('Comment model', function () { - it('Should correctly extract mentions', async function () { - const comment = new CommentMock() - - comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + - 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' - const result = comment.extractMentions().sort((a, b) => a.localeCompare(b)) - - expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) - }) -}) diff --git a/server/tests/helpers/core-utils.ts b/server/tests/helpers/core-utils.ts deleted file mode 100644 index cd2f07e4a..000000000 --- a/server/tests/helpers/core-utils.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { snakeCase } from 'lodash' -import validator from 'validator' -import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate } from '@shared/core-utils' -import { VideoResolution } from '@shared/models' -import { objectConverter, parseBytes, parseDurationToMs } from '../../helpers/core-utils' - -describe('Parse Bytes', function () { - - it('Should pass on valid value', async function () { - // just return it - expect(parseBytes(-1024)).to.equal(-1024) - expect(parseBytes(1024)).to.equal(1024) - expect(parseBytes(1048576)).to.equal(1048576) - expect(parseBytes('1024')).to.equal(1024) - expect(parseBytes('1048576')).to.equal(1048576) - - // sizes - expect(parseBytes('1B')).to.equal(1024) - expect(parseBytes('1MB')).to.equal(1048576) - expect(parseBytes('1GB')).to.equal(1073741824) - expect(parseBytes('1TB')).to.equal(1099511627776) - - expect(parseBytes('5GB')).to.equal(5368709120) - expect(parseBytes('5TB')).to.equal(5497558138880) - - expect(parseBytes('1024B')).to.equal(1048576) - expect(parseBytes('1024MB')).to.equal(1073741824) - expect(parseBytes('1024GB')).to.equal(1099511627776) - expect(parseBytes('1024TB')).to.equal(1125899906842624) - - // with whitespace - expect(parseBytes('1 GB')).to.equal(1073741824) - expect(parseBytes('1\tGB')).to.equal(1073741824) - - // sum value - expect(parseBytes('1TB 1024MB')).to.equal(1100585369600) - expect(parseBytes('4GB 1024MB')).to.equal(5368709120) - expect(parseBytes('4TB 1024GB')).to.equal(5497558138880) - expect(parseBytes('4TB 1024GB 0MB')).to.equal(5497558138880) - expect(parseBytes('1024TB 1024GB 1024MB')).to.equal(1127000492212224) - }) - - it('Should be invalid when given invalid value', async function () { - expect(parseBytes('6GB 1GB')).to.equal(6) - }) -}) - -describe('Parse duration', function () { - - it('Should pass when given valid value', async function () { - expect(parseDurationToMs(35)).to.equal(35) - expect(parseDurationToMs(-35)).to.equal(-35) - expect(parseDurationToMs('35 seconds')).to.equal(35 * 1000) - expect(parseDurationToMs('1 minute')).to.equal(60 * 1000) - expect(parseDurationToMs('1 hour')).to.equal(3600 * 1000) - expect(parseDurationToMs('35 hours')).to.equal(3600 * 35 * 1000) - }) - - it('Should be invalid when given invalid value', async function () { - expect(parseBytes('35m 5s')).to.equal(35) - }) -}) - -describe('Object', function () { - - it('Should convert an object', async function () { - function keyConverter (k: string) { - return snakeCase(k) - } - - function valueConverter (v: any) { - if (validator.isNumeric(v + '')) return parseInt('' + v, 10) - - return v - } - - const obj = { - mySuperKey: 'hello', - mySuper2Key: '45', - mySuper3Key: { - mySuperSubKey: '15', - mySuperSub2Key: 'hello', - mySuperSub3Key: [ '1', 'hello', 2 ], - mySuperSub4Key: 4 - }, - mySuper4Key: 45, - toto: { - super_key: '15', - superKey2: 'hello' - }, - super_key: { - superKey4: 15 - } - } - - const res = objectConverter(obj, keyConverter, valueConverter) - - expect(res.my_super_key).to.equal('hello') - expect(res.my_super_2_key).to.equal(45) - expect(res.my_super_3_key.my_super_sub_key).to.equal(15) - expect(res.my_super_3_key.my_super_sub_2_key).to.equal('hello') - expect(res.my_super_3_key.my_super_sub_3_key).to.deep.equal([ 1, 'hello', 2 ]) - expect(res.my_super_3_key.my_super_sub_4_key).to.equal(4) - expect(res.toto.super_key).to.equal(15) - expect(res.toto.super_key_2).to.equal('hello') - expect(res.super_key.super_key_4).to.equal(15) - - // Immutable - expect(res.mySuperKey).to.be.undefined - expect(obj['my_super_key']).to.be.undefined - }) -}) - -describe('Bitrate', function () { - - it('Should get appropriate max bitrate', function () { - const tests = [ - { resolution: VideoResolution.H_144P, ratio: 16 / 9, fps: 24, min: 200, max: 400 }, - { resolution: VideoResolution.H_240P, ratio: 16 / 9, fps: 24, min: 600, max: 800 }, - { resolution: VideoResolution.H_360P, ratio: 16 / 9, fps: 24, min: 1200, max: 1600 }, - { resolution: VideoResolution.H_480P, ratio: 16 / 9, fps: 24, min: 2000, max: 2300 }, - { resolution: VideoResolution.H_720P, ratio: 16 / 9, fps: 24, min: 4000, max: 4400 }, - { resolution: VideoResolution.H_1080P, ratio: 16 / 9, fps: 24, min: 8000, max: 10000 }, - { resolution: VideoResolution.H_4K, ratio: 16 / 9, fps: 24, min: 25000, max: 30000 } - ] - - for (const test of tests) { - expect(getMaxTheoreticalBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000) - } - }) - - it('Should get appropriate average bitrate', function () { - const tests = [ - { resolution: VideoResolution.H_144P, ratio: 16 / 9, fps: 24, min: 50, max: 300 }, - { resolution: VideoResolution.H_240P, ratio: 16 / 9, fps: 24, min: 350, max: 450 }, - { resolution: VideoResolution.H_360P, ratio: 16 / 9, fps: 24, min: 700, max: 900 }, - { resolution: VideoResolution.H_480P, ratio: 16 / 9, fps: 24, min: 1100, max: 1300 }, - { resolution: VideoResolution.H_720P, ratio: 16 / 9, fps: 24, min: 2300, max: 2500 }, - { resolution: VideoResolution.H_1080P, ratio: 16 / 9, fps: 24, min: 4700, max: 5000 }, - { resolution: VideoResolution.H_4K, ratio: 16 / 9, fps: 24, min: 15000, max: 17000 } - ] - - for (const test of tests) { - expect(getAverageTheoreticalBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000) - } - }) -}) diff --git a/server/tests/helpers/crypto.ts b/server/tests/helpers/crypto.ts deleted file mode 100644 index b508c715b..000000000 --- a/server/tests/helpers/crypto.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { decrypt, encrypt } from '@server/helpers/peertube-crypto' - -describe('Encrypt/Descrypt', function () { - - it('Should encrypt and decrypt the string', async function () { - const secret = 'my_secret' - const str = 'my super string' - - const encrypted = await encrypt(str, secret) - const decrypted = await decrypt(encrypted, secret) - - expect(str).to.equal(decrypted) - }) - - it('Should not decrypt without the same secret', async function () { - const str = 'my super string' - - const encrypted = await encrypt(str, 'my_secret') - - let error = false - - try { - await decrypt(encrypted, 'my_sicret') - } catch (err) { - error = true - } - - expect(error).to.be.true - }) -}) diff --git a/server/tests/helpers/dns.ts b/server/tests/helpers/dns.ts deleted file mode 100644 index 49b506e7b..000000000 --- a/server/tests/helpers/dns.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { isResolvingToUnicastOnly } from '@server/helpers/dns' - -describe('DNS helpers', function () { - - it('Should correctly check unicast IPs', async function () { - expect(await isResolvingToUnicastOnly('cpy.re')).to.be.true - expect(await isResolvingToUnicastOnly('framasoft.org')).to.be.true - expect(await isResolvingToUnicastOnly('8.8.8.8')).to.be.true - - expect(await isResolvingToUnicastOnly('127.0.0.1')).to.be.false - expect(await isResolvingToUnicastOnly('127.0.0.1.cpy.re')).to.be.false - }) -}) diff --git a/server/tests/helpers/image.ts b/server/tests/helpers/image.ts deleted file mode 100644 index 6021ffc48..000000000 --- a/server/tests/helpers/image.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { readFile, remove } from 'fs-extra' -import { join } from 'path' -import { execPromise } from '@server/helpers/core-utils' -import { buildAbsoluteFixturePath, root } from '@shared/core-utils' -import { processImage } from '../../../server/helpers/image-utils' - -async function checkBuffers (path1: string, path2: string, equals: boolean) { - const [ buf1, buf2 ] = await Promise.all([ - readFile(path1), - readFile(path2) - ]) - - if (equals) { - expect(buf1.equals(buf2)).to.be.true - } else { - expect(buf1.equals(buf2)).to.be.false - } -} - -async function hasTitleExif (path: string) { - const result = JSON.parse(await execPromise(`exiftool -json ${path}`)) - - return result[0]?.Title === 'should be removed' -} - -describe('Image helpers', function () { - const imageDestDir = join(root(), 'test-images') - - const imageDestJPG = join(imageDestDir, 'test.jpg') - const imageDestPNG = join(imageDestDir, 'test.png') - - const thumbnailSize = { width: 280, height: 157 } - - it('Should skip processing if the source image is okay', async function () { - const input = buildAbsoluteFixturePath('custom-thumbnail.jpg') - await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) - - await checkBuffers(input, imageDestJPG, true) - }) - - it('Should not skip processing if the source image does not have the appropriate extension', async function () { - const input = buildAbsoluteFixturePath('custom-thumbnail.png') - await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) - - await checkBuffers(input, imageDestJPG, false) - }) - - it('Should not skip processing if the source image does not have the appropriate size', async function () { - const input = buildAbsoluteFixturePath('custom-preview.jpg') - await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) - - await checkBuffers(input, imageDestJPG, false) - }) - - it('Should not skip processing if the source image does not have the appropriate size', async function () { - const input = buildAbsoluteFixturePath('custom-thumbnail-big.jpg') - await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) - - await checkBuffers(input, imageDestJPG, false) - }) - - it('Should strip exif for a jpg file that can not be copied', async function () { - const input = buildAbsoluteFixturePath('exif.jpg') - expect(await hasTitleExif(input)).to.be.true - - await processImage({ path: input, destination: imageDestJPG, newSize: { width: 100, height: 100 }, keepOriginal: true }) - await checkBuffers(input, imageDestJPG, false) - - expect(await hasTitleExif(imageDestJPG)).to.be.false - }) - - it('Should strip exif for a jpg file that could be copied', async function () { - const input = buildAbsoluteFixturePath('exif.jpg') - expect(await hasTitleExif(input)).to.be.true - - await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) - await checkBuffers(input, imageDestJPG, false) - - expect(await hasTitleExif(imageDestJPG)).to.be.false - }) - - it('Should strip exif for png', async function () { - const input = buildAbsoluteFixturePath('exif.png') - expect(await hasTitleExif(input)).to.be.true - - await processImage({ path: input, destination: imageDestPNG, newSize: thumbnailSize, keepOriginal: true }) - expect(await hasTitleExif(imageDestPNG)).to.be.false - }) - - after(async function () { - await remove(imageDestDir) - }) -}) diff --git a/server/tests/helpers/index.ts b/server/tests/helpers/index.ts deleted file mode 100644 index 073ae6455..000000000 --- a/server/tests/helpers/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import './comment-model' -import './core-utils' -import './crypto' -import './dns' -import './image' -import './markdown' -import './request' -import './validator' -import './version' diff --git a/server/tests/helpers/markdown.ts b/server/tests/helpers/markdown.ts deleted file mode 100644 index 6fab31d6f..000000000 --- a/server/tests/helpers/markdown.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { mdToOneLinePlainText } from '@server/helpers/markdown' -import { expect } from 'chai' - -describe('Markdown helpers', function () { - - describe('Plain text', function () { - - it('Should convert a list to plain text', function () { - const result = mdToOneLinePlainText(`* list 1 -* list 2 -* list 3`) - - expect(result).to.equal('list 1, list 2, list 3') - }) - - it('Should convert a list with indentation to plain text', function () { - const result = mdToOneLinePlainText(`Hello: - * list 1 - * list 2 - * list 3`) - - expect(result).to.equal('Hello: list 1, list 2, list 3') - }) - - it('Should convert HTML to plain text', function () { - const result = mdToOneLinePlainText(`**Hello** coucou`) - - expect(result).to.equal('Hello coucou') - }) - - it('Should convert tags to plain text', function () { - const result = mdToOneLinePlainText(`#déconversion\n#newage\n#histoire`) - - expect(result).to.equal('#déconversion #newage #histoire') - }) - }) -}) diff --git a/server/tests/helpers/request.ts b/server/tests/helpers/request.ts deleted file mode 100644 index 363237df5..000000000 --- a/server/tests/helpers/request.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, remove } from 'fs-extra' -import { join } from 'path' -import { root, wait } from '@shared/core-utils' -import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' -import { FIXTURE_URLS, Mock429 } from '../shared' - -describe('Request helpers', function () { - const destPath1 = join(root(), 'test-output-1.txt') - const destPath2 = join(root(), 'test-output-2.txt') - - it('Should throw an error when the bytes limit is exceeded for request', async function () { - try { - await doRequest(FIXTURE_URLS.file4K, { bodyKBLimit: 3 }) - } catch { - return - } - - throw new Error('No error thrown by do request') - }) - - it('Should throw an error when the bytes limit is exceeded for request and save file', async function () { - try { - await doRequestAndSaveToFile(FIXTURE_URLS.file4K, destPath1, { bodyKBLimit: 3 }) - } catch { - - await wait(500) - expect(await pathExists(destPath1)).to.be.false - return - } - - throw new Error('No error thrown by do request and save to file') - }) - - it('Should correctly retry on 429 error', async function () { - this.timeout(25000) - - const mock = new Mock429() - const port = await mock.initialize() - - const before = new Date().getTime() - await doRequest('http://127.0.0.1:' + port) - - expect(new Date().getTime() - before).to.be.greaterThan(2000) - - await mock.terminate() - }) - - it('Should succeed if the file is below the limit', async function () { - await doRequest(FIXTURE_URLS.file4K, { bodyKBLimit: 5 }) - await doRequestAndSaveToFile(FIXTURE_URLS.file4K, destPath2, { bodyKBLimit: 5 }) - - expect(await pathExists(destPath2)).to.be.true - }) - - after(async function () { - await remove(destPath1) - await remove(destPath2) - }) -}) diff --git a/server/tests/helpers/validator.ts b/server/tests/helpers/validator.ts deleted file mode 100644 index f40a3aaae..000000000 --- a/server/tests/helpers/validator.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { isPluginStableOrUnstableVersionValid, isPluginStableVersionValid } from '@server/helpers/custom-validators/plugins' - -describe('Validators', function () { - - it('Should correctly check stable plugin versions', async function () { - expect(isPluginStableVersionValid('3.4.0')).to.be.true - expect(isPluginStableVersionValid('0.4.0')).to.be.true - expect(isPluginStableVersionValid('0.1.0')).to.be.true - - expect(isPluginStableVersionValid('0.1.0-beta-1')).to.be.false - expect(isPluginStableVersionValid('hello')).to.be.false - expect(isPluginStableVersionValid('0.x.a')).to.be.false - }) - - it('Should correctly check unstable plugin versions', async function () { - expect(isPluginStableOrUnstableVersionValid('3.4.0')).to.be.true - expect(isPluginStableOrUnstableVersionValid('0.4.0')).to.be.true - expect(isPluginStableOrUnstableVersionValid('0.1.0')).to.be.true - - expect(isPluginStableOrUnstableVersionValid('0.1.0-beta.1')).to.be.true - expect(isPluginStableOrUnstableVersionValid('0.1.0-alpha.45')).to.be.true - expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45')).to.be.true - - expect(isPluginStableOrUnstableVersionValid('hello')).to.be.false - expect(isPluginStableOrUnstableVersionValid('0.x.a')).to.be.false - expect(isPluginStableOrUnstableVersionValid('0.1.0-rc-45')).to.be.false - expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45d')).to.be.false - }) -}) diff --git a/server/tests/helpers/version.ts b/server/tests/helpers/version.ts deleted file mode 100644 index 2a90efba3..000000000 --- a/server/tests/helpers/version.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { compareSemVer } from '@shared/core-utils' - -describe('Version', function () { - - it('Should correctly compare two stable versions', async function () { - expect(compareSemVer('3.4.0', '3.5.0')).to.be.below(0) - expect(compareSemVer('3.5.0', '3.4.0')).to.be.above(0) - - expect(compareSemVer('3.4.0', '4.1.0')).to.be.below(0) - expect(compareSemVer('4.1.0', '3.4.0')).to.be.above(0) - - expect(compareSemVer('3.4.0', '3.4.1')).to.be.below(0) - expect(compareSemVer('3.4.1', '3.4.0')).to.be.above(0) - }) - - it('Should correctly compare two unstable version', async function () { - expect(compareSemVer('3.4.0-alpha', '3.4.0-beta.1')).to.be.below(0) - expect(compareSemVer('3.4.0-alpha.1', '3.4.0-beta.1')).to.be.below(0) - expect(compareSemVer('3.4.0-beta.1', '3.4.0-beta.2')).to.be.below(0) - expect(compareSemVer('3.4.0-beta.1', '3.5.0-alpha.1')).to.be.below(0) - - expect(compareSemVer('3.4.0-alpha.1', '3.4.0-nightly.4')).to.be.below(0) - expect(compareSemVer('3.4.0-nightly.3', '3.4.0-nightly.4')).to.be.below(0) - expect(compareSemVer('3.3.0-nightly.5', '3.4.0-nightly.4')).to.be.below(0) - }) - - it('Should correctly compare a stable and unstable versions', async function () { - expect(compareSemVer('3.4.0', '3.4.1-beta.1')).to.be.below(0) - expect(compareSemVer('3.4.0-beta.1', '3.4.0-beta.2')).to.be.below(0) - expect(compareSemVer('3.4.0-beta.1', '3.4.0')).to.be.below(0) - expect(compareSemVer('3.4.0-nightly.4', '3.4.0')).to.be.below(0) - }) -}) diff --git a/server/tests/index.ts b/server/tests/index.ts deleted file mode 100644 index 4ec1ebe67..000000000 --- a/server/tests/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Order of the tests we want to execute -import './client' -import './misc-endpoints' -import './feeds/' -import './cli/' -import './api/' -import './peertube-runner/' -import './plugins/' -import './helpers/' -import './lib/' diff --git a/server/tests/lib/index.ts b/server/tests/lib/index.ts deleted file mode 100644 index a40df35fd..000000000 --- a/server/tests/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './video-constant-registry-factory' diff --git a/server/tests/lib/video-constant-registry-factory.ts b/server/tests/lib/video-constant-registry-factory.ts deleted file mode 100644 index c3480dc12..000000000 --- a/server/tests/lib/video-constant-registry-factory.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions */ -import { expect } from 'chai' -import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory' -import { - VIDEO_CATEGORIES, - VIDEO_LANGUAGES, - VIDEO_LICENCES, - VIDEO_PLAYLIST_PRIVACIES, - VIDEO_PRIVACIES -} from '@server/initializers/constants' -import { - VideoPlaylistPrivacy, - VideoPrivacy -} from '@shared/models' - -describe('VideoConstantManagerFactory', function () { - const factory = new VideoConstantManagerFactory('peertube-plugin-constants') - - afterEach(() => { - factory.resetVideoConstants('peertube-plugin-constants') - }) - - describe('VideoCategoryManager', () => { - const videoCategoryManager = factory.createVideoConstantManager('category') - - it('Should be able to list all video category constants', () => { - const constants = videoCategoryManager.getConstants() - expect(constants).to.deep.equal(VIDEO_CATEGORIES) - }) - - it('Should be able to delete a video category constant', () => { - const successfullyDeleted = videoCategoryManager.deleteConstant(1) - expect(successfullyDeleted).to.be.true - expect(videoCategoryManager.getConstantValue(1)).to.be.undefined - }) - - it('Should be able to add a video category constant', () => { - const successfullyAdded = videoCategoryManager.addConstant(42, 'The meaning of life') - expect(successfullyAdded).to.be.true - expect(videoCategoryManager.getConstantValue(42)).to.equal('The meaning of life') - }) - - it('Should be able to reset video category constants', () => { - videoCategoryManager.deleteConstant(1) - videoCategoryManager.resetConstants() - expect(videoCategoryManager.getConstantValue(1)).not.be.undefined - }) - }) - - describe('VideoLicenceManager', () => { - const videoLicenceManager = factory.createVideoConstantManager('licence') - it('Should be able to list all video licence constants', () => { - const constants = videoLicenceManager.getConstants() - expect(constants).to.deep.equal(VIDEO_LICENCES) - }) - - it('Should be able to delete a video licence constant', () => { - const successfullyDeleted = videoLicenceManager.deleteConstant(1) - expect(successfullyDeleted).to.be.true - expect(videoLicenceManager.getConstantValue(1)).to.be.undefined - }) - - it('Should be able to add a video licence constant', () => { - const successfullyAdded = videoLicenceManager.addConstant(42, 'European Union Public Licence') - expect(successfullyAdded).to.be.true - expect(videoLicenceManager.getConstantValue(42 as any)).to.equal('European Union Public Licence') - }) - - it('Should be able to reset video licence constants', () => { - videoLicenceManager.deleteConstant(1) - videoLicenceManager.resetConstants() - expect(videoLicenceManager.getConstantValue(1)).not.be.undefined - }) - }) - - describe('PlaylistPrivacyManager', () => { - const playlistPrivacyManager = factory.createVideoConstantManager('playlistPrivacy') - it('Should be able to list all video playlist privacy constants', () => { - const constants = playlistPrivacyManager.getConstants() - expect(constants).to.deep.equal(VIDEO_PLAYLIST_PRIVACIES) - }) - - it('Should be able to delete a video playlist privacy constant', () => { - const successfullyDeleted = playlistPrivacyManager.deleteConstant(1) - expect(successfullyDeleted).to.be.true - expect(playlistPrivacyManager.getConstantValue(1)).to.be.undefined - }) - - it('Should be able to add a video playlist privacy constant', () => { - const successfullyAdded = playlistPrivacyManager.addConstant(42 as any, 'Friends only') - expect(successfullyAdded).to.be.true - expect(playlistPrivacyManager.getConstantValue(42 as any)).to.equal('Friends only') - }) - - it('Should be able to reset video playlist privacy constants', () => { - playlistPrivacyManager.deleteConstant(1) - playlistPrivacyManager.resetConstants() - expect(playlistPrivacyManager.getConstantValue(1)).not.be.undefined - }) - }) - - describe('VideoPrivacyManager', () => { - const videoPrivacyManager = factory.createVideoConstantManager('privacy') - it('Should be able to list all video privacy constants', () => { - const constants = videoPrivacyManager.getConstants() - expect(constants).to.deep.equal(VIDEO_PRIVACIES) - }) - - it('Should be able to delete a video privacy constant', () => { - const successfullyDeleted = videoPrivacyManager.deleteConstant(1) - expect(successfullyDeleted).to.be.true - expect(videoPrivacyManager.getConstantValue(1)).to.be.undefined - }) - - it('Should be able to add a video privacy constant', () => { - const successfullyAdded = videoPrivacyManager.addConstant(42 as any, 'Friends only') - expect(successfullyAdded).to.be.true - expect(videoPrivacyManager.getConstantValue(42 as any)).to.equal('Friends only') - }) - - it('Should be able to reset video privacy constants', () => { - videoPrivacyManager.deleteConstant(1) - videoPrivacyManager.resetConstants() - expect(videoPrivacyManager.getConstantValue(1)).not.be.undefined - }) - }) - - describe('VideoLanguageManager', () => { - const videoLanguageManager = factory.createVideoConstantManager('language') - it('Should be able to list all video language constants', () => { - const constants = videoLanguageManager.getConstants() - expect(constants).to.deep.equal(VIDEO_LANGUAGES) - }) - - it('Should be able to add a video language constant', () => { - const successfullyAdded = videoLanguageManager.addConstant('fr', 'Fr occitan') - expect(successfullyAdded).to.be.true - expect(videoLanguageManager.getConstantValue('fr')).to.equal('Fr occitan') - }) - - it('Should be able to delete a video language constant', () => { - videoLanguageManager.addConstant('fr', 'Fr occitan') - const successfullyDeleted = videoLanguageManager.deleteConstant('fr') - expect(successfullyDeleted).to.be.true - expect(videoLanguageManager.getConstantValue('fr')).to.be.undefined - }) - - it('Should be able to reset video language constants', () => { - videoLanguageManager.addConstant('fr', 'Fr occitan') - videoLanguageManager.resetConstants() - expect(videoLanguageManager.getConstantValue('fr')).to.be.undefined - }) - }) -}) diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts deleted file mode 100644 index f9cf2b717..000000000 --- a/server/tests/misc-endpoints.ts +++ /dev/null @@ -1,237 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { writeJson } from 'fs-extra' -import { join } from 'path' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' -import { expectLogDoesNotContain } from './shared' - -describe('Test misc endpoints', function () { - let server: PeerTubeServer - let wellKnownPath: string - - before(async function () { - this.timeout(120000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - - wellKnownPath = server.getDirectoryPath('well-known') - }) - - describe('Test a well known endpoints', function () { - - it('Should get security.txt', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/security.txt', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('security issue') - }) - - it('Should get nodeinfo', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/nodeinfo', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.links).to.be.an('array') - expect(res.body.links).to.have.lengthOf(1) - expect(res.body.links[0].rel).to.equal('http://nodeinfo.diaspora.software/ns/schema/2.0') - }) - - it('Should get dnt policy text', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/dnt-policy.txt', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('http://www.w3.org/TR/tracking-dnt') - }) - - it('Should get dnt policy', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/dnt', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.tracking).to.equal('N') - }) - - it('Should get change-password location', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/change-password', - expectedStatus: HttpStatusCode.FOUND_302 - }) - - expect(res.header.location).to.equal('/my-account/settings') - }) - - it('Should test webfinger', async function () { - const resource = 'acct:peertube@' + server.host - const accountUrl = server.url + '/accounts/peertube' - - const res = await makeGetRequest({ - url: server.url, - path: '/.well-known/webfinger?resource=' + resource, - expectedStatus: HttpStatusCode.OK_200 - }) - - const data = res.body - - expect(data.subject).to.equal(resource) - expect(data.aliases).to.contain(accountUrl) - - const self = data.links.find(l => l.rel === 'self') - expect(self).to.exist - expect(self.type).to.equal('application/activity+json') - expect(self.href).to.equal(accountUrl) - - const remoteInteract = data.links.find(l => l.rel === 'http://ostatus.org/schema/1.0/subscribe') - expect(remoteInteract).to.exist - expect(remoteInteract.template).to.equal(server.url + '/remote-interaction?uri={uri}') - }) - - it('Should return 404 for non-existing files in /.well-known', async function () { - await makeGetRequest({ - url: server.url, - path: '/.well-known/non-existing-file', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should return custom file from /.well-known', async function () { - const filename = 'existing-file.json' - - await writeJson(join(wellKnownPath, filename), { iThink: 'therefore I am' }) - - const { body } = await makeGetRequest({ - url: server.url, - path: '/.well-known/' + filename, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(body.iThink).to.equal('therefore I am') - }) - }) - - describe('Test classic static endpoints', function () { - - it('Should get robots.txt', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/robots.txt', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('User-agent') - }) - - it('Should get security.txt', async function () { - await makeGetRequest({ - url: server.url, - path: '/security.txt', - expectedStatus: HttpStatusCode.MOVED_PERMANENTLY_301 - }) - }) - - it('Should get nodeinfo', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/nodeinfo/2.0.json', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.software.name).to.equal('peertube') - expect(res.body.usage.users.activeMonth).to.equal(1) - expect(res.body.usage.users.activeHalfyear).to.equal(1) - }) - }) - - describe('Test bots endpoints', function () { - - it('Should get the empty sitemap', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/sitemap.xml', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"') - expect(res.text).to.contain('' + server.url + '/about/instance') - }) - - it('Should get the empty cached sitemap', async function () { - const res = await makeGetRequest({ - url: server.url, - path: '/sitemap.xml', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"') - expect(res.text).to.contain('' + server.url + '/about/instance') - }) - - it('Should add videos, channel and accounts and get sitemap', async function () { - this.timeout(35000) - - await server.videos.upload({ attributes: { name: 'video 1', nsfw: false } }) - await server.videos.upload({ attributes: { name: 'video 2', nsfw: false } }) - await server.videos.upload({ attributes: { name: 'video 3', privacy: VideoPrivacy.PRIVATE } }) - - await server.channels.create({ attributes: { name: 'channel1', displayName: 'channel 1' } }) - await server.channels.create({ attributes: { name: 'channel2', displayName: 'channel 2' } }) - - await server.users.create({ username: 'user1', password: 'password' }) - await server.users.create({ username: 'user2', password: 'password' }) - - const res = await makeGetRequest({ - url: server.url, - path: '/sitemap.xml?t=1', // avoid using cache - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.text).to.contain('xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"') - expect(res.text).to.contain('' + server.url + '/about/instance') - - expect(res.text).to.contain('video 1') - expect(res.text).to.contain('video 2') - expect(res.text).to.not.contain('video 3') - - expect(res.text).to.contain('' + server.url + '/video-channels/channel1') - expect(res.text).to.contain('' + server.url + '/video-channels/channel2') - - expect(res.text).to.contain('' + server.url + '/accounts/user1') - expect(res.text).to.contain('' + server.url + '/accounts/user2') - }) - - it('Should not fail with big title/description videos', async function () { - const name = 'v'.repeat(115) - - await server.videos.upload({ attributes: { name, description: 'd'.repeat(2500), nsfw: false } }) - - const res = await makeGetRequest({ - url: server.url, - path: '/sitemap.xml?t=2', // avoid using cache - expectedStatus: HttpStatusCode.OK_200 - }) - - await expectLogDoesNotContain(server, 'Warning in sitemap generation') - await expectLogDoesNotContain(server, 'Error in sitemap generation') - - expect(res.text).to.contain(`${'v'.repeat(97)}...`) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/peertube-runner/client-cli.ts b/server/tests/peertube-runner/client-cli.ts deleted file mode 100644 index 5cbdc4e77..000000000 --- a/server/tests/peertube-runner/client-cli.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { PeerTubeRunnerProcess } from '@server/tests/shared' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' - -describe('Test peertube-runner program client CLI', function () { - let server: PeerTubeServer - let peertubeRunner: PeerTubeRunnerProcess - - before(async function () { - this.timeout(120_000) - - server = await createSingleServer(1) - - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await server.config.enableRemoteTranscoding() - - peertubeRunner = new PeerTubeRunnerProcess(server) - await peertubeRunner.runServer() - }) - - it('Should not have PeerTube instance listed', async function () { - const data = await peertubeRunner.listRegisteredPeerTubeInstances() - - expect(data).to.not.contain(server.url) - }) - - it('Should register a new PeerTube instance', async function () { - const registrationToken = await server.runnerRegistrationTokens.getFirstRegistrationToken() - - await peertubeRunner.registerPeerTubeInstance({ - registrationToken, - runnerName: 'my super runner', - runnerDescription: 'super description' - }) - }) - - it('Should list this new PeerTube instance', async function () { - const data = await peertubeRunner.listRegisteredPeerTubeInstances() - - expect(data).to.contain(server.url) - expect(data).to.contain('my super runner') - expect(data).to.contain('super description') - }) - - it('Should still have the configuration after a restart', async function () { - peertubeRunner.kill() - - await peertubeRunner.runServer() - }) - - it('Should unregister the PeerTube instance', async function () { - await peertubeRunner.unregisterPeerTubeInstance({ runnerName: 'my super runner' }) - }) - - it('Should not have PeerTube instance listed', async function () { - const data = await peertubeRunner.listRegisteredPeerTubeInstances() - - expect(data).to.not.contain(server.url) - }) - - after(async function () { - peertubeRunner.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/peertube-runner/index.ts b/server/tests/peertube-runner/index.ts deleted file mode 100644 index 470316417..000000000 --- a/server/tests/peertube-runner/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './client-cli' -export * from './live-transcoding' -export * from './studio-transcoding' -export * from './vod-transcoding' diff --git a/server/tests/peertube-runner/live-transcoding.ts b/server/tests/peertube-runner/live-transcoding.ts deleted file mode 100644 index 41b01f8d5..000000000 --- a/server/tests/peertube-runner/live-transcoding.ts +++ /dev/null @@ -1,201 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { - checkPeerTubeRunnerCacheIsEmpty, - expectStartWith, - PeerTubeRunnerProcess, - SQLCommand, - testLiveVideoResolutions -} from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled, wait } from '@shared/core-utils' -import { HttpStatusCode, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - findExternalSavedVideo, - makeRawRequest, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs, - waitUntilLivePublishedOnAllServers, - waitUntilLiveWaitingOnAllServers -} from '@shared/server-commands' - -describe('Test Live transcoding in peertube-runner program', function () { - let servers: PeerTubeServer[] = [] - let peertubeRunner: PeerTubeRunnerProcess - let sqlCommandServer1: SQLCommand - - function runSuite (options: { - objectStorage?: ObjectStorageCommand - } = {}) { - const { objectStorage } = options - - it('Should enable transcoding without additional resolutions', async function () { - this.timeout(120000) - - const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid }) - await waitUntilLivePublishedOnAllServers(servers, video.uuid) - await waitJobs(servers) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: video.uuid, - resolutions: [ 720, 480, 360, 240, 144 ], - objectStorage, - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveWaitingOnAllServers(servers, video.uuid) - await servers[0].videos.remove({ id: video.id }) - }) - - it('Should transcode audio only RTMP stream', async function () { - this.timeout(120000) - - const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.UNLISTED }) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid, fixtureName: 'video_short_no_audio.mp4' }) - await waitUntilLivePublishedOnAllServers(servers, video.uuid) - await waitJobs(servers) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveWaitingOnAllServers(servers, video.uuid) - await servers[0].videos.remove({ id: video.id }) - }) - - it('Should save a replay', async function () { - this.timeout(240000) - - const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: true }) - - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid }) - await waitUntilLivePublishedOnAllServers(servers, video.uuid) - - await testLiveVideoResolutions({ - originServer: servers[0], - sqlCommand: sqlCommandServer1, - servers, - liveVideoId: video.uuid, - resolutions: [ 720, 480, 360, 240, 144 ], - objectStorage, - transcoded: true - }) - - await stopFfmpeg(ffmpegCommand) - - await waitUntilLiveWaitingOnAllServers(servers, video.uuid) - await waitJobs(servers) - - const session = await servers[0].live.findLatestSession({ videoId: video.uuid }) - expect(session.endingProcessed).to.be.true - expect(session.endDate).to.exist - expect(session.saveReplay).to.be.true - - const videoLiveDetails = await servers[0].videos.get({ id: video.uuid }) - const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) - - for (const server of servers) { - const video = await server.videos.get({ id: replay.uuid }) - - expect(video.files).to.have.lengthOf(0) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const files = video.streamingPlaylists[0].files - expect(files).to.have.lengthOf(5) - - for (const file of files) { - if (objectStorage) { - expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - } - - await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - } - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - sqlCommandServer1 = new SQLCommand(servers[0]) - - await servers[0].config.enableRemoteTranscoding() - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - await servers[0].config.enableLive({ allowReplay: true, resolutions: 'max', transcoding: true }) - - const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken() - - peertubeRunner = new PeerTubeRunnerProcess(servers[0]) - await peertubeRunner.runServer() - await peertubeRunner.registerPeerTubeInstance({ registrationToken, runnerName: 'runner' }) - }) - - describe('With lives on local filesystem storage', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ webVideo: true, hls: false, with0p: true }) - }) - - runSuite() - }) - - describe('With lives on object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - - await servers[0].run(objectStorage.getDefaultMockConfig()) - - // Wait for peertube runner socket reconnection - await wait(1500) - }) - - runSuite({ objectStorage }) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - describe('Check cleanup', function () { - - it('Should have an empty cache directory', async function () { - await checkPeerTubeRunnerCacheIsEmpty(peertubeRunner) - }) - }) - - after(async function () { - if (peertubeRunner) { - await peertubeRunner.unregisterPeerTubeInstance({ runnerName: 'runner' }) - peertubeRunner.kill() - } - - if (sqlCommandServer1) await sqlCommandServer1.cleanup() - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/peertube-runner/studio-transcoding.ts b/server/tests/peertube-runner/studio-transcoding.ts deleted file mode 100644 index 56bfef897..000000000 --- a/server/tests/peertube-runner/studio-transcoding.ts +++ /dev/null @@ -1,124 +0,0 @@ - -import { expect } from 'chai' -import { checkPeerTubeRunnerCacheIsEmpty, checkVideoDuration, expectStartWith, PeerTubeRunnerProcess } from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled, getAllFiles, wait } from '@shared/core-utils' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - VideoStudioCommand, - waitJobs -} from '@shared/server-commands' - -describe('Test studio transcoding in peertube-runner program', function () { - let servers: PeerTubeServer[] = [] - let peertubeRunner: PeerTubeRunnerProcess - - function runSuite (options: { - objectStorage?: ObjectStorageCommand - } = {}) { - const { objectStorage } = options - - it('Should run a complex studio transcoding', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'mp4', fixture: 'video_short.mp4' }) - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - const oldFileUrls = getAllFiles(video).map(f => f.fileUrl) - - await servers[0].videoStudio.createEditionTasks({ videoId: uuid, tasks: VideoStudioCommand.getComplexTask() }) - await waitJobs(servers, { runnerJobs: true }) - - for (const server of servers) { - const video = await server.videos.get({ id: uuid }) - const files = getAllFiles(video) - - for (const f of files) { - expect(oldFileUrls).to.not.include(f.fileUrl) - } - - if (objectStorage) { - for (const webVideoFile of video.files) { - expectStartWith(webVideoFile.fileUrl, objectStorage.getMockWebVideosBaseUrl()) - } - - for (const hlsFile of video.streamingPlaylists[0].files) { - expectStartWith(hlsFile.fileUrl, objectStorage.getMockPlaylistBaseUrl()) - } - } - - await checkVideoDuration(server, uuid, 9) - } - }) - } - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true }) - await servers[0].config.enableStudio() - await servers[0].config.enableRemoteStudio() - - const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken() - - peertubeRunner = new PeerTubeRunnerProcess(servers[0]) - await peertubeRunner.runServer() - await peertubeRunner.registerPeerTubeInstance({ registrationToken, runnerName: 'runner' }) - }) - - describe('With videos on local filesystem storage', function () { - runSuite() - }) - - describe('With videos on object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - - await servers[0].run(objectStorage.getDefaultMockConfig()) - - // Wait for peertube runner socket reconnection - await wait(1500) - }) - - runSuite({ objectStorage }) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - describe('Check cleanup', function () { - - it('Should have an empty cache directory', async function () { - await checkPeerTubeRunnerCacheIsEmpty(peertubeRunner) - }) - }) - - after(async function () { - if (peertubeRunner) { - await peertubeRunner.unregisterPeerTubeInstance({ runnerName: 'runner' }) - peertubeRunner.kill() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/peertube-runner/vod-transcoding.ts b/server/tests/peertube-runner/vod-transcoding.ts deleted file mode 100644 index b3b62e5e0..000000000 --- a/server/tests/peertube-runner/vod-transcoding.ts +++ /dev/null @@ -1,350 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { - checkPeerTubeRunnerCacheIsEmpty, - completeCheckHlsPlaylist, - completeWebVideoFilesCheck, - PeerTubeRunnerProcess -} from '@server/tests/shared' -import { areMockObjectStorageTestsDisabled, getAllFiles, wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - ObjectStorageCommand, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' - -describe('Test VOD transcoding in peertube-runner program', function () { - let servers: PeerTubeServer[] = [] - let peertubeRunner: PeerTubeRunnerProcess - - function runSuite (options: { - webVideoEnabled: boolean - hlsEnabled: boolean - objectStorage?: ObjectStorageCommand - }) { - const { webVideoEnabled, hlsEnabled, objectStorage } = options - - const objectStorageBaseUrlWebVideo = objectStorage - ? objectStorage.getMockWebVideosBaseUrl() - : undefined - - const objectStorageBaseUrlHLS = objectStorage - ? objectStorage.getMockPlaylistBaseUrl() - : undefined - - it('Should upload a classic video mp4 and transcode it', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'mp4', fixture: 'video_short.mp4' }) - - await waitJobs(servers, { runnerJobs: true }) - - for (const server of servers) { - if (webVideoEnabled) { - await completeWebVideoFilesCheck({ - server, - originServer: servers[0], - fixture: 'video_short.mp4', - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlWebVideo, - files: [ - { resolution: 0 }, - { resolution: 144 }, - { resolution: 240 }, - { resolution: 360 }, - { resolution: 480 }, - { resolution: 720 } - ] - }) - } - - if (hlsEnabled) { - await completeCheckHlsPlaylist({ - hlsOnly: !webVideoEnabled, - servers, - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlHLS, - resolutions: [ 720, 480, 360, 240, 144, 0 ] - }) - } - } - }) - - it('Should upload a webm video and transcode it', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'mp4', fixture: 'video_short.webm' }) - - await waitJobs(servers, { runnerJobs: true }) - - for (const server of servers) { - if (webVideoEnabled) { - await completeWebVideoFilesCheck({ - server, - originServer: servers[0], - fixture: 'video_short.webm', - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlWebVideo, - files: [ - { resolution: 0 }, - { resolution: 144 }, - { resolution: 240 }, - { resolution: 360 }, - { resolution: 480 }, - { resolution: 720 } - ] - }) - } - - if (hlsEnabled) { - await completeCheckHlsPlaylist({ - hlsOnly: !webVideoEnabled, - servers, - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlHLS, - resolutions: [ 720, 480, 360, 240, 144, 0 ] - }) - } - } - }) - - it('Should upload an audio only video and transcode it', async function () { - this.timeout(120000) - - const attributes = { name: 'audio_without_preview', fixture: 'sample.ogg' } - const { uuid } = await servers[0].videos.upload({ attributes, mode: 'resumable' }) - - await waitJobs(servers, { runnerJobs: true }) - - for (const server of servers) { - if (webVideoEnabled) { - await completeWebVideoFilesCheck({ - server, - originServer: servers[0], - fixture: 'sample.ogg', - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlWebVideo, - files: [ - { resolution: 0 }, - { resolution: 144 }, - { resolution: 240 }, - { resolution: 360 }, - { resolution: 480 } - ] - }) - } - - if (hlsEnabled) { - await completeCheckHlsPlaylist({ - hlsOnly: !webVideoEnabled, - servers, - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlHLS, - resolutions: [ 480, 360, 240, 144, 0 ] - }) - } - } - }) - - it('Should upload a private video and transcode it', async function () { - this.timeout(120000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'mp4', fixture: 'video_short.mp4', privacy: VideoPrivacy.PRIVATE }) - - await waitJobs(servers, { runnerJobs: true }) - - if (webVideoEnabled) { - await completeWebVideoFilesCheck({ - server: servers[0], - originServer: servers[0], - fixture: 'video_short.mp4', - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlWebVideo, - files: [ - { resolution: 0 }, - { resolution: 144 }, - { resolution: 240 }, - { resolution: 360 }, - { resolution: 480 }, - { resolution: 720 } - ] - }) - } - - if (hlsEnabled) { - await completeCheckHlsPlaylist({ - hlsOnly: !webVideoEnabled, - servers: [ servers[0] ], - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlHLS, - resolutions: [ 720, 480, 360, 240, 144, 0 ] - }) - } - }) - - it('Should transcode videos on manual run', async function () { - this.timeout(120000) - - await servers[0].config.disableTranscoding() - - const { uuid } = await servers[0].videos.quickUpload({ name: 'manual transcoding', fixture: 'video_short.mp4' }) - await waitJobs(servers, { runnerJobs: true }) - - { - const video = await servers[0].videos.get({ id: uuid }) - expect(getAllFiles(video)).to.have.lengthOf(1) - } - - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - - await servers[0].videos.runTranscoding({ transcodingType: 'web-video', videoId: uuid }) - await waitJobs(servers, { runnerJobs: true }) - - await completeWebVideoFilesCheck({ - server: servers[0], - originServer: servers[0], - fixture: 'video_short.mp4', - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlWebVideo, - files: [ - { resolution: 0 }, - { resolution: 144 }, - { resolution: 240 }, - { resolution: 360 }, - { resolution: 480 }, - { resolution: 720 } - ] - }) - - await servers[0].videos.runTranscoding({ transcodingType: 'hls', videoId: uuid }) - await waitJobs(servers, { runnerJobs: true }) - - await completeCheckHlsPlaylist({ - hlsOnly: false, - servers: [ servers[0] ], - videoUUID: uuid, - objectStorageBaseUrl: objectStorageBaseUrlHLS, - resolutions: [ 720, 480, 360, 240, 144, 0 ] - }) - }) - } - - before(async function () { - this.timeout(120_000) - - servers = await createMultipleServers(2) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].config.enableRemoteTranscoding() - - const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken() - - peertubeRunner = new PeerTubeRunnerProcess(servers[0]) - await peertubeRunner.runServer() - await peertubeRunner.registerPeerTubeInstance({ registrationToken, runnerName: 'runner' }) - }) - - describe('With videos on local filesystem storage', function () { - - describe('Web video only enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ webVideo: true, hls: false, with0p: true }) - }) - - runSuite({ webVideoEnabled: true, hlsEnabled: false }) - }) - - describe('HLS videos only enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ webVideo: false, hls: true, with0p: true }) - }) - - runSuite({ webVideoEnabled: false, hlsEnabled: true }) - }) - - describe('Web video & HLS enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - }) - - runSuite({ webVideoEnabled: true, hlsEnabled: true }) - }) - }) - - describe('With videos on object storage', function () { - if (areMockObjectStorageTestsDisabled()) return - - const objectStorage = new ObjectStorageCommand() - - before(async function () { - await objectStorage.prepareDefaultMockBuckets() - - await servers[0].kill() - - await servers[0].run(objectStorage.getDefaultMockConfig()) - - // Wait for peertube runner socket reconnection - await wait(1500) - }) - - describe('Web video only enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ webVideo: true, hls: false, with0p: true }) - }) - - runSuite({ webVideoEnabled: true, hlsEnabled: false, objectStorage }) - }) - - describe('HLS videos only enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ webVideo: false, hls: true, with0p: true }) - }) - - runSuite({ webVideoEnabled: false, hlsEnabled: true, objectStorage }) - }) - - describe('Web video & HLS enabled', function () { - - before(async function () { - await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true }) - }) - - runSuite({ webVideoEnabled: true, hlsEnabled: true, objectStorage }) - }) - - after(async function () { - await objectStorage.cleanupMock() - }) - }) - - describe('Check cleanup', function () { - - it('Should have an empty cache directory', async function () { - await checkPeerTubeRunnerCacheIsEmpty(peertubeRunner) - }) - }) - - after(async function () { - if (peertubeRunner) { - await peertubeRunner.unregisterPeerTubeInstance({ runnerName: 'runner' }) - peertubeRunner.kill() - } - - await cleanupTests(servers) - }) -}) diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts deleted file mode 100644 index 773be0d76..000000000 --- a/server/tests/plugins/action-hooks.ts +++ /dev/null @@ -1,298 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { ServerHookName, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - killallServers, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers, - setDefaultVideoChannel, - stopFfmpeg, - waitJobs -} from '@shared/server-commands' - -describe('Test plugin action hooks', function () { - let servers: PeerTubeServer[] - let videoUUID: string - let threadId: number - - function checkHook (hook: ServerHookName, strictCount = true, count = 1) { - return servers[0].servers.waitUntilLog('Run hook ' + hook, count, strictCount) - } - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath() }) - - await killallServers([ servers[0] ]) - - await servers[0].run({ - live: { - enabled: true - } - }) - - await servers[0].config.enableFileUpdate() - - await doubleFollow(servers[0], servers[1]) - }) - - describe('Application hooks', function () { - it('Should run action:application.listening', async function () { - await checkHook('action:application.listening') - }) - }) - - describe('Videos hooks', function () { - - it('Should run action:api.video.uploaded', async function () { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video' } }) - videoUUID = uuid - - await checkHook('action:api.video.uploaded') - }) - - it('Should run action:api.video.updated', async function () { - await servers[0].videos.update({ id: videoUUID, attributes: { name: 'video updated' } }) - - await checkHook('action:api.video.updated') - }) - - it('Should run action:api.video.viewed', async function () { - await servers[0].views.simulateView({ id: videoUUID }) - - await checkHook('action:api.video.viewed') - }) - - it('Should run action:api.video.file-updated', async function () { - await servers[0].videos.replaceSourceFile({ videoId: videoUUID, fixture: 'video_short.mp4' }) - - await checkHook('action:api.video.file-updated') - }) - - it('Should run action:api.video.deleted', async function () { - await servers[0].videos.remove({ id: videoUUID }) - - await checkHook('action:api.video.deleted') - }) - - after(async function () { - const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) - videoUUID = uuid - }) - }) - - describe('Video channel hooks', function () { - const channelName = 'my_super_channel' - - it('Should run action:api.video-channel.created', async function () { - await servers[0].channels.create({ attributes: { name: channelName } }) - - await checkHook('action:api.video-channel.created') - }) - - it('Should run action:api.video-channel.updated', async function () { - await servers[0].channels.update({ channelName, attributes: { displayName: 'my display name' } }) - - await checkHook('action:api.video-channel.updated') - }) - - it('Should run action:api.video-channel.deleted', async function () { - await servers[0].channels.delete({ channelName }) - - await checkHook('action:api.video-channel.deleted') - }) - }) - - describe('Live hooks', function () { - - it('Should run action:api.live-video.created', async function () { - const attributes = { - name: 'live', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id - } - - await servers[0].live.create({ fields: attributes }) - - await checkHook('action:api.live-video.created') - }) - - it('Should run action:live.video.state.updated', async function () { - this.timeout(60000) - - const attributes = { - name: 'live', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id - } - - const { uuid: liveVideoId } = await servers[0].live.create({ fields: attributes }) - const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoId }) - await servers[0].live.waitUntilPublished({ videoId: liveVideoId }) - await waitJobs(servers) - - await checkHook('action:live.video.state.updated', true, 1) - - await stopFfmpeg(ffmpegCommand) - await servers[0].live.waitUntilEnded({ videoId: liveVideoId }) - await waitJobs(servers) - - await checkHook('action:live.video.state.updated', true, 2) - }) - }) - - describe('Comments hooks', function () { - it('Should run action:api.video-thread.created', async function () { - const created = await servers[0].comments.createThread({ videoId: videoUUID, text: 'thread' }) - threadId = created.id - - await checkHook('action:api.video-thread.created') - }) - - it('Should run action:api.video-comment-reply.created', async function () { - await servers[0].comments.addReply({ videoId: videoUUID, toCommentId: threadId, text: 'reply' }) - - await checkHook('action:api.video-comment-reply.created') - }) - - it('Should run action:api.video-comment.deleted', async function () { - await servers[0].comments.delete({ videoId: videoUUID, commentId: threadId }) - - await checkHook('action:api.video-comment.deleted') - }) - }) - - describe('Captions hooks', function () { - it('Should run action:api.video-caption.created', async function () { - await servers[0].captions.add({ videoId: videoUUID, language: 'en', fixture: 'subtitle-good.srt' }) - - await checkHook('action:api.video-caption.created') - }) - - it('Should run action:api.video-caption.deleted', async function () { - await servers[0].captions.delete({ videoId: videoUUID, language: 'en' }) - - await checkHook('action:api.video-caption.deleted') - }) - }) - - describe('Users hooks', function () { - let userId: number - - it('Should run action:api.user.registered', async function () { - await servers[0].registrations.register({ username: 'registered_user' }) - - await checkHook('action:api.user.registered') - }) - - it('Should run action:api.user.created', async function () { - const user = await servers[0].users.create({ username: 'created_user' }) - userId = user.id - - await checkHook('action:api.user.created') - }) - - it('Should run action:api.user.oauth2-got-token', async function () { - await servers[0].login.login({ user: { username: 'created_user' } }) - - await checkHook('action:api.user.oauth2-got-token') - }) - - it('Should run action:api.user.blocked', async function () { - await servers[0].users.banUser({ userId }) - - await checkHook('action:api.user.blocked') - }) - - it('Should run action:api.user.unblocked', async function () { - await servers[0].users.unbanUser({ userId }) - - await checkHook('action:api.user.unblocked') - }) - - it('Should run action:api.user.updated', async function () { - await servers[0].users.update({ userId, videoQuota: 50 }) - - await checkHook('action:api.user.updated') - }) - - it('Should run action:api.user.deleted', async function () { - await servers[0].users.remove({ userId }) - - await checkHook('action:api.user.deleted') - }) - }) - - describe('Playlist hooks', function () { - let playlistId: number - let videoId: number - - before(async function () { - { - const { id } = await servers[0].playlists.create({ - attributes: { - displayName: 'My playlist', - privacy: VideoPlaylistPrivacy.PRIVATE - } - }) - playlistId = id - } - - { - const { id } = await servers[0].videos.upload({ attributes: { name: 'my super name' } }) - videoId = id - } - }) - - it('Should run action:api.video-playlist-element.created', async function () { - await servers[0].playlists.addElement({ playlistId, attributes: { videoId } }) - - await checkHook('action:api.video-playlist-element.created') - }) - }) - - describe('Notification hook', function () { - - it('Should run action:notifier.notification.created', async function () { - await checkHook('action:notifier.notification.created', false) - }) - }) - - describe('Activity Pub hooks', function () { - let videoUUID: string - - it('Should run action:activity-pub.remote-video.created', async function () { - this.timeout(30000) - - const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) - videoUUID = uuid - - await servers[0].servers.waitUntilLog('action:activity-pub.remote-video.created - AP remote video - video remote video') - }) - - it('Should run action:activity-pub.remote-video.updated', async function () { - this.timeout(30000) - - await servers[1].videos.update({ id: videoUUID, attributes: { name: 'remote video updated' } }) - - await servers[0].servers.waitUntilLog( - 'action:activity-pub.remote-video.updated - AP remote video updated - video remote video updated', - 1, - false - ) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts deleted file mode 100644 index e4015939a..000000000 --- a/server/tests/plugins/external-auth.ts +++ /dev/null @@ -1,436 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' -import { - cleanupTests, - createSingleServer, - decodeQueryString, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' - -async function loginExternal (options: { - server: PeerTubeServer - npmName: string - authName: string - username: string - query?: any - expectedStatus?: HttpStatusCode - expectedStatusStep2?: HttpStatusCode -}) { - const res = await options.server.plugins.getExternalAuth({ - npmName: options.npmName, - npmVersion: '0.0.1', - authName: options.authName, - query: options.query, - expectedStatus: options.expectedStatus || HttpStatusCode.FOUND_302 - }) - - if (res.status !== HttpStatusCode.FOUND_302) return - - const location = res.header.location - const { externalAuthToken } = decodeQueryString(location) - - const resLogin = await options.server.login.loginUsingExternalToken({ - username: options.username, - externalAuthToken: externalAuthToken as string, - expectedStatus: options.expectedStatusStep2 - }) - - return resLogin.body -} - -describe('Test external auth plugins', function () { - let server: PeerTubeServer - - let cyanAccessToken: string - let cyanRefreshToken: string - - let kefkaAccessToken: string - let kefkaRefreshToken: string - let kefkaId: number - - let externalAuthToken: string - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1, { - rates_limit: { - login: { - max: 30 - } - } - }) - - await setAccessTokensToServers([ server ]) - - for (const suffix of [ 'one', 'two', 'three' ]) { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-external-auth-' + suffix) }) - } - }) - - it('Should display the correct configuration', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredExternalAuths - expect(auths).to.have.lengthOf(9) - - const auth2 = auths.find((a) => a.authName === 'external-auth-2') - expect(auth2).to.exist - expect(auth2.authDisplayName).to.equal('External Auth 2') - expect(auth2.npmName).to.equal('peertube-plugin-test-external-auth-one') - }) - - it('Should redirect for a Cyan login', async function () { - const res = await server.plugins.getExternalAuth({ - npmName: 'test-external-auth-one', - npmVersion: '0.0.1', - authName: 'external-auth-1', - query: { - username: 'cyan' - }, - expectedStatus: HttpStatusCode.FOUND_302 - }) - - const location = res.header.location - expect(location.startsWith('/login?')).to.be.true - - const searchParams = decodeQueryString(location) - - expect(searchParams.externalAuthToken).to.exist - expect(searchParams.username).to.equal('cyan') - - externalAuthToken = searchParams.externalAuthToken as string - }) - - it('Should reject auto external login with a missing or invalid token', async function () { - const command = server.login - - await command.loginUsingExternalToken({ username: 'cyan', externalAuthToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.loginUsingExternalToken({ username: 'cyan', externalAuthToken: 'blabla', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should reject auto external login with a missing or invalid username', async function () { - const command = server.login - - await command.loginUsingExternalToken({ username: '', externalAuthToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.loginUsingExternalToken({ username: '', externalAuthToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should reject auto external login with an expired token', async function () { - this.timeout(15000) - - await wait(5000) - - await server.login.loginUsingExternalToken({ - username: 'cyan', - externalAuthToken, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await server.servers.waitUntilLog('expired external auth token', 4) - }) - - it('Should auto login Cyan, create the user and use the token', async function () { - { - const res = await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-1', - query: { - username: 'cyan' - }, - username: 'cyan' - }) - - cyanAccessToken = res.access_token - cyanRefreshToken = res.refresh_token - } - - { - const body = await server.users.getMyInfo({ token: cyanAccessToken }) - expect(body.username).to.equal('cyan') - expect(body.account.displayName).to.equal('cyan') - expect(body.email).to.equal('cyan@example.com') - expect(body.role.id).to.equal(UserRole.USER) - expect(body.adminFlags).to.equal(UserAdminFlag.NONE) - expect(body.videoQuota).to.equal(5242880) - expect(body.videoQuotaDaily).to.equal(-1) - } - }) - - it('Should auto login Kefka, create the user and use the token', async function () { - { - const res = await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-2', - username: 'kefka' - }) - - kefkaAccessToken = res.access_token - kefkaRefreshToken = res.refresh_token - } - - { - const body = await server.users.getMyInfo({ token: kefkaAccessToken }) - expect(body.username).to.equal('kefka') - expect(body.account.displayName).to.equal('Kefka Palazzo') - expect(body.email).to.equal('kefka@example.com') - expect(body.role.id).to.equal(UserRole.ADMINISTRATOR) - expect(body.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST) - expect(body.videoQuota).to.equal(42000) - expect(body.videoQuotaDaily).to.equal(42100) - - kefkaId = body.id - } - }) - - it('Should refresh Cyan token, but not Kefka token', async function () { - { - const resRefresh = await server.login.refreshToken({ refreshToken: cyanRefreshToken }) - cyanAccessToken = resRefresh.body.access_token - cyanRefreshToken = resRefresh.body.refresh_token - - const body = await server.users.getMyInfo({ token: cyanAccessToken }) - expect(body.username).to.equal('cyan') - } - - { - await server.login.refreshToken({ refreshToken: kefkaRefreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - }) - - it('Should update Cyan profile', async function () { - await server.users.updateMe({ - token: cyanAccessToken, - displayName: 'Cyan Garamonde', - description: 'Retainer to the king of Doma' - }) - - const body = await server.users.getMyInfo({ token: cyanAccessToken }) - expect(body.account.displayName).to.equal('Cyan Garamonde') - expect(body.account.description).to.equal('Retainer to the king of Doma') - }) - - it('Should logout Cyan', async function () { - await server.login.logout({ token: cyanAccessToken }) - }) - - it('Should have logged out Cyan', async function () { - await server.servers.waitUntilLog('On logout cyan') - - await server.users.getMyInfo({ token: cyanAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should login Cyan and keep the old existing profile', async function () { - { - const res = await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-1', - query: { - username: 'cyan' - }, - username: 'cyan' - }) - - cyanAccessToken = res.access_token - } - - const body = await server.users.getMyInfo({ token: cyanAccessToken }) - expect(body.username).to.equal('cyan') - expect(body.account.displayName).to.equal('Cyan Garamonde') - expect(body.account.description).to.equal('Retainer to the king of Doma') - expect(body.role.id).to.equal(UserRole.USER) - }) - - it('Should login Kefka and update the profile', async function () { - { - await server.users.update({ userId: kefkaId, videoQuota: 43000, videoQuotaDaily: 43100 }) - await server.users.updateMe({ token: kefkaAccessToken, displayName: 'kefka updated' }) - - const body = await server.users.getMyInfo({ token: kefkaAccessToken }) - expect(body.username).to.equal('kefka') - expect(body.account.displayName).to.equal('kefka updated') - expect(body.videoQuota).to.equal(43000) - expect(body.videoQuotaDaily).to.equal(43100) - } - - { - const res = await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-2', - username: 'kefka' - }) - - kefkaAccessToken = res.access_token - kefkaRefreshToken = res.refresh_token - - const body = await server.users.getMyInfo({ token: kefkaAccessToken }) - expect(body.username).to.equal('kefka') - expect(body.account.displayName).to.equal('Kefka Palazzo') - expect(body.videoQuota).to.equal(42000) - expect(body.videoQuotaDaily).to.equal(43100) - } - }) - - it('Should not update an external auth email', async function () { - await server.users.updateMe({ - token: cyanAccessToken, - email: 'toto@example.com', - currentPassword: 'toto', - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should reject token of Kefka by the plugin hook', async function () { - await wait(5000) - - await server.users.getMyInfo({ token: kefkaAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should unregister external-auth-2 and do not login existing Kefka', async function () { - await server.plugins.updateSettings({ - npmName: 'peertube-plugin-test-external-auth-one', - settings: { disableKefka: true } - }) - - await server.login.login({ user: { username: 'kefka', password: 'fake' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - - await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-2', - query: { - username: 'kefka' - }, - username: 'kefka', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should have disabled this auth', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredExternalAuths - expect(auths).to.have.lengthOf(8) - - const auth1 = auths.find(a => a.authName === 'external-auth-2') - expect(auth1).to.not.exist - }) - - it('Should uninstall the plugin one and do not login Cyan', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-external-auth-one' }) - - await loginExternal({ - server, - npmName: 'test-external-auth-one', - authName: 'external-auth-1', - query: { - username: 'cyan' - }, - username: 'cyan', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - - await server.login.login({ user: { username: 'cyan', password: null }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.login.login({ user: { username: 'cyan', password: '' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.login.login({ user: { username: 'cyan', password: 'fake' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not login kefka with another plugin', async function () { - await loginExternal({ - server, - npmName: 'test-external-auth-two', - authName: 'external-auth-4', - username: 'kefka2', - expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400 - }) - - await loginExternal({ - server, - npmName: 'test-external-auth-two', - authName: 'external-auth-4', - username: 'kefka', - expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should not login an existing user email', async function () { - await server.users.create({ username: 'existing_user', password: 'super_password' }) - - await loginExternal({ - server, - npmName: 'test-external-auth-two', - authName: 'external-auth-6', - username: 'existing_user', - expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should be able to login an existing user username and channel', async function () { - await server.users.create({ username: 'existing_user2' }) - await server.users.create({ username: 'existing_user2-1_channel' }) - - // Test twice to ensure we don't generate a username on every login - for (let i = 0; i < 2; i++) { - const res = await loginExternal({ - server, - npmName: 'test-external-auth-two', - authName: 'external-auth-7', - username: 'existing_user2' - }) - - const token = res.access_token - - const myInfo = await server.users.getMyInfo({ token }) - expect(myInfo.username).to.equal('existing_user2-1') - - expect(myInfo.videoChannels[0].name).to.equal('existing_user2-1_channel-1') - } - }) - - it('Should display the correct configuration', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredExternalAuths - expect(auths).to.have.lengthOf(7) - - const auth2 = auths.find((a) => a.authName === 'external-auth-2') - expect(auth2).to.not.exist - }) - - after(async function () { - await cleanupTests([ server ]) - }) - - it('Should forward the redirectUrl if the plugin returns one', async function () { - const resLogin = await loginExternal({ - server, - npmName: 'test-external-auth-three', - authName: 'external-auth-7', - username: 'cid' - }) - - const { redirectUrl } = await server.login.logout({ token: resLogin.access_token }) - expect(redirectUrl).to.equal('https://example.com/redirectUrl') - }) - - it('Should call the plugin\'s onLogout method with the request', async function () { - const resLogin = await loginExternal({ - server, - npmName: 'test-external-auth-three', - authName: 'external-auth-8', - username: 'cid' - }) - - const { redirectUrl } = await server.login.logout({ token: resLogin.access_token }) - expect(redirectUrl).to.equal('https://example.com/redirectUrl?access_token=' + resLogin.access_token) - }) -}) diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts deleted file mode 100644 index 8382b400f..000000000 --- a/server/tests/plugins/filter-hooks.ts +++ /dev/null @@ -1,909 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - HttpStatusCode, - PeerTubeProblemDocument, - VideoDetails, - VideoImportState, - VideoPlaylist, - VideoPlaylistPrivacy, - VideoPrivacy -} from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeActivityPubGetRequest, - makeGetRequest, - makeRawRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs -} from '@shared/server-commands' -import { FIXTURE_URLS } from '../shared' - -describe('Test plugin filter hooks', function () { - let servers: PeerTubeServer[] - let videoUUID: string - let threadId: number - let videoPlaylistUUID: string - - before(async function () { - this.timeout(120000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await doubleFollow(servers[0], servers[1]) - - await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath() }) - await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath('-filter-translations') }) - { - ({ uuid: videoPlaylistUUID } = await servers[0].playlists.create({ - attributes: { - displayName: 'my super playlist', - privacy: VideoPlaylistPrivacy.PUBLIC, - description: 'my super description', - videoChannelId: servers[0].store.channel.id - } - })) - } - - for (let i = 0; i < 10; i++) { - const video = await servers[0].videos.upload({ attributes: { name: 'default video ' + i } }) - await servers[0].playlists.addElement({ playlistId: videoPlaylistUUID, attributes: { videoId: video.id } }) - } - - const { data } = await servers[0].videos.list() - videoUUID = data[0].uuid - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { enabled: true }, - signup: { enabled: true }, - videoFile: { - update: { - enabled: true - } - }, - import: { - videos: { - http: { enabled: true }, - torrent: { enabled: true } - } - } - } - }) - - // Root subscribes to itself - await servers[0].subscriptions.add({ targetUri: 'root_channel@' + servers[0].host }) - }) - - describe('Videos', function () { - - it('Should run filter:api.videos.list.params', async function () { - const { data } = await servers[0].videos.list({ start: 0, count: 2 }) - - // 2 plugins do +1 to the count parameter - expect(data).to.have.lengthOf(4) - }) - - it('Should run filter:api.videos.list.result', async function () { - const { total } = await servers[0].videos.list({ start: 0, count: 0 }) - - // Plugin do +1 to the total result - expect(total).to.equal(11) - }) - - it('Should run filter:api.video-playlist.videos.list.params', async function () { - const { data } = await servers[0].playlists.listVideos({ - count: 2, - playlistId: videoPlaylistUUID - }) - - // 1 plugin do +1 to the count parameter - expect(data).to.have.lengthOf(3) - }) - - it('Should run filter:api.video-playlist.videos.list.result', async function () { - const { total } = await servers[0].playlists.listVideos({ - count: 0, - playlistId: videoPlaylistUUID - }) - - // Plugin do +1 to the total result - expect(total).to.equal(11) - }) - - it('Should run filter:api.accounts.videos.list.params', async function () { - const { data } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) - - // 1 plugin do +1 to the count parameter - expect(data).to.have.lengthOf(3) - }) - - it('Should run filter:api.accounts.videos.list.result', async function () { - const { total } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) - - // Plugin do +2 to the total result - expect(total).to.equal(12) - }) - - it('Should run filter:api.video-channels.videos.list.params', async function () { - const { data } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) - - // 1 plugin do +3 to the count parameter - expect(data).to.have.lengthOf(5) - }) - - it('Should run filter:api.video-channels.videos.list.result', async function () { - const { total } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) - - // Plugin do +3 to the total result - expect(total).to.equal(13) - }) - - it('Should run filter:api.user.me.videos.list.params', async function () { - const { data } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) - - // 1 plugin do +4 to the count parameter - expect(data).to.have.lengthOf(6) - }) - - it('Should run filter:api.user.me.videos.list.result', async function () { - const { total } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) - - // Plugin do +4 to the total result - expect(total).to.equal(14) - }) - - it('Should run filter:api.user.me.subscription-videos.list.params', async function () { - const { data } = await servers[0].videos.listMySubscriptionVideos({ start: 0, count: 2 }) - - // 1 plugin do +1 to the count parameter - expect(data).to.have.lengthOf(3) - }) - - it('Should run filter:api.user.me.subscription-videos.list.result', async function () { - const { total } = await servers[0].videos.listMySubscriptionVideos({ start: 0, count: 2 }) - - // Plugin do +4 to the total result - expect(total).to.equal(14) - }) - - it('Should run filter:api.video.get.result', async function () { - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.name).to.contain('<3') - }) - }) - - describe('Video/live/import accept', function () { - - it('Should run filter:api.video.upload.accept.result', async function () { - const options = { attributes: { name: 'video with bad word' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 } - await servers[0].videos.upload({ mode: 'legacy', ...options }) - await servers[0].videos.upload({ mode: 'resumable', ...options }) - }) - - it('Should run filter:api.video.update-file.accept.result', async function () { - const res = await servers[0].videos.replaceSourceFile({ - videoId: videoUUID, - fixture: 'video_short1.webm', - completedExpectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - - expect((res as any)?.error).to.equal('no webm') - }) - - it('Should run filter:api.live-video.create.accept.result', async function () { - const attributes = { - name: 'video with bad word', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id - } - - await servers[0].live.create({ fields: attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should run filter:api.video.pre-import-url.accept.result', async function () { - const attributes = { - name: 'normal title', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id, - targetUrl: FIXTURE_URLS.goodVideo + 'bad' - } - await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should run filter:api.video.pre-import-torrent.accept.result', async function () { - const attributes = { - name: 'bad torrent', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id, - torrentfile: 'video-720p.torrent' as any - } - await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - }) - - it('Should run filter:api.video.post-import-url.accept.result', async function () { - this.timeout(60000) - - let videoImportId: number - - { - const attributes = { - name: 'title with bad word', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id, - targetUrl: FIXTURE_URLS.goodVideo - } - const body = await servers[0].imports.importVideo({ attributes }) - videoImportId = body.id - } - - await waitJobs(servers) - - { - const body = await servers[0].imports.getMyVideoImports() - const videoImports = body.data - - const videoImport = videoImports.find(i => i.id === videoImportId) - - expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) - expect(videoImport.state.label).to.equal('Rejected') - } - }) - - it('Should run filter:api.video.post-import-torrent.accept.result', async function () { - this.timeout(60000) - - let videoImportId: number - - { - const attributes = { - name: 'title with bad word', - privacy: VideoPrivacy.PUBLIC, - channelId: servers[0].store.channel.id, - torrentfile: 'video-720p.torrent' as any - } - const body = await servers[0].imports.importVideo({ attributes }) - videoImportId = body.id - } - - await waitJobs(servers) - - { - const { data: videoImports } = await servers[0].imports.getMyVideoImports() - - const videoImport = videoImports.find(i => i.id === videoImportId) - - expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) - expect(videoImport.state.label).to.equal('Rejected') - } - }) - }) - - describe('Video comments accept', function () { - - it('Should run filter:api.video-thread.create.accept.result', async function () { - await servers[0].comments.createThread({ - videoId: videoUUID, - text: 'comment with bad word', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - }) - - it('Should run filter:api.video-comment-reply.create.accept.result', async function () { - const created = await servers[0].comments.createThread({ videoId: videoUUID, text: 'thread' }) - threadId = created.id - - await servers[0].comments.addReply({ - videoId: videoUUID, - toCommentId: threadId, - text: 'comment with bad word', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - await servers[0].comments.addReply({ - videoId: videoUUID, - toCommentId: threadId, - text: 'comment with good word', - expectedStatus: HttpStatusCode.OK_200 - }) - }) - - it('Should run filter:activity-pub.remote-video-comment.create.accept.result on a thread creation', async function () { - this.timeout(30000) - - await servers[1].comments.createThread({ videoId: videoUUID, text: 'comment with bad word' }) - - await waitJobs(servers) - - { - const thread = await servers[0].comments.listThreads({ videoId: videoUUID }) - expect(thread.data).to.have.lengthOf(1) - expect(thread.data[0].text).to.not.include(' bad ') - } - - { - const thread = await servers[1].comments.listThreads({ videoId: videoUUID }) - expect(thread.data).to.have.lengthOf(2) - } - }) - - it('Should run filter:activity-pub.remote-video-comment.create.accept.result on a reply creation', async function () { - this.timeout(30000) - - const { data } = await servers[1].comments.listThreads({ videoId: videoUUID }) - const threadIdServer2 = data.find(t => t.text === 'thread').id - - await servers[1].comments.addReply({ - videoId: videoUUID, - toCommentId: threadIdServer2, - text: 'comment with bad word' - }) - - await waitJobs(servers) - - { - const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId }) - expect(tree.children).to.have.lengthOf(1) - expect(tree.children[0].comment.text).to.not.include(' bad ') - } - - { - const tree = await servers[1].comments.getThread({ videoId: videoUUID, threadId: threadIdServer2 }) - expect(tree.children).to.have.lengthOf(2) - } - }) - }) - - describe('Video comments', function () { - - it('Should run filter:api.video-threads.list.params', async function () { - const { data } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) - - // our plugin do +1 to the count parameter - expect(data).to.have.lengthOf(1) - }) - - it('Should run filter:api.video-threads.list.result', async function () { - const { total } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) - - // Plugin do +1 to the total result - expect(total).to.equal(2) - }) - - it('Should run filter:api.video-thread-comments.list.params') - - it('Should run filter:api.video-thread-comments.list.result', async function () { - const thread = await servers[0].comments.getThread({ videoId: videoUUID, threadId }) - - expect(thread.comment.text.endsWith(' <3')).to.be.true - }) - - it('Should run filter:api.overviews.videos.list.{params,result}', async function () { - await servers[0].overviews.getVideos({ page: 1 }) - - // 3 because we get 3 samples per page - await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.params', 3) - await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.result', 3) - }) - }) - - describe('filter:video.auto-blacklist.result', function () { - - async function checkIsBlacklisted (id: number | string, value: boolean) { - const video = await servers[0].videos.getWithToken({ id }) - expect(video.blacklisted).to.equal(value) - } - - it('Should blacklist on upload', async function () { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video please blacklist me' } }) - await checkIsBlacklisted(uuid, true) - }) - - it('Should blacklist on import', async function () { - this.timeout(15000) - - const attributes = { - name: 'video please blacklist me', - targetUrl: FIXTURE_URLS.goodVideo, - channelId: servers[0].store.channel.id - } - const body = await servers[0].imports.importVideo({ attributes }) - await checkIsBlacklisted(body.video.uuid, true) - }) - - it('Should blacklist on update', async function () { - const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video' } }) - await checkIsBlacklisted(uuid, false) - - await servers[0].videos.update({ id: uuid, attributes: { name: 'please blacklist me' } }) - await checkIsBlacklisted(uuid, true) - }) - - it('Should blacklist on remote upload', async function () { - this.timeout(120000) - - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'remote please blacklist me' } }) - await waitJobs(servers) - - await checkIsBlacklisted(uuid, true) - }) - - it('Should blacklist on remote update', async function () { - this.timeout(120000) - - const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video' } }) - await waitJobs(servers) - - await checkIsBlacklisted(uuid, false) - - await servers[1].videos.update({ id: uuid, attributes: { name: 'please blacklist me' } }) - await waitJobs(servers) - - await checkIsBlacklisted(uuid, true) - }) - }) - - describe('Should run filter:api.user.signup.allowed.result', function () { - - before(async function () { - await servers[0].config.updateExistingSubConfig({ newConfig: { signup: { requiresApproval: false } } }) - }) - - it('Should run on config endpoint', async function () { - const body = await servers[0].config.getConfig() - expect(body.signup.allowed).to.be.true - }) - - it('Should allow a signup', async function () { - await servers[0].registrations.register({ username: 'john1' }) - }) - - it('Should not allow a signup', async function () { - const res = await servers[0].registrations.register({ - username: 'jma 1', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - - expect(res.body.error).to.equal('No jma 1') - }) - }) - - describe('Should run filter:api.user.request-signup.allowed.result', function () { - - before(async function () { - await servers[0].config.updateExistingSubConfig({ newConfig: { signup: { requiresApproval: true } } }) - }) - - it('Should run on config endpoint', async function () { - const body = await servers[0].config.getConfig() - expect(body.signup.allowed).to.be.true - }) - - it('Should allow a signup request', async function () { - await servers[0].registrations.requestRegistration({ username: 'john2', registrationReason: 'tt' }) - }) - - it('Should not allow a signup request', async function () { - const body = await servers[0].registrations.requestRegistration({ - username: 'jma 2', - registrationReason: 'tt', - expectedStatus: HttpStatusCode.FORBIDDEN_403 - }) - - expect((body as unknown as PeerTubeProblemDocument).error).to.equal('No jma 2') - }) - }) - - describe('Download hooks', function () { - const downloadVideos: VideoDetails[] = [] - let downloadVideo2Token: string - - before(async function () { - this.timeout(120000) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - transcoding: { - webVideos: { - enabled: true - }, - hls: { - enabled: true - } - } - } - }) - - const uuids: string[] = [] - - for (const name of [ 'bad torrent', 'bad file', 'bad playlist file' ]) { - const uuid = (await servers[0].videos.quickUpload({ name })).uuid - uuids.push(uuid) - } - - await waitJobs(servers) - - for (const uuid of uuids) { - downloadVideos.push(await servers[0].videos.get({ id: uuid })) - } - - downloadVideo2Token = await servers[0].videoToken.getVideoFileToken({ videoId: downloadVideos[2].uuid }) - }) - - it('Should run filter:api.download.torrent.allowed.result', async function () { - const res = await makeRawRequest({ url: downloadVideos[0].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - expect(res.body.error).to.equal('Liu Bei') - - await makeRawRequest({ url: downloadVideos[1].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: downloadVideos[2].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) - }) - - it('Should run filter:api.download.video.allowed.result', async function () { - { - const refused = downloadVideos[1].files[0].fileDownloadUrl - const allowed = [ - downloadVideos[0].files[0].fileDownloadUrl, - downloadVideos[2].files[0].fileDownloadUrl - ] - - const res = await makeRawRequest({ url: refused, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - expect(res.body.error).to.equal('Cao Cao') - - for (const url of allowed) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - { - const refused = downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl - - const allowed = [ - downloadVideos[2].files[0].fileDownloadUrl, - downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, - downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl - ] - - // Only streaming playlist is refuse - const res = await makeRawRequest({ url: refused, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) - expect(res.body.error).to.equal('Sun Jian') - - // But not we there is a user in res - await makeRawRequest({ url: refused, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 }) - await makeRawRequest({ url: refused, query: { videoFileToken: downloadVideo2Token }, expectedStatus: HttpStatusCode.OK_200 }) - - // Other files work - for (const url of allowed) { - await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) - } - } - }) - }) - - describe('Embed filters', function () { - const embedVideos: VideoDetails[] = [] - const embedPlaylists: VideoPlaylist[] = [] - - before(async function () { - this.timeout(60000) - - await servers[0].config.disableTranscoding() - - for (const name of [ 'bad embed', 'good embed' ]) { - { - const uuid = (await servers[0].videos.quickUpload({ name })).uuid - embedVideos.push(await servers[0].videos.get({ id: uuid })) - } - - { - const attributes = { displayName: name, videoChannelId: servers[0].store.channel.id, privacy: VideoPlaylistPrivacy.PUBLIC } - const { id } = await servers[0].playlists.create({ attributes }) - - const playlist = await servers[0].playlists.get({ playlistId: id }) - embedPlaylists.push(playlist) - } - } - }) - - it('Should run filter:html.embed.video.allowed.result', async function () { - const res = await makeGetRequest({ url: servers[0].url, path: embedVideos[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).to.equal('Lu Bu') - }) - - it('Should run filter:html.embed.video-playlist.allowed.result', async function () { - const res = await makeGetRequest({ url: servers[0].url, path: embedPlaylists[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).to.equal('Diao Chan') - }) - }) - - describe('Client HTML filters', function () { - let videoUUID: string - - before(async function () { - this.timeout(60000) - - const { uuid } = await servers[0].videos.quickUpload({ name: 'html video' }) - videoUUID = uuid - }) - - it('Should run filter:html.client.json-ld.result', async function () { - const res = await makeGetRequest({ url: servers[0].url, path: '/w/' + videoUUID, expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).to.contain('"recordedAt":"http://example.com/recordedAt"') - }) - - it('Should not run filter:html.client.json-ld.result with an account', async function () { - const res = await makeGetRequest({ url: servers[0].url, path: '/a/root', expectedStatus: HttpStatusCode.OK_200 }) - expect(res.text).not.to.contain('"recordedAt":"http://example.com/recordedAt"') - }) - }) - - describe('Search filters', function () { - - before(async function () { - await servers[0].config.updateCustomSubConfig({ - newConfig: { - search: { - searchIndex: { - enabled: true, - isDefaultSearch: false, - disableLocalSearch: false - } - } - } - }) - }) - - it('Should run filter:api.search.videos.local.list.{params,result}', async function () { - await servers[0].search.advancedVideoSearch({ - search: { - search: 'Sun Quan' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.local.list.result', 1) - }) - - it('Should run filter:api.search.videos.index.list.{params,result}', async function () { - await servers[0].search.advancedVideoSearch({ - search: { - search: 'Sun Quan', - searchTarget: 'search-index' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.local.list.result', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.index.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.videos.index.list.result', 1) - }) - - it('Should run filter:api.search.video-channels.local.list.{params,result}', async function () { - await servers[0].search.advancedChannelSearch({ - search: { - search: 'Sun Ce' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.local.list.result', 1) - }) - - it('Should run filter:api.search.video-channels.index.list.{params,result}', async function () { - await servers[0].search.advancedChannelSearch({ - search: { - search: 'Sun Ce', - searchTarget: 'search-index' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.local.list.result', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.index.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-channels.index.list.result', 1) - }) - - it('Should run filter:api.search.video-playlists.local.list.{params,result}', async function () { - await servers[0].search.advancedPlaylistSearch({ - search: { - search: 'Sun Jian' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.local.list.result', 1) - }) - - it('Should run filter:api.search.video-playlists.index.list.{params,result}', async function () { - await servers[0].search.advancedPlaylistSearch({ - search: { - search: 'Sun Jian', - searchTarget: 'search-index' - } - }) - - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.local.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.local.list.result', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.index.list.params', 1) - await servers[0].servers.waitUntilLog('Run hook filter:api.search.video-playlists.index.list.result', 1) - }) - }) - - describe('Upload/import/live attributes filters', function () { - - before(async function () { - await servers[0].config.enableLive({ transcoding: false, allowReplay: false }) - await servers[0].config.enableImports() - await servers[0].config.disableTranscoding() - }) - - it('Should run filter:api.video.upload.video-attribute.result', async function () { - for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) { - const { id } = await servers[0].videos.upload({ attributes: { name: 'video', description: 'upload' }, mode }) - - const video = await servers[0].videos.get({ id }) - expect(video.description).to.equal('upload - filter:api.video.upload.video-attribute.result') - } - }) - - it('Should run filter:api.video.import-url.video-attribute.result', async function () { - const attributes = { - name: 'video', - description: 'import url', - channelId: servers[0].store.channel.id, - targetUrl: FIXTURE_URLS.goodVideo, - privacy: VideoPrivacy.PUBLIC - } - const { video: { id } } = await servers[0].imports.importVideo({ attributes }) - - const video = await servers[0].videos.get({ id }) - expect(video.description).to.equal('import url - filter:api.video.import-url.video-attribute.result') - }) - - it('Should run filter:api.video.import-torrent.video-attribute.result', async function () { - const attributes = { - name: 'video', - description: 'import torrent', - channelId: servers[0].store.channel.id, - magnetUri: FIXTURE_URLS.magnet, - privacy: VideoPrivacy.PUBLIC - } - const { video: { id } } = await servers[0].imports.importVideo({ attributes }) - - const video = await servers[0].videos.get({ id }) - expect(video.description).to.equal('import torrent - filter:api.video.import-torrent.video-attribute.result') - }) - - it('Should run filter:api.video.live.video-attribute.result', async function () { - const fields = { - name: 'live', - description: 'live', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - const { id } = await servers[0].live.create({ fields }) - - const video = await servers[0].videos.get({ id }) - expect(video.description).to.equal('live - filter:api.video.live.video-attribute.result') - }) - }) - - describe('Stats filters', function () { - - it('Should run filter:api.server.stats.get.result', async function () { - const data = await servers[0].stats.get() - - expect((data as any).customStats).to.equal(14) - }) - - }) - - describe('Job queue filters', function () { - let videoUUID: string - - before(async function () { - this.timeout(120_000) - - await servers[0].config.enableMinimumTranscoding() - const { uuid } = await servers[0].videos.quickUpload({ name: 'studio' }) - - const video = await servers[0].videos.get({ id: uuid }) - expect(video.duration).at.least(2) - videoUUID = video.uuid - - await waitJobs(servers) - - await servers[0].config.enableStudio() - }) - - it('Should run filter:job-queue.process.params', async function () { - this.timeout(120_000) - - await servers[0].videoStudio.createEditionTasks({ - videoId: videoUUID, - tasks: [ - { - name: 'add-intro', - options: { - file: 'video_very_short_240p.mp4' - } - } - ] - }) - - await waitJobs(servers) - - await servers[0].servers.waitUntilLog('Run hook filter:job-queue.process.params', 1, false) - - const video = await servers[0].videos.get({ id: videoUUID }) - expect(video.duration).at.most(2) - }) - - it('Should run filter:job-queue.process.result', async function () { - await servers[0].servers.waitUntilLog('Run hook filter:job-queue.process.result', 1, false) - }) - }) - - describe('Transcoding filters', async function () { - - it('Should run filter:transcoding.auto.resolutions-to-transcode.result', async function () { - const { uuid } = await servers[0].videos.quickUpload({ name: 'transcode-filter' }) - - await waitJobs(servers) - - const video = await servers[0].videos.get({ id: uuid }) - expect(video.files).to.have.lengthOf(2) - expect(video.files.find(f => f.resolution.id === 100 as any)).to.exist - }) - }) - - describe('Video channel filters', async function () { - - it('Should run filter:api.video-channels.list.params', async function () { - const { data } = await servers[0].channels.list({ start: 0, count: 0 }) - - // plugin do +1 to the count parameter - expect(data).to.have.lengthOf(1) - }) - - it('Should run filter:api.video-channels.list.result', async function () { - const { total } = await servers[0].channels.list({ start: 0, count: 1 }) - - // plugin do +1 to the total parameter - expect(total).to.equal(4) - }) - - it('Should run filter:api.video-channel.get.result', async function () { - const channel = await servers[0].channels.get({ channelName: 'root_channel' }) - expect(channel.displayName).to.equal('Main root channel <3') - }) - }) - - describe('Activity Pub', function () { - - it('Should run filter:activity-pub.activity.context.build.result', async function () { - const { body } = await makeActivityPubGetRequest(servers[0].url, '/w/' + videoUUID) - expect(body.type).to.equal('Video') - - expect(body['@context'].some(c => { - return typeof c === 'object' && c.recordedAt === 'https://schema.org/recordedAt' - })).to.be.true - }) - - it('Should run filter:activity-pub.video.json-ld.build.result', async function () { - const { body } = await makeActivityPubGetRequest(servers[0].url, '/w/' + videoUUID) - expect(body.name).to.equal('default video 0') - expect(body.videoName).to.equal('default video 0') - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/plugins/html-injection.ts b/server/tests/plugins/html-injection.ts deleted file mode 100644 index fe16bf1e6..000000000 --- a/server/tests/plugins/html-injection.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - makeHTMLRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' - -describe('Test plugins HTML injection', function () { - let server: PeerTubeServer = null - let command: PluginsCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - command = server.plugins - }) - - it('Should not inject global css file in HTML', async function () { - { - const text = await command.getCSS() - expect(text).to.be.empty - } - - for (const path of [ '/', '/videos/embed/1', '/video-playlists/embed/1' ]) { - const res = await makeHTMLRequest(server.url, path) - expect(res.text).to.not.include('link rel="stylesheet" href="/plugins/global.css') - } - }) - - it('Should install a plugin and a theme', async function () { - this.timeout(30000) - - await command.install({ npmName: 'peertube-plugin-hello-world' }) - }) - - it('Should have the correct global css', async function () { - { - const text = await command.getCSS() - expect(text).to.contain('background-color: red') - } - - for (const path of [ '/', '/videos/embed/1', '/video-playlists/embed/1' ]) { - const res = await makeHTMLRequest(server.url, path) - expect(res.text).to.include('link rel="stylesheet" href="/plugins/global.css') - } - }) - - it('Should have an empty global css on uninstall', async function () { - await command.uninstall({ npmName: 'peertube-plugin-hello-world' }) - - { - const text = await command.getCSS() - expect(text).to.be.empty - } - - for (const path of [ '/', '/videos/embed/1', '/video-playlists/embed/1' ]) { - const res = await makeHTMLRequest(server.url, path) - expect(res.text).to.not.include('link rel="stylesheet" href="/plugins/global.css') - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/id-and-pass-auth.ts b/server/tests/plugins/id-and-pass-auth.ts deleted file mode 100644 index 127c29cbc..000000000 --- a/server/tests/plugins/id-and-pass-auth.ts +++ /dev/null @@ -1,242 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { wait } from '@shared/core-utils' -import { HttpStatusCode, UserRole } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test id and pass auth plugins', function () { - let server: PeerTubeServer - - let crashAccessToken: string - let crashRefreshToken: string - - let lagunaAccessToken: string - let lagunaRefreshToken: string - let lagunaId: number - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - for (const suffix of [ 'one', 'two', 'three' ]) { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-id-pass-auth-' + suffix) }) - } - }) - - it('Should display the correct configuration', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredIdAndPassAuths - expect(auths).to.have.lengthOf(8) - - const crashAuth = auths.find(a => a.authName === 'crash-auth') - expect(crashAuth).to.exist - expect(crashAuth.npmName).to.equal('peertube-plugin-test-id-pass-auth-one') - expect(crashAuth.weight).to.equal(50) - }) - - it('Should not login', async function () { - await server.login.login({ user: { username: 'toto', password: 'password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should login Spyro, create the user and use the token', async function () { - const accessToken = await server.login.getAccessToken({ username: 'spyro', password: 'spyro password' }) - - const body = await server.users.getMyInfo({ token: accessToken }) - - expect(body.username).to.equal('spyro') - expect(body.account.displayName).to.equal('Spyro the Dragon') - expect(body.role.id).to.equal(UserRole.USER) - }) - - it('Should login Crash, create the user and use the token', async function () { - { - const body = await server.login.login({ user: { username: 'crash', password: 'crash password' } }) - crashAccessToken = body.access_token - crashRefreshToken = body.refresh_token - } - - { - const body = await server.users.getMyInfo({ token: crashAccessToken }) - - expect(body.username).to.equal('crash') - expect(body.account.displayName).to.equal('Crash Bandicoot') - expect(body.role.id).to.equal(UserRole.MODERATOR) - } - }) - - it('Should login the first Laguna, create the user and use the token', async function () { - { - const body = await server.login.login({ user: { username: 'laguna', password: 'laguna password' } }) - lagunaAccessToken = body.access_token - lagunaRefreshToken = body.refresh_token - } - - { - const body = await server.users.getMyInfo({ token: lagunaAccessToken }) - - expect(body.username).to.equal('laguna') - expect(body.account.displayName).to.equal('Laguna Loire') - expect(body.role.id).to.equal(UserRole.USER) - - lagunaId = body.id - } - }) - - it('Should refresh crash token, but not laguna token', async function () { - { - const resRefresh = await server.login.refreshToken({ refreshToken: crashRefreshToken }) - crashAccessToken = resRefresh.body.access_token - crashRefreshToken = resRefresh.body.refresh_token - - const body = await server.users.getMyInfo({ token: crashAccessToken }) - expect(body.username).to.equal('crash') - } - - { - await server.login.refreshToken({ refreshToken: lagunaRefreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - } - }) - - it('Should update Crash profile', async function () { - await server.users.updateMe({ - token: crashAccessToken, - displayName: 'Beautiful Crash', - description: 'Mutant eastern barred bandicoot' - }) - - const body = await server.users.getMyInfo({ token: crashAccessToken }) - - expect(body.account.displayName).to.equal('Beautiful Crash') - expect(body.account.description).to.equal('Mutant eastern barred bandicoot') - }) - - it('Should logout Crash', async function () { - await server.login.logout({ token: crashAccessToken }) - }) - - it('Should have logged out Crash', async function () { - await server.servers.waitUntilLog('On logout for auth 1 - 2') - - await server.users.getMyInfo({ token: crashAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should login Crash and keep the old existing profile', async function () { - crashAccessToken = await server.login.getAccessToken({ username: 'crash', password: 'crash password' }) - - const body = await server.users.getMyInfo({ token: crashAccessToken }) - - expect(body.username).to.equal('crash') - expect(body.account.displayName).to.equal('Beautiful Crash') - expect(body.account.description).to.equal('Mutant eastern barred bandicoot') - expect(body.role.id).to.equal(UserRole.MODERATOR) - }) - - it('Should login Laguna and update the profile', async function () { - { - await server.users.update({ userId: lagunaId, videoQuota: 43000, videoQuotaDaily: 43100 }) - await server.users.updateMe({ token: lagunaAccessToken, displayName: 'laguna updated' }) - - const body = await server.users.getMyInfo({ token: lagunaAccessToken }) - expect(body.username).to.equal('laguna') - expect(body.account.displayName).to.equal('laguna updated') - expect(body.videoQuota).to.equal(43000) - expect(body.videoQuotaDaily).to.equal(43100) - } - - { - const body = await server.login.login({ user: { username: 'laguna', password: 'laguna password' } }) - lagunaAccessToken = body.access_token - lagunaRefreshToken = body.refresh_token - } - - { - const body = await server.users.getMyInfo({ token: lagunaAccessToken }) - expect(body.username).to.equal('laguna') - expect(body.account.displayName).to.equal('Laguna Loire') - expect(body.videoQuota).to.equal(42000) - expect(body.videoQuotaDaily).to.equal(43100) - } - }) - - it('Should reject token of laguna by the plugin hook', async function () { - await wait(5000) - - await server.users.getMyInfo({ token: lagunaAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) - - it('Should reject an invalid username, email, role or display name', async function () { - const command = server.login - - await command.login({ user: { username: 'ward', password: 'ward password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.servers.waitUntilLog('valid username') - - await command.login({ user: { username: 'kiros', password: 'kiros password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.servers.waitUntilLog('valid displayName') - - await command.login({ user: { username: 'raine', password: 'raine password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.servers.waitUntilLog('valid role') - - await command.login({ user: { username: 'ellone', password: 'elonne password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await server.servers.waitUntilLog('valid email') - }) - - it('Should unregister spyro-auth and do not login existing Spyro', async function () { - await server.plugins.updateSettings({ - npmName: 'peertube-plugin-test-id-pass-auth-one', - settings: { disableSpyro: true } - }) - - const command = server.login - await command.login({ user: { username: 'spyro', password: 'spyro password' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await command.login({ user: { username: 'spyro', password: 'fake' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should have disabled this auth', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredIdAndPassAuths - expect(auths).to.have.lengthOf(7) - - const spyroAuth = auths.find(a => a.authName === 'spyro-auth') - expect(spyroAuth).to.not.exist - }) - - it('Should uninstall the plugin one and do not login existing Crash', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-id-pass-auth-one' }) - - await server.login.login({ - user: { username: 'crash', password: 'crash password' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - }) - - it('Should display the correct configuration', async function () { - const config = await server.config.getConfig() - - const auths = config.plugin.registeredIdAndPassAuths - expect(auths).to.have.lengthOf(6) - - const crashAuth = auths.find(a => a.authName === 'crash-auth') - expect(crashAuth).to.not.exist - }) - - it('Should display plugin auth information in users list', async function () { - const { data } = await server.users.list() - - const root = data.find(u => u.username === 'root') - const crash = data.find(u => u.username === 'crash') - const laguna = data.find(u => u.username === 'laguna') - - expect(root.pluginAuth).to.be.null - expect(crash.pluginAuth).to.equal('peertube-plugin-test-id-pass-auth-one') - expect(laguna.pluginAuth).to.equal('peertube-plugin-test-id-pass-auth-two') - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/index.ts b/server/tests/plugins/index.ts deleted file mode 100644 index 210af7236..000000000 --- a/server/tests/plugins/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import './action-hooks' -import './external-auth' -import './filter-hooks' -import './html-injection' -import './id-and-pass-auth' -import './plugin-helpers' -import './plugin-router' -import './plugin-storage' -import './plugin-transcoding' -import './plugin-unloading' -import './plugin-websocket' -import './translations' -import './video-constants' diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts deleted file mode 100644 index f5a0cbe85..000000000 --- a/server/tests/plugins/plugin-helpers.ts +++ /dev/null @@ -1,383 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists } from 'fs-extra' -import { HttpStatusCode, ThumbnailType } from '@shared/models' -import { - cleanupTests, - createMultipleServers, - doubleFollow, - makeGetRequest, - makePostBodyRequest, - makeRawRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers, - waitJobs -} from '@shared/server-commands' -import { checkVideoFilesWereRemoved } from '../shared' - -function postCommand (server: PeerTubeServer, command: string, bodyArg?: object) { - const body = { command } - if (bodyArg) Object.assign(body, bodyArg) - - return makePostBodyRequest({ - url: server.url, - path: '/plugins/test-four/router/commander', - fields: body, - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) -} - -describe('Test plugin helpers', function () { - let servers: PeerTubeServer[] - - before(async function () { - this.timeout(60000) - - servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - - await doubleFollow(servers[0], servers[1]) - - await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath('-four') }) - }) - - describe('Logger', function () { - - it('Should have logged things', async function () { - await servers[0].servers.waitUntilLog(servers[0].host + ' peertube-plugin-test-four', 1, false) - await servers[0].servers.waitUntilLog('Hello world from plugin four', 1) - }) - }) - - describe('Database', function () { - - it('Should have made a query', async function () { - await servers[0].servers.waitUntilLog(`root email is admin${servers[0].internalServerNumber}@example.com`) - }) - }) - - describe('Config', function () { - - it('Should have the correct webserver url', async function () { - await servers[0].servers.waitUntilLog(`server url is ${servers[0].url}`) - }) - - it('Should have the correct listening config', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/server-listening-config', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.config).to.exist - expect(res.body.config.hostname).to.equal('::') - expect(res.body.config.port).to.equal(servers[0].port) - }) - - it('Should have the correct config', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/server-config', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.serverConfig).to.exist - expect(res.body.serverConfig.instance.name).to.equal('PeerTube') - }) - }) - - describe('Server', function () { - - it('Should get the server actor', async function () { - await servers[0].servers.waitUntilLog('server actor name is peertube') - }) - }) - - describe('Socket', function () { - - it('Should sendNotification without any exceptions', async () => { - const user = await servers[0].users.create({ username: 'notis_redding', password: 'secret1234?' }) - await makePostBodyRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/send-notification', - fields: { - userId: user.id - }, - expectedStatus: HttpStatusCode.CREATED_201 - }) - }) - - it('Should sendVideoLiveNewState without any exceptions', async () => { - const res = await servers[0].videos.quickUpload({ name: 'video server 1' }) - - await makePostBodyRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/send-video-live-new-state/' + res.uuid, - expectedStatus: HttpStatusCode.CREATED_201 - }) - - await servers[0].videos.remove({ id: res.uuid }) - }) - }) - - describe('Plugin', function () { - - it('Should get the base static route', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/static-route', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.staticRoute).to.equal('/plugins/test-four/0.0.1/static/') - }) - - it('Should get the base static route', async function () { - const baseRouter = '/plugins/test-four/0.0.1/router/' - - const res = await makeGetRequest({ - url: servers[0].url, - path: baseRouter + 'router-route', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.routerRoute).to.equal(baseRouter) - }) - }) - - describe('User', function () { - let rootId: number - - it('Should not get a user if not authenticated', async function () { - await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/user', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should get a user if authenticated', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - token: servers[0].accessToken, - path: '/plugins/test-four/router/user', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.username).to.equal('root') - expect(res.body.displayName).to.equal('root') - expect(res.body.isAdmin).to.be.true - expect(res.body.isModerator).to.be.false - expect(res.body.isUser).to.be.false - - rootId = res.body.id - }) - - it('Should load a user by id', async function () { - { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/user/' + rootId, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.username).to.equal('root') - } - - { - await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/user/42', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - } - }) - }) - - describe('Moderation', function () { - let videoUUIDServer1: string - - before(async function () { - this.timeout(60000) - - { - const res = await servers[0].videos.quickUpload({ name: 'video server 1' }) - videoUUIDServer1 = res.uuid - } - - { - await servers[1].videos.quickUpload({ name: 'video server 2' }) - } - - await waitJobs(servers) - - const { data } = await servers[0].videos.list() - - expect(data).to.have.lengthOf(2) - }) - - it('Should mute server 2', async function () { - await postCommand(servers[0], 'blockServer', { hostToBlock: servers[1].host }) - - const { data } = await servers[0].videos.list() - - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('video server 1') - }) - - it('Should unmute server 2', async function () { - await postCommand(servers[0], 'unblockServer', { hostToUnblock: servers[1].host }) - - const { data } = await servers[0].videos.list() - - expect(data).to.have.lengthOf(2) - }) - - it('Should mute account of server 2', async function () { - await postCommand(servers[0], 'blockAccount', { handleToBlock: `root@${servers[1].host}` }) - - const { data } = await servers[0].videos.list() - - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('video server 1') - }) - - it('Should unmute account of server 2', async function () { - await postCommand(servers[0], 'unblockAccount', { handleToUnblock: `root@${servers[1].host}` }) - - const { data } = await servers[0].videos.list() - - expect(data).to.have.lengthOf(2) - }) - - it('Should blacklist video', async function () { - await postCommand(servers[0], 'blacklist', { videoUUID: videoUUIDServer1, unfederate: true }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - expect(data).to.have.lengthOf(1) - expect(data[0].name).to.equal('video server 2') - } - }) - - it('Should unblacklist video', async function () { - await postCommand(servers[0], 'unblacklist', { videoUUID: videoUUIDServer1 }) - - await waitJobs(servers) - - for (const server of servers) { - const { data } = await server.videos.list() - - expect(data).to.have.lengthOf(2) - } - }) - }) - - describe('Videos', function () { - let videoUUID: string - let videoPath: string - - before(async function () { - this.timeout(240000) - - await servers[0].config.enableTranscoding() - - const res = await servers[0].videos.quickUpload({ name: 'video1' }) - videoUUID = res.uuid - - await waitJobs(servers) - }) - - it('Should get video files', async function () { - const { body } = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/video-files/' + videoUUID, - expectedStatus: HttpStatusCode.OK_200 - }) - - // Video files check - { - expect(body.webVideo.videoFiles).to.be.an('array') - expect(body.hls.videoFiles).to.be.an('array') - - for (const resolution of [ 144, 240, 360, 480, 720 ]) { - for (const files of [ body.webVideo.videoFiles, body.hls.videoFiles ]) { - const file = files.find(f => f.resolution === resolution) - expect(file).to.exist - - expect(file.size).to.be.a('number') - expect(file.fps).to.equal(25) - - expect(await pathExists(file.path)).to.be.true - await makeRawRequest({ url: file.url, expectedStatus: HttpStatusCode.OK_200 }) - } - } - - videoPath = body.webVideo.videoFiles[0].path - } - - // Thumbnails check - { - expect(body.thumbnails).to.be.an('array') - - const miniature = body.thumbnails.find(t => t.type === ThumbnailType.MINIATURE) - expect(miniature).to.exist - expect(await pathExists(miniature.path)).to.be.true - await makeRawRequest({ url: miniature.url, expectedStatus: HttpStatusCode.OK_200 }) - - const preview = body.thumbnails.find(t => t.type === ThumbnailType.PREVIEW) - expect(preview).to.exist - expect(await pathExists(preview.path)).to.be.true - await makeRawRequest({ url: preview.url, expectedStatus: HttpStatusCode.OK_200 }) - } - }) - - it('Should probe a file', async function () { - const { body } = await makeGetRequest({ - url: servers[0].url, - path: '/plugins/test-four/router/ffprobe', - query: { - path: videoPath - }, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(body.streams).to.be.an('array') - expect(body.streams).to.have.lengthOf(2) - }) - - it('Should remove a video after a view', async function () { - this.timeout(40000) - - // Should not throw -> video exists - const video = await servers[0].videos.get({ id: videoUUID }) - // Should delete the video - await servers[0].views.simulateView({ id: videoUUID }) - - await servers[0].servers.waitUntilLog('Video deleted by plugin four.') - - try { - // Should throw because the video should have been deleted - await servers[0].videos.get({ id: videoUUID }) - throw new Error('Video exists') - } catch (err) { - if (err.message.includes('exists')) throw err - } - - await checkVideoFilesWereRemoved({ server: servers[0], video }) - }) - - it('Should have fetched the video by URL', async function () { - await servers[0].servers.waitUntilLog(`video from DB uuid is ${videoUUID}`) - }) - }) - - after(async function () { - await cleanupTests(servers) - }) -}) diff --git a/server/tests/plugins/plugin-router.ts b/server/tests/plugins/plugin-router.ts deleted file mode 100644 index 40b15eb79..000000000 --- a/server/tests/plugins/plugin-router.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - makePostBodyRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Test plugin helpers', function () { - let server: PeerTubeServer - const basePaths = [ - '/plugins/test-five/router/', - '/plugins/test-five/0.0.1/router/' - ] - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-five') }) - }) - - it('Should answer "pong"', async function () { - for (const path of basePaths) { - const res = await makeGetRequest({ - url: server.url, - path: path + 'ping', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.message).to.equal('pong') - } - }) - - it('Should check if authenticated', async function () { - for (const path of basePaths) { - const res = await makeGetRequest({ - url: server.url, - path: path + 'is-authenticated', - token: server.accessToken, - expectedStatus: 200 - }) - - expect(res.body.isAuthenticated).to.equal(true) - - const secRes = await makeGetRequest({ - url: server.url, - path: path + 'is-authenticated', - expectedStatus: 200 - }) - - expect(secRes.body.isAuthenticated).to.equal(false) - } - }) - - it('Should mirror post body', async function () { - const body = { - hello: 'world', - riri: 'fifi', - loulou: 'picsou' - } - - for (const path of basePaths) { - const res = await makePostBodyRequest({ - url: server.url, - path: path + 'form/post/mirror', - fields: body, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body).to.deep.equal(body) - } - }) - - it('Should remove the plugin and remove the routes', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-five' }) - - for (const path of basePaths) { - await makeGetRequest({ - url: server.url, - path: path + 'ping', - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - - await makePostBodyRequest({ - url: server.url, - path: path + 'ping', - fields: {}, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/plugin-storage.ts b/server/tests/plugins/plugin-storage.ts deleted file mode 100644 index 112652a1f..000000000 --- a/server/tests/plugins/plugin-storage.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir, readFile } from 'fs-extra' -import { join } from 'path' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Test plugin storage', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-six') }) - }) - - describe('DB storage', function () { - it('Should correctly store a subkey', async function () { - await server.servers.waitUntilLog('superkey stored value is toto') - }) - - it('Should correctly retrieve an array as array from the storage.', async function () { - await server.servers.waitUntilLog('storedArrayKey isArray is true') - await server.servers.waitUntilLog('storedArrayKey stored value is toto, toto2') - }) - }) - - describe('Disk storage', function () { - let dataPath: string - let pluginDataPath: string - - async function getFileContent () { - const files = await readdir(pluginDataPath) - expect(files).to.have.lengthOf(1) - - return readFile(join(pluginDataPath, files[0]), 'utf8') - } - - before(function () { - dataPath = server.servers.buildDirectory('plugins/data') - pluginDataPath = join(dataPath, 'peertube-plugin-test-six') - }) - - it('Should have created the directory on install', async function () { - const dataPath = server.servers.buildDirectory('plugins/data') - const pluginDataPath = join(dataPath, 'peertube-plugin-test-six') - - expect(await pathExists(dataPath)).to.be.true - expect(await pathExists(pluginDataPath)).to.be.true - expect(await readdir(pluginDataPath)).to.have.lengthOf(0) - }) - - it('Should have created a file', async function () { - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path: '/plugins/test-six/router/create-file', - expectedStatus: HttpStatusCode.OK_200 - }) - - const content = await getFileContent() - expect(content).to.equal('Prince Ali') - }) - - it('Should still have the file after an uninstallation', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-six' }) - - const content = await getFileContent() - expect(content).to.equal('Prince Ali') - }) - - it('Should still have the file after the reinstallation', async function () { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-six') }) - - const content = await getFileContent() - expect(content).to.equal('Prince Ali') - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/plugin-transcoding.ts b/server/tests/plugins/plugin-transcoding.ts deleted file mode 100644 index 21f82fbac..000000000 --- a/server/tests/plugins/plugin-transcoding.ts +++ /dev/null @@ -1,279 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { getAudioStream, getVideoStream, getVideoStreamFPS } from '@shared/ffmpeg' -import { VideoPrivacy } from '@shared/models' -import { - cleanupTests, - createSingleServer, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers, - setDefaultVideoChannel, - testFfmpegStreamError, - waitJobs -} from '@shared/server-commands' - -async function createLiveWrapper (server: PeerTubeServer) { - const liveAttributes = { - name: 'live video', - channelId: server.store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - - const { uuid } = await server.live.create({ fields: liveAttributes }) - - return uuid -} - -function updateConf (server: PeerTubeServer, vodProfile: string, liveProfile: string) { - return server.config.updateCustomSubConfig({ - newConfig: { - transcoding: { - enabled: true, - profile: vodProfile, - hls: { - enabled: true - }, - webVideos: { - enabled: true - }, - resolutions: { - '240p': true, - '360p': false, - '480p': false, - '720p': true - } - }, - live: { - transcoding: { - profile: liveProfile, - enabled: true, - resolutions: { - '240p': true, - '360p': false, - '480p': false, - '720p': true - } - } - } - } - }) -} - -describe('Test transcoding plugins', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(60000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - await setDefaultVideoChannel([ server ]) - - await updateConf(server, 'default', 'default') - }) - - describe('When using a plugin adding profiles to existing encoders', function () { - - async function checkVideoFPS (uuid: string, type: 'above' | 'below', fps: number) { - const video = await server.videos.get({ id: uuid }) - const files = video.files.concat(...video.streamingPlaylists.map(p => p.files)) - - for (const file of files) { - if (type === 'above') { - expect(file.fps).to.be.above(fps) - } else { - expect(file.fps).to.be.below(fps) - } - } - } - - async function checkLiveFPS (uuid: string, type: 'above' | 'below', fps: number) { - const playlistUrl = `${server.url}/static/streaming-playlists/hls/${uuid}/0.m3u8` - const videoFPS = await getVideoStreamFPS(playlistUrl) - - if (type === 'above') { - expect(videoFPS).to.be.above(fps) - } else { - expect(videoFPS).to.be.below(fps) - } - } - - before(async function () { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-transcoding-one') }) - }) - - it('Should have the appropriate available profiles', async function () { - const config = await server.config.getConfig() - - expect(config.transcoding.availableProfiles).to.have.members([ 'default', 'low-vod', 'input-options-vod', 'bad-scale-vod' ]) - expect(config.live.transcoding.availableProfiles).to.have.members([ 'default', 'high-live', 'input-options-live', 'bad-scale-live' ]) - }) - - describe('VOD', function () { - - it('Should not use the plugin profile if not chosen by the admin', async function () { - this.timeout(240000) - - const videoUUID = (await server.videos.quickUpload({ name: 'video' })).uuid - await waitJobs([ server ]) - - await checkVideoFPS(videoUUID, 'above', 20) - }) - - it('Should use the vod profile', async function () { - this.timeout(240000) - - await updateConf(server, 'low-vod', 'default') - - const videoUUID = (await server.videos.quickUpload({ name: 'video' })).uuid - await waitJobs([ server ]) - - await checkVideoFPS(videoUUID, 'below', 12) - }) - - it('Should apply input options in vod profile', async function () { - this.timeout(240000) - - await updateConf(server, 'input-options-vod', 'default') - - const videoUUID = (await server.videos.quickUpload({ name: 'video' })).uuid - await waitJobs([ server ]) - - await checkVideoFPS(videoUUID, 'below', 6) - }) - - it('Should apply the scale filter in vod profile', async function () { - this.timeout(240000) - - await updateConf(server, 'bad-scale-vod', 'default') - - const videoUUID = (await server.videos.quickUpload({ name: 'video' })).uuid - await waitJobs([ server ]) - - // Transcoding failed - const video = await server.videos.get({ id: videoUUID }) - expect(video.files).to.have.lengthOf(1) - expect(video.streamingPlaylists).to.have.lengthOf(0) - }) - }) - - describe('Live', function () { - - it('Should not use the plugin profile if not chosen by the admin', async function () { - this.timeout(240000) - - const liveVideoId = await createLiveWrapper(server) - - await server.live.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_very_short_240p.mp4' }) - await server.live.waitUntilPublished({ videoId: liveVideoId }) - await waitJobs([ server ]) - - await checkLiveFPS(liveVideoId, 'above', 20) - }) - - it('Should use the live profile', async function () { - this.timeout(240000) - - await updateConf(server, 'low-vod', 'high-live') - - const liveVideoId = await createLiveWrapper(server) - - await server.live.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_very_short_240p.mp4' }) - await server.live.waitUntilPublished({ videoId: liveVideoId }) - await waitJobs([ server ]) - - await checkLiveFPS(liveVideoId, 'above', 45) - }) - - it('Should apply the input options on live profile', async function () { - this.timeout(240000) - - await updateConf(server, 'low-vod', 'input-options-live') - - const liveVideoId = await createLiveWrapper(server) - - await server.live.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_very_short_240p.mp4' }) - await server.live.waitUntilPublished({ videoId: liveVideoId }) - await waitJobs([ server ]) - - await checkLiveFPS(liveVideoId, 'above', 45) - }) - - it('Should apply the scale filter name on live profile', async function () { - this.timeout(240000) - - await updateConf(server, 'low-vod', 'bad-scale-live') - - const liveVideoId = await createLiveWrapper(server) - - const command = await server.live.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_very_short_240p.mp4' }) - await testFfmpegStreamError(command, true) - }) - - it('Should default to the default profile if the specified profile does not exist', async function () { - this.timeout(240000) - - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-transcoding-one' }) - - const config = await server.config.getConfig() - - expect(config.transcoding.availableProfiles).to.deep.equal([ 'default' ]) - expect(config.live.transcoding.availableProfiles).to.deep.equal([ 'default' ]) - - const videoUUID = (await server.videos.quickUpload({ name: 'video', fixture: 'video_very_short_240p.mp4' })).uuid - await waitJobs([ server ]) - - await checkVideoFPS(videoUUID, 'above', 20) - }) - }) - - }) - - describe('When using a plugin adding new encoders', function () { - - before(async function () { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-transcoding-two') }) - - await updateConf(server, 'test-vod-profile', 'test-live-profile') - }) - - it('Should use the new vod encoders', async function () { - this.timeout(240000) - - const videoUUID = (await server.videos.quickUpload({ name: 'video', fixture: 'video_very_short_240p.mp4' })).uuid - await waitJobs([ server ]) - - const video = await server.videos.get({ id: videoUUID }) - - const path = server.servers.buildWebVideoFilePath(video.files[0].fileUrl) - const audioProbe = await getAudioStream(path) - expect(audioProbe.audioStream.codec_name).to.equal('opus') - - const videoProbe = await getVideoStream(path) - expect(videoProbe.codec_name).to.equal('vp9') - }) - - it('Should use the new live encoders', async function () { - this.timeout(240000) - - const liveVideoId = await createLiveWrapper(server) - - await server.live.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' }) - await server.live.waitUntilPublished({ videoId: liveVideoId }) - await waitJobs([ server ]) - - const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8` - const audioProbe = await getAudioStream(playlistUrl) - expect(audioProbe.audioStream.codec_name).to.equal('opus') - - const videoProbe = await getVideoStream(playlistUrl) - expect(videoProbe.codec_name).to.equal('h264') - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/plugin-unloading.ts b/server/tests/plugins/plugin-unloading.ts deleted file mode 100644 index 5aca1a0c0..000000000 --- a/server/tests/plugins/plugin-unloading.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' -import { HttpStatusCode } from '@shared/models' - -describe('Test plugins module unloading', function () { - let server: PeerTubeServer = null - const requestPath = '/plugins/test-unloading/router/get' - let value: string = null - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-unloading') }) - }) - - it('Should return a numeric value', async function () { - const res = await makeGetRequest({ - url: server.url, - path: requestPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.message).to.match(/^\d+$/) - value = res.body.message - }) - - it('Should return the same value the second time', async function () { - const res = await makeGetRequest({ - url: server.url, - path: requestPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.message).to.be.equal(value) - }) - - it('Should uninstall the plugin and free the route', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-unloading' }) - - await makeGetRequest({ - url: server.url, - path: requestPath, - expectedStatus: HttpStatusCode.NOT_FOUND_404 - }) - }) - - it('Should return a different numeric value', async function () { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-unloading') }) - - const res = await makeGetRequest({ - url: server.url, - path: requestPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.body.message).to.match(/^\d+$/) - expect(res.body.message).to.be.not.equal(value) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/plugin-websocket.ts b/server/tests/plugins/plugin-websocket.ts deleted file mode 100644 index adaa28b1d..000000000 --- a/server/tests/plugins/plugin-websocket.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import WebSocket from 'ws' -import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' - -function buildWebSocket (server: PeerTubeServer, path: string) { - return new WebSocket('ws://' + server.host + path) -} - -function expectErrorOrTimeout (server: PeerTubeServer, path: string, expectedTimeout: number) { - return new Promise((res, rej) => { - const ws = buildWebSocket(server, path) - ws.on('error', () => res()) - - const timeout = setTimeout(() => res(), expectedTimeout) - - ws.on('open', () => { - clearTimeout(timeout) - - return rej(new Error('Connect did not timeout')) - }) - }) -} - -describe('Test plugin websocket', function () { - let server: PeerTubeServer - const basePaths = [ - '/plugins/test-websocket/ws/', - '/plugins/test-websocket/0.0.1/ws/' - ] - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-websocket') }) - }) - - it('Should not connect to the websocket without the appropriate path', async function () { - const paths = [ - '/plugins/unknown/ws/', - '/plugins/unknown/0.0.1/ws/' - ] - - for (const path of paths) { - await expectErrorOrTimeout(server, path, 1000) - } - }) - - it('Should not connect to the websocket without the appropriate sub path', async function () { - for (const path of basePaths) { - await expectErrorOrTimeout(server, path + '/unknown', 1000) - } - }) - - it('Should connect to the websocket and receive pong', function (done) { - const ws = buildWebSocket(server, basePaths[0]) - - ws.on('open', () => ws.send('ping')) - ws.on('message', data => { - if (data.toString() === 'pong') return done() - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts deleted file mode 100644 index 67e4683f8..000000000 --- a/server/tests/plugins/translations.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' - -describe('Test plugin translations', function () { - let server: PeerTubeServer - let command: PluginsCommand - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - command = server.plugins - - await command.install({ path: PluginsCommand.getPluginTestPath() }) - await command.install({ path: PluginsCommand.getPluginTestPath('-filter-translations') }) - }) - - it('Should not have translations for locale pt', async function () { - const body = await command.getTranslations({ locale: 'pt' }) - - expect(body).to.deep.equal({}) - }) - - it('Should have translations for locale fr', async function () { - const body = await command.getTranslations({ locale: 'fr-FR' }) - - expect(body).to.deep.equal({ - 'peertube-plugin-test': { - Hi: 'Coucou' - }, - 'peertube-plugin-test-filter-translations': { - 'Hello world': 'Bonjour le monde' - } - }) - }) - - it('Should have translations of locale it', async function () { - const body = await command.getTranslations({ locale: 'it-IT' }) - - expect(body).to.deep.equal({ - 'peertube-plugin-test-filter-translations': { - 'Hello world': 'Ciao, mondo!' - } - }) - }) - - it('Should remove the plugin and remove the locales', async function () { - await command.uninstall({ npmName: 'peertube-plugin-test-filter-translations' }) - - { - const body = await command.getTranslations({ locale: 'fr-FR' }) - - expect(body).to.deep.equal({ - 'peertube-plugin-test': { - Hi: 'Coucou' - } - }) - } - - { - const body = await command.getTranslations({ locale: 'it-IT' }) - - expect(body).to.deep.equal({}) - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts deleted file mode 100644 index c388f02d1..000000000 --- a/server/tests/plugins/video-constants.ts +++ /dev/null @@ -1,180 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { - cleanupTests, - createSingleServer, - makeGetRequest, - PeerTubeServer, - PluginsCommand, - setAccessTokensToServers -} from '@shared/server-commands' -import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' - -describe('Test plugin altering video constants', function () { - let server: PeerTubeServer - - before(async function () { - this.timeout(30000) - - server = await createSingleServer(1) - await setAccessTokensToServers([ server ]) - - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-video-constants') }) - }) - - it('Should have updated languages', async function () { - const languages = await server.videos.getLanguages() - - expect(languages['en']).to.not.exist - expect(languages['fr']).to.not.exist - - expect(languages['al_bhed']).to.equal('Al Bhed') - expect(languages['al_bhed2']).to.equal('Al Bhed 2') - expect(languages['al_bhed3']).to.not.exist - }) - - it('Should have updated categories', async function () { - const categories = await server.videos.getCategories() - - expect(categories[1]).to.not.exist - expect(categories[2]).to.not.exist - - expect(categories[42]).to.equal('Best category') - expect(categories[43]).to.equal('High best category') - }) - - it('Should have updated licences', async function () { - const licences = await server.videos.getLicences() - - expect(licences[1]).to.not.exist - expect(licences[7]).to.not.exist - - expect(licences[42]).to.equal('Best licence') - expect(licences[43]).to.equal('High best licence') - }) - - it('Should have updated video privacies', async function () { - const privacies = await server.videos.getPrivacies() - - expect(privacies[1]).to.exist - expect(privacies[2]).to.not.exist - expect(privacies[3]).to.exist - expect(privacies[4]).to.exist - }) - - it('Should have updated playlist privacies', async function () { - const playlistPrivacies = await server.playlists.getPrivacies() - - expect(playlistPrivacies[1]).to.exist - expect(playlistPrivacies[2]).to.exist - expect(playlistPrivacies[3]).to.not.exist - }) - - it('Should not be able to create a video with this privacy', async function () { - const attributes = { name: 'video', privacy: 2 } - await server.videos.upload({ attributes, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should not be able to create a video with this privacy', async function () { - const attributes = { displayName: 'video playlist', privacy: VideoPlaylistPrivacy.PRIVATE } - await server.playlists.create({ attributes, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) - - it('Should be able to upload a video with these values', async function () { - const attributes = { name: 'video', category: 42, licence: 42, language: 'al_bhed2' } - const { uuid } = await server.videos.upload({ attributes }) - - const video = await server.videos.get({ id: uuid }) - expect(video.language.label).to.equal('Al Bhed 2') - expect(video.licence.label).to.equal('Best licence') - expect(video.category.label).to.equal('Best category') - }) - - it('Should uninstall the plugin and reset languages, categories, licences and privacies', async function () { - await server.plugins.uninstall({ npmName: 'peertube-plugin-test-video-constants' }) - - { - const languages = await server.videos.getLanguages() - - expect(languages['en']).to.equal('English') - expect(languages['fr']).to.equal('French') - - expect(languages['al_bhed']).to.not.exist - expect(languages['al_bhed2']).to.not.exist - expect(languages['al_bhed3']).to.not.exist - } - - { - const categories = await server.videos.getCategories() - - expect(categories[1]).to.equal('Music') - expect(categories[2]).to.equal('Films') - - expect(categories[42]).to.not.exist - expect(categories[43]).to.not.exist - } - - { - const licences = await server.videos.getLicences() - - expect(licences[1]).to.equal('Attribution') - expect(licences[7]).to.equal('Public Domain Dedication') - - expect(licences[42]).to.not.exist - expect(licences[43]).to.not.exist - } - - { - const privacies = await server.videos.getPrivacies() - - expect(privacies[1]).to.exist - expect(privacies[2]).to.exist - expect(privacies[3]).to.exist - expect(privacies[4]).to.exist - } - - { - const playlistPrivacies = await server.playlists.getPrivacies() - - expect(playlistPrivacies[1]).to.exist - expect(playlistPrivacies[2]).to.exist - expect(playlistPrivacies[3]).to.exist - } - }) - - it('Should be able to reset categories', async function () { - await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-video-constants') }) - - { - const categories = await server.videos.getCategories() - - expect(categories[1]).to.not.exist - expect(categories[2]).to.not.exist - - expect(categories[42]).to.exist - expect(categories[43]).to.exist - } - - await makeGetRequest({ - url: server.url, - token: server.accessToken, - path: '/plugins/test-video-constants/router/reset-categories', - expectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - - { - const categories = await server.videos.getCategories() - - expect(categories[1]).to.exist - expect(categories[2]).to.exist - - expect(categories[42]).to.not.exist - expect(categories[43]).to.not.exist - } - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/shared/actors.ts b/server/tests/shared/actors.ts deleted file mode 100644 index 41fd72e89..000000000 --- a/server/tests/shared/actors.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { Account, VideoChannel } from '@shared/models' -import { PeerTubeServer } from '@shared/server-commands' - -async function expectChannelsFollows (options: { - server: PeerTubeServer - handle: string - followers: number - following: number -}) { - const { server } = options - const { data } = await server.channels.list() - - return expectActorFollow({ ...options, data }) -} - -async function expectAccountFollows (options: { - server: PeerTubeServer - handle: string - followers: number - following: number -}) { - const { server } = options - const { data } = await server.accounts.list() - - return expectActorFollow({ ...options, data }) -} - -async function checkActorFilesWereRemoved (filename: string, server: PeerTubeServer) { - for (const directory of [ 'avatars' ]) { - const directoryPath = server.getDirectoryPath(directory) - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - for (const file of files) { - expect(file).to.not.contain(filename) - } - } -} - -export { - expectAccountFollows, - expectChannelsFollows, - checkActorFilesWereRemoved -} - -// --------------------------------------------------------------------------- - -function expectActorFollow (options: { - server: PeerTubeServer - data: (Account | VideoChannel)[] - handle: string - followers: number - following: number -}) { - const { server, data, handle, followers, following } = options - - const actor = data.find(a => a.name + '@' + a.host === handle) - const message = `${handle} on ${server.url}` - - expect(actor, message).to.exist - expect(actor.followersCount).to.equal(followers, message) - expect(actor.followingCount).to.equal(following, message) -} diff --git a/server/tests/shared/captions.ts b/server/tests/shared/captions.ts deleted file mode 100644 index 35e722408..000000000 --- a/server/tests/shared/captions.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { expect } from 'chai' -import request from 'supertest' -import { HttpStatusCode } from '@shared/models' - -async function testCaptionFile (url: string, captionPath: string, toTest: RegExp | string) { - const res = await request(url) - .get(captionPath) - .expect(HttpStatusCode.OK_200) - - if (toTest instanceof RegExp) { - expect(res.text).to.match(toTest) - } else { - expect(res.text).to.contain(toTest) - } -} - -// --------------------------------------------------------------------------- - -export { - testCaptionFile -} diff --git a/server/tests/shared/checks.ts b/server/tests/shared/checks.ts deleted file mode 100644 index 90179c6ac..000000000 --- a/server/tests/shared/checks.ts +++ /dev/null @@ -1,174 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ - -import { expect } from 'chai' -import { pathExists, readFile } from 'fs-extra' -import JPEG from 'jpeg-js' -import { join } from 'path' -import pixelmatch from 'pixelmatch' -import { PNG } from 'pngjs' -import { root } from '@shared/core-utils' -import { HttpStatusCode } from '@shared/models' -import { makeGetRequest, PeerTubeServer } from '@shared/server-commands' - -// Default interval -> 5 minutes -function dateIsValid (dateString: string | Date, interval = 300000) { - const dateToCheck = new Date(dateString) - const now = new Date() - - return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval -} - -function expectStartWith (str: string, start: string) { - expect(str.startsWith(start), `${str} does not start with ${start}`).to.be.true -} - -function expectNotStartWith (str: string, start: string) { - expect(str.startsWith(start), `${str} does not start with ${start}`).to.be.false -} - -function expectEndWith (str: string, end: string) { - expect(str.endsWith(end), `${str} does not end with ${end}`).to.be.true -} - -// --------------------------------------------------------------------------- - -async function expectLogDoesNotContain (server: PeerTubeServer, str: string) { - const content = await server.servers.getLogContent() - - expect(content.toString()).to.not.contain(str) -} - -async function expectLogContain (server: PeerTubeServer, str: string) { - const content = await server.servers.getLogContent() - - expect(content.toString()).to.contain(str) -} - -async function testImageSize (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { - const res = await makeGetRequest({ - url, - path: imageHTTPPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - const body = res.body - - const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) - const minLength = data.length - ((40 * data.length) / 100) - const maxLength = data.length + ((40 * data.length) / 100) - - expect(body.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') - expect(body.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') -} - -async function testImageGeneratedByFFmpeg (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { - if (process.env.ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS !== 'true') { - console.log( - 'Pixel comparison of image generated by ffmpeg is disabled. ' + - 'You can enable it using `ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS=true env variable') - } - - return testImage(url, imageName, imageHTTPPath, extension) -} - -async function testImage (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { - const res = await makeGetRequest({ - url, - path: imageHTTPPath, - expectedStatus: HttpStatusCode.OK_200 - }) - - const body = res.body - const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) - - const img1 = imageHTTPPath.endsWith('.png') - ? PNG.sync.read(body) - : JPEG.decode(body) - - const img2 = extension === '.png' - ? PNG.sync.read(data) - : JPEG.decode(data) - - const result = pixelmatch(img1.data, img2.data, null, img1.width, img1.height, { threshold: 0.1 }) - - expect(result).to.equal(0, `${imageHTTPPath} image is not the same as ${imageName}${extension}`) -} - -async function testFileExistsOrNot (server: PeerTubeServer, directory: string, filePath: string, exist: boolean) { - const base = server.servers.buildDirectory(directory) - - expect(await pathExists(join(base, filePath))).to.equal(exist) -} - -// --------------------------------------------------------------------------- - -function checkBadStartPagination (url: string, path: string, token?: string, query = {}) { - return makeGetRequest({ - url, - path, - token, - query: { ...query, start: 'hello' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) -} - -async function checkBadCountPagination (url: string, path: string, token?: string, query = {}) { - await makeGetRequest({ - url, - path, - token, - query: { ...query, count: 'hello' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) - - await makeGetRequest({ - url, - path, - token, - query: { ...query, count: 2000 }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) -} - -function checkBadSortPagination (url: string, path: string, token?: string, query = {}) { - return makeGetRequest({ - url, - path, - token, - query: { ...query, sort: 'hello' }, - expectedStatus: HttpStatusCode.BAD_REQUEST_400 - }) -} - -// --------------------------------------------------------------------------- - -async function checkVideoDuration (server: PeerTubeServer, videoUUID: string, duration: number) { - const video = await server.videos.get({ id: videoUUID }) - - expect(video.duration).to.be.approximately(duration, 1) - - for (const file of video.files) { - const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) - - for (const stream of metadata.streams) { - expect(Math.round(stream.duration)).to.be.approximately(duration, 1) - } - } -} - -export { - dateIsValid, - testImageGeneratedByFFmpeg, - testImageSize, - testImage, - expectLogDoesNotContain, - testFileExistsOrNot, - expectStartWith, - expectNotStartWith, - expectEndWith, - checkBadStartPagination, - checkBadCountPagination, - checkBadSortPagination, - checkVideoDuration, - expectLogContain -} diff --git a/server/tests/shared/directories.ts b/server/tests/shared/directories.ts deleted file mode 100644 index 5ad12d78a..000000000 --- a/server/tests/shared/directories.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { homedir } from 'os' -import { join } from 'path' -import { PeerTubeServer } from '@shared/server-commands' -import { PeerTubeRunnerProcess } from './peertube-runner-process' - -export async function checkTmpIsEmpty (server: PeerTubeServer) { - await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) - - if (await pathExists(server.getDirectoryPath('tmp/hls'))) { - await checkDirectoryIsEmpty(server, 'tmp/hls') - } -} - -export async function checkPersistentTmpIsEmpty (server: PeerTubeServer) { - await checkDirectoryIsEmpty(server, 'tmp-persistent') -} - -export async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) { - const directoryPath = server.getDirectoryPath(directory) - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - const filtered = files.filter(f => exceptions.includes(f) === false) - - expect(filtered).to.have.lengthOf(0) -} - -export async function checkPeerTubeRunnerCacheIsEmpty (runner: PeerTubeRunnerProcess) { - const directoryPath = join(homedir(), '.cache', 'peertube-runner-nodejs', runner.getId(), 'transcoding') - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - - expect(files, 'Directory content: ' + files.join(', ')).to.have.lengthOf(0) -} diff --git a/server/tests/shared/generate.ts b/server/tests/shared/generate.ts deleted file mode 100644 index 3788b049f..000000000 --- a/server/tests/shared/generate.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { expect } from 'chai' -import ffmpeg from 'fluent-ffmpeg' -import { ensureDir, pathExists } from 'fs-extra' -import { dirname } from 'path' -import { buildAbsoluteFixturePath, getMaxTheoreticalBitrate } from '@shared/core-utils' -import { getVideoStreamBitrate, getVideoStreamDimensionsInfo, getVideoStreamFPS } from '@shared/ffmpeg' - -async function ensureHasTooBigBitrate (fixturePath: string) { - const bitrate = await getVideoStreamBitrate(fixturePath) - const dataResolution = await getVideoStreamDimensionsInfo(fixturePath) - const fps = await getVideoStreamFPS(fixturePath) - - const maxBitrate = getMaxTheoreticalBitrate({ ...dataResolution, fps }) - expect(bitrate).to.be.above(maxBitrate) -} - -async function generateHighBitrateVideo () { - const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating high bitrate video.') - - // Generate a random, high bitrate video on the fly, so we don't have to include - // a large file in the repo. The video needs to have a certain minimum length so - // that FFmpeg properly applies bitrate limits. - // https://stackoverflow.com/a/15795112 - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - await ensureHasTooBigBitrate(tempFixturePath) - - return tempFixturePath -} - -async function generateVideoWithFramerate (fps = 60) { - const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating video with framerate %d.', fps) - - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ `-r ${fps}` ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - return tempFixturePath -} - -export { - generateHighBitrateVideo, - generateVideoWithFramerate -} diff --git a/server/tests/shared/index.ts b/server/tests/shared/index.ts deleted file mode 100644 index eda24adb5..000000000 --- a/server/tests/shared/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -export * from './mock-servers' -export * from './actors' -export * from './captions' -export * from './checks' -export * from './directories' -export * from './generate' -export * from './live' -export * from './notifications' -export * from './peertube-runner-process' -export * from './video-playlists' -export * from './plugins' -export * from './requests' -export * from './sql-command' -export * from './streaming-playlists' -export * from './tests' -export * from './tracker' -export * from './videos' -export * from './views' -export * from './webtorrent' diff --git a/server/tests/shared/live.ts b/server/tests/shared/live.ts deleted file mode 100644 index 9d8c1d941..000000000 --- a/server/tests/shared/live.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { join } from 'path' -import { sha1 } from '@shared/extra-utils' -import { LiveVideo, VideoStreamingPlaylistType } from '@shared/models' -import { ObjectStorageCommand, PeerTubeServer } from '@shared/server-commands' -import { SQLCommand } from './sql-command' -import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist } from './streaming-playlists' - -async function checkLiveCleanup (options: { - server: PeerTubeServer - videoUUID: string - permanent: boolean - savedResolutions?: number[] -}) { - const { server, videoUUID, permanent, savedResolutions = [] } = options - - const basePath = server.servers.buildDirectory('streaming-playlists') - const hlsPath = join(basePath, 'hls', videoUUID) - - if (permanent) { - if (!await pathExists(hlsPath)) return - - const files = await readdir(hlsPath) - expect(files).to.have.lengthOf(0) - return - } - - if (savedResolutions.length === 0) { - return checkUnsavedLiveCleanup(server, videoUUID, hlsPath) - } - - return checkSavedLiveCleanup(hlsPath, savedResolutions) -} - -// --------------------------------------------------------------------------- - -async function testLiveVideoResolutions (options: { - sqlCommand: SQLCommand - originServer: PeerTubeServer - - servers: PeerTubeServer[] - liveVideoId: string - resolutions: number[] - transcoded: boolean - - objectStorage?: ObjectStorageCommand - objectStorageBaseUrl?: string -}) { - const { - originServer, - sqlCommand, - servers, - liveVideoId, - resolutions, - transcoded, - objectStorage, - objectStorageBaseUrl = objectStorage?.getMockPlaylistBaseUrl() - } = options - - for (const server of servers) { - const { data } = await server.videos.list() - expect(data.find(v => v.uuid === liveVideoId)).to.exist - - const video = await server.videos.get({ id: liveVideoId }) - expect(video.streamingPlaylists).to.have.lengthOf(1) - - const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) - expect(hlsPlaylist).to.exist - expect(hlsPlaylist.files).to.have.lengthOf(0) // Only fragmented mp4 files are displayed - - await checkResolutionsInMasterPlaylist({ - server, - playlistUrl: hlsPlaylist.playlistUrl, - resolutions, - transcoded, - withRetry: !!objectStorage - }) - - if (objectStorage) { - expect(hlsPlaylist.playlistUrl).to.contain(objectStorageBaseUrl) - } - - for (let i = 0; i < resolutions.length; i++) { - const segmentNum = 3 - const segmentName = `${i}-00000${segmentNum}.ts` - await originServer.live.waitUntilSegmentGeneration({ - server: originServer, - videoUUID: video.uuid, - playlistNumber: i, - segment: segmentNum, - objectStorage, - objectStorageBaseUrl - }) - - const baseUrl = objectStorage - ? join(objectStorageBaseUrl, 'hls') - : originServer.url + '/static/streaming-playlists/hls' - - if (objectStorage) { - expect(hlsPlaylist.segmentsSha256Url).to.contain(objectStorageBaseUrl) - } - - const subPlaylist = await originServer.streamingPlaylists.get({ - url: `${baseUrl}/${video.uuid}/${i}.m3u8`, - withRetry: !!objectStorage // With object storage, the request may fail because of inconsistent data in S3 - }) - - expect(subPlaylist).to.contain(segmentName) - - await checkLiveSegmentHash({ - server, - baseUrlSegment: baseUrl, - videoUUID: video.uuid, - segmentName, - hlsPlaylist, - withRetry: !!objectStorage // With object storage, the request may fail because of inconsistent data in S3 - }) - - if (originServer.internalServerNumber === server.internalServerNumber) { - const infohash = sha1(`${2 + hlsPlaylist.playlistUrl}+V${i}`) - const dbInfohashes = await sqlCommand.getPlaylistInfohash(hlsPlaylist.id) - - expect(dbInfohashes).to.include(infohash) - } - } - } -} - -// --------------------------------------------------------------------------- - -export { - checkLiveCleanup, - testLiveVideoResolutions -} - -// --------------------------------------------------------------------------- - -async function checkSavedLiveCleanup (hlsPath: string, savedResolutions: number[] = []) { - const files = await readdir(hlsPath) - - // fragmented file and playlist per resolution + master playlist + segments sha256 json file - expect(files, `Directory content: ${files.join(', ')}`).to.have.lengthOf(savedResolutions.length * 2 + 2) - - for (const resolution of savedResolutions) { - const fragmentedFile = files.find(f => f.endsWith(`-${resolution}-fragmented.mp4`)) - expect(fragmentedFile).to.exist - - const playlistFile = files.find(f => f.endsWith(`${resolution}.m3u8`)) - expect(playlistFile).to.exist - } - - const masterPlaylistFile = files.find(f => f.endsWith('-master.m3u8')) - expect(masterPlaylistFile).to.exist - - const shaFile = files.find(f => f.endsWith('-segments-sha256.json')) - expect(shaFile).to.exist -} - -async function checkUnsavedLiveCleanup (server: PeerTubeServer, videoUUID: string, hlsPath: string) { - let live: LiveVideo - - try { - live = await server.live.get({ videoId: videoUUID }) - } catch {} - - if (live?.permanentLive) { - expect(await pathExists(hlsPath)).to.be.true - - const hlsFiles = await readdir(hlsPath) - expect(hlsFiles).to.have.lengthOf(1) // Only replays directory - - const replayDir = join(hlsPath, 'replay') - expect(await pathExists(replayDir)).to.be.true - - const replayFiles = await readdir(join(hlsPath, 'replay')) - expect(replayFiles).to.have.lengthOf(0) - - return - } - - expect(await pathExists(hlsPath)).to.be.false -} diff --git a/server/tests/shared/mock-servers/index.ts b/server/tests/shared/mock-servers/index.ts deleted file mode 100644 index 1fa983116..000000000 --- a/server/tests/shared/mock-servers/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from './mock-429' -export * from './mock-email' -export * from './mock-http' -export * from './mock-instances-index' -export * from './mock-joinpeertube-versions' -export * from './mock-object-storage' -export * from './mock-plugin-blocklist' -export * from './mock-proxy' diff --git a/server/tests/shared/mock-servers/mock-429.ts b/server/tests/shared/mock-servers/mock-429.ts deleted file mode 100644 index 1fc20b079..000000000 --- a/server/tests/shared/mock-servers/mock-429.ts +++ /dev/null @@ -1,33 +0,0 @@ -import express from 'express' -import { Server } from 'http' -import { getPort, randomListen, terminateServer } from './shared' - -export class Mock429 { - private server: Server - private responseSent = false - - async initialize () { - const app = express() - - app.get('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { - - if (!this.responseSent) { - this.responseSent = true - - // Retry after 5 seconds - res.header('retry-after', '2') - return res.sendStatus(429) - } - - return res.sendStatus(200) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - terminate () { - return terminateServer(this.server) - } -} diff --git a/server/tests/shared/mock-servers/mock-email.ts b/server/tests/shared/mock-servers/mock-email.ts deleted file mode 100644 index 6eda2dfda..000000000 --- a/server/tests/shared/mock-servers/mock-email.ts +++ /dev/null @@ -1,61 +0,0 @@ -import MailDev from '@peertube/maildev' -import { parallelTests, randomInt } from '@shared/core-utils' - -class MockSmtpServer { - - private static instance: MockSmtpServer - private started = false - private maildev: any - private emails: object[] - - private constructor () { } - - collectEmails (emailsCollection: object[]) { - return new Promise((res, rej) => { - const port = parallelTests() ? randomInt(1025, 2000) : 1025 - this.emails = emailsCollection - - if (this.started) { - return res(undefined) - } - - this.maildev = new MailDev({ - ip: '127.0.0.1', - smtp: port, - disableWeb: true, - silent: true - }) - - this.maildev.on('new', email => { - this.emails.push(email) - }) - - this.maildev.listen(err => { - if (err) return rej(err) - - this.started = true - - return res(port) - }) - }) - } - - kill () { - if (!this.maildev) return - - this.maildev.close() - - this.maildev = null - MockSmtpServer.instance = null - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } -} - -// --------------------------------------------------------------------------- - -export { - MockSmtpServer -} diff --git a/server/tests/shared/mock-servers/mock-http.ts b/server/tests/shared/mock-servers/mock-http.ts deleted file mode 100644 index b7a019e07..000000000 --- a/server/tests/shared/mock-servers/mock-http.ts +++ /dev/null @@ -1,23 +0,0 @@ -import express from 'express' -import { Server } from 'http' -import { getPort, randomListen, terminateServer } from './shared' - -export class MockHTTP { - private server: Server - - async initialize () { - const app = express() - - app.get('/*', (req: express.Request, res: express.Response, next: express.NextFunction) => { - return res.sendStatus(200) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - terminate () { - return terminateServer(this.server) - } -} diff --git a/server/tests/shared/mock-servers/mock-instances-index.ts b/server/tests/shared/mock-servers/mock-instances-index.ts deleted file mode 100644 index 598b007f1..000000000 --- a/server/tests/shared/mock-servers/mock-instances-index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import express from 'express' -import { Server } from 'http' -import { getPort, randomListen, terminateServer } from './shared' - -export class MockInstancesIndex { - private server: Server - - private readonly indexInstances: { host: string, createdAt: string }[] = [] - - async initialize () { - const app = express() - - app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { - if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) - - return next() - }) - - app.get('/api/v1/instances/hosts', (req: express.Request, res: express.Response) => { - const since = req.query.since - - const filtered = this.indexInstances.filter(i => { - if (!since) return true - - return i.createdAt > since - }) - - return res.json({ - total: filtered.length, - data: filtered - }) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - addInstance (host: string) { - this.indexInstances.push({ host, createdAt: new Date().toISOString() }) - } - - terminate () { - return terminateServer(this.server) - } -} diff --git a/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts b/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts deleted file mode 100644 index 502f4e2f5..000000000 --- a/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts +++ /dev/null @@ -1,34 +0,0 @@ -import express from 'express' -import { Server } from 'http' -import { getPort, randomListen } from './shared' - -export class MockJoinPeerTubeVersions { - private server: Server - private latestVersion: string - - async initialize () { - const app = express() - - app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { - if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) - - return next() - }) - - app.get('/versions.json', (req: express.Request, res: express.Response) => { - return res.json({ - peertube: { - latestVersion: this.latestVersion - } - }) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - setLatestVersion (latestVersion: string) { - this.latestVersion = latestVersion - } -} diff --git a/server/tests/shared/mock-servers/mock-object-storage.ts b/server/tests/shared/mock-servers/mock-object-storage.ts deleted file mode 100644 index ae76c4f3f..000000000 --- a/server/tests/shared/mock-servers/mock-object-storage.ts +++ /dev/null @@ -1,41 +0,0 @@ -import express from 'express' -import got, { RequestError } from 'got' -import { Server } from 'http' -import { pipeline } from 'stream' -import { ObjectStorageCommand } from '@shared/server-commands' -import { getPort, randomListen, terminateServer } from './shared' - -export class MockObjectStorageProxy { - private server: Server - - async initialize () { - const app = express() - - app.get('/:bucketName/:path(*)', (req: express.Request, res: express.Response, next: express.NextFunction) => { - const url = `http://${req.params.bucketName}.${ObjectStorageCommand.getMockEndpointHost()}/${req.params.path}` - - if (process.env.DEBUG) { - console.log('Receiving request on mocked server %s.', req.url) - console.log('Proxifying request to %s', url) - } - - return pipeline( - got.stream(url, { throwHttpErrors: false }), - res, - (err: RequestError) => { - if (!err) return - - console.error('Pipeline failed.', err) - } - ) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - terminate () { - return terminateServer(this.server) - } -} diff --git a/server/tests/shared/mock-servers/mock-plugin-blocklist.ts b/server/tests/shared/mock-servers/mock-plugin-blocklist.ts deleted file mode 100644 index 5d6e01816..000000000 --- a/server/tests/shared/mock-servers/mock-plugin-blocklist.ts +++ /dev/null @@ -1,36 +0,0 @@ -import express, { Request, Response } from 'express' -import { Server } from 'http' -import { getPort, randomListen, terminateServer } from './shared' - -type BlocklistResponse = { - data: { - value: string - action?: 'add' | 'remove' - updatedAt?: string - }[] -} - -export class MockBlocklist { - private body: BlocklistResponse - private server: Server - - async initialize () { - const app = express() - - app.get('/blocklist', (req: Request, res: Response) => { - return res.json(this.body) - }) - - this.server = await randomListen(app) - - return getPort(this.server) - } - - replace (body: BlocklistResponse) { - this.body = body - } - - terminate () { - return terminateServer(this.server) - } -} diff --git a/server/tests/shared/mock-servers/mock-proxy.ts b/server/tests/shared/mock-servers/mock-proxy.ts deleted file mode 100644 index e741d6735..000000000 --- a/server/tests/shared/mock-servers/mock-proxy.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createServer, Server } from 'http' -import { createProxy } from 'proxy' -import { getPort, terminateServer } from './shared' - -class MockProxy { - private server: Server - - initialize () { - return new Promise(res => { - this.server = createProxy(createServer()) - this.server.listen(0, () => res(getPort(this.server))) - }) - } - - terminate () { - return terminateServer(this.server) - } -} - -// --------------------------------------------------------------------------- - -export { - MockProxy -} diff --git a/server/tests/shared/mock-servers/shared.ts b/server/tests/shared/mock-servers/shared.ts deleted file mode 100644 index 235642439..000000000 --- a/server/tests/shared/mock-servers/shared.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Express } from 'express' -import { Server } from 'http' -import { AddressInfo } from 'net' - -function randomListen (app: Express) { - return new Promise(res => { - const server = app.listen(0, () => res(server)) - }) -} - -function getPort (server: Server) { - const address = server.address() as AddressInfo - - return address.port -} - -function terminateServer (server: Server) { - if (!server) return Promise.resolve() - - return new Promise((res, rej) => { - server.close(err => { - if (err) return rej(err) - - return res() - }) - }) -} - -export { - randomListen, - getPort, - terminateServer -} diff --git a/server/tests/shared/notifications.ts b/server/tests/shared/notifications.ts deleted file mode 100644 index 6c0688d5a..000000000 --- a/server/tests/shared/notifications.ts +++ /dev/null @@ -1,889 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { inspect } from 'util' -import { - AbuseState, - PluginType, - UserNotification, - UserNotificationSetting, - UserNotificationSettingValue, - UserNotificationType -} from '@shared/models' -import { - ConfigCommand, - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultAccountAvatar, - setDefaultChannelAvatar, - setDefaultVideoChannel -} from '@shared/server-commands' -import { MockSmtpServer } from './mock-servers' - -type CheckerBaseParams = { - server: PeerTubeServer - emails: any[] - socketNotifications: UserNotification[] - token: string - check?: { web: boolean, mail: boolean } -} - -type CheckerType = 'presence' | 'absence' - -function getAllNotificationsSettings (): UserNotificationSetting { - return { - newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - myVideoStudioEditionFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL - } -} - -async function checkNewVideoFromSubscription (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { - const { videoName, shortUUID } = options - const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkVideo(notification.video, videoName, shortUUID) - checkActor(notification.video.channel) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkVideoIsPublished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { - const { videoName, shortUUID } = options - const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkVideo(notification.video, videoName, shortUUID) - checkActor(notification.video.channel) - } else { - expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - return text.includes(shortUUID) && text.includes('Your video') - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkVideoStudioEditionIsFinished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - checkType: CheckerType -}) { - const { videoName, shortUUID } = options - const notificationType = UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkVideo(notification.video, videoName, shortUUID) - checkActor(notification.video.channel) - } else { - expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - return text.includes(shortUUID) && text.includes('Edition of your video') - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { - videoName: string - shortUUID: string - url: string - success: boolean - checkType: CheckerType -}) { - const { videoName, shortUUID, url, success } = options - - const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.videoImport.targetUrl).to.equal(url) - - if (success) checkVideo(notification.videoImport.video, videoName, shortUUID) - } else { - expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - const toFind = success ? ' finished' : ' error' - - return text.includes(url) && text.includes(toFind) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -// --------------------------------------------------------------------------- - -async function checkUserRegistered (options: CheckerBaseParams & { - username: string - checkType: CheckerType -}) { - const { username } = options - const notificationType = UserNotificationType.NEW_USER_REGISTRATION - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.account, { withAvatar: false }) - expect(notification.account.name).to.equal(username) - } else { - expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' registered.') && text.includes(username) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkRegistrationRequest (options: CheckerBaseParams & { - username: string - registrationReason: string - checkType: CheckerType -}) { - const { username, registrationReason } = options - const notificationType = UserNotificationType.NEW_USER_REGISTRATION_REQUEST - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.registration.username).to.equal(username) - } else { - expect(notification).to.satisfy(n => n.type !== notificationType || n.registration.username !== username) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' wants to register ') && text.includes(username) && text.includes(registrationReason) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -// --------------------------------------------------------------------------- - -async function checkNewActorFollow (options: CheckerBaseParams & { - followType: 'channel' | 'account' - followerName: string - followerDisplayName: string - followingDisplayName: string - checkType: CheckerType -}) { - const { followType, followerName, followerDisplayName, followingDisplayName } = options - const notificationType = UserNotificationType.NEW_FOLLOW - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.actorFollow.follower) - expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName) - expect(notification.actorFollow.follower.name).to.equal(followerName) - expect(notification.actorFollow.follower.host).to.not.be.undefined - - const following = notification.actorFollow.following - expect(following.displayName).to.equal(followingDisplayName) - expect(following.type).to.equal(followType) - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || - (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName) - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewInstanceFollower (options: CheckerBaseParams & { - followerHost: string - checkType: CheckerType -}) { - const { followerHost } = options - const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.actorFollow.follower, { withAvatar: false }) - expect(notification.actorFollow.follower.name).to.equal('peertube') - expect(notification.actorFollow.follower.host).to.equal(followerHost) - - expect(notification.actorFollow.following.name).to.equal('peertube') - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || n.actorFollow.follower.host !== followerHost - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes('instance has a new follower') && text.includes(followerHost) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkAutoInstanceFollowing (options: CheckerBaseParams & { - followerHost: string - followingHost: string - checkType: CheckerType -}) { - const { followerHost, followingHost } = options - const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - const following = notification.actorFollow.following - - checkActor(following, { withAvatar: false }) - expect(following.name).to.equal('peertube') - expect(following.host).to.equal(followingHost) - - expect(notification.actorFollow.follower.name).to.equal('peertube') - expect(notification.actorFollow.follower.host).to.equal(followerHost) - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || n.actorFollow.following.host !== followingHost - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' automatically followed a new instance') && text.includes(followingHost) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkCommentMention (options: CheckerBaseParams & { - shortUUID: string - commentId: number - threadId: number - byAccountDisplayName: string - checkType: CheckerType -}) { - const { shortUUID, commentId, threadId, byAccountDisplayName } = options - const notificationType = UserNotificationType.COMMENT_MENTION - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkComment(notification.comment, commentId, threadId) - checkActor(notification.comment.account) - expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) - - checkVideo(notification.comment.video, undefined, shortUUID) - } else { - expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -let lastEmailCount = 0 - -async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { - shortUUID: string - commentId: number - threadId: number - checkType: CheckerType -}) { - const { server, shortUUID, commentId, threadId, checkType, emails } = options - const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkComment(notification.comment, commentId, threadId) - checkActor(notification.comment.account) - checkVideo(notification.comment.video, undefined, shortUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.comment === undefined || n.comment.id !== commentId - }) - } - } - - const commentUrl = `${server.url}/w/${shortUUID};threadId=${threadId}` - - function emailNotificationFinder (email: object) { - return email['text'].indexOf(commentUrl) !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) - - if (checkType === 'presence') { - // We cannot detect email duplicates, so check we received another email - expect(emails).to.have.length.above(lastEmailCount) - lastEmailCount = emails.length - } -} - -async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { - const { shortUUID, videoName } = options - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - checkVideo(notification.abuse.video, videoName, shortUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewAbuseMessage (options: CheckerBaseParams & { - abuseId: number - message: string - toEmail: string - checkType: CheckerType -}) { - const { abuseId, message, toEmail } = options - const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.equal(abuseId) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - const to = email['to'].filter(t => t.address === toEmail) - - return text.indexOf(message) !== -1 && to.length !== 0 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkAbuseStateChange (options: CheckerBaseParams & { - abuseId: number - state: AbuseState - checkType: CheckerType -}) { - const { abuseId, state } = options - const notificationType = UserNotificationType.ABUSE_STATE_CHANGE - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.equal(abuseId) - expect(notification.abuse.state).to.equal(state) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - const contains = state === AbuseState.ACCEPTED - ? ' accepted' - : ' rejected' - - return text.indexOf(contains) !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { - const { shortUUID, videoName } = options - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - checkVideo(notification.abuse.comment.video, videoName, shortUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & { - displayName: string - checkType: CheckerType -}) { - const { displayName } = options - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - expect(notification.abuse.account.displayName).to.equal(displayName) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & { - shortUUID: string - videoName: string - checkType: CheckerType -}) { - const { shortUUID, videoName } = options - const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.videoBlacklist.video.id).to.be.a('number') - checkVideo(notification.videoBlacklist.video, videoName, shortUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & { - shortUUID: string - videoName: string - blacklistType: 'blacklist' | 'unblacklist' -}) { - const { videoName, shortUUID, blacklistType } = options - const notificationType = blacklistType === 'blacklist' - ? UserNotificationType.BLACKLIST_ON_MY_VIDEO - : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO - - function notificationChecker (notification: UserNotification) { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video - - checkVideo(video, videoName, shortUUID) - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - const blacklistText = blacklistType === 'blacklist' - ? 'blacklisted' - : 'unblacklisted' - - return text.includes(shortUUID) && text.includes(blacklistText) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' }) -} - -async function checkNewPeerTubeVersion (options: CheckerBaseParams & { - latestVersion: string - checkType: CheckerType -}) { - const { latestVersion } = options - const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.peertube).to.exist - expect(notification.peertube.latestVersion).to.equal(latestVersion) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - return text.includes(latestVersion) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function checkNewPluginVersion (options: CheckerBaseParams & { - pluginType: PluginType - pluginName: string - checkType: CheckerType -}) { - const { pluginName, pluginType } = options - const notificationType = UserNotificationType.NEW_PLUGIN_VERSION - - function notificationChecker (notification: UserNotification, checkType: CheckerType) { - if (checkType === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.plugin.name).to.equal(pluginName) - expect(notification.plugin.type).to.equal(pluginType) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - return text.includes(pluginName) - } - - await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) -} - -async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { - const userNotifications: UserNotification[] = [] - const adminNotifications: UserNotification[] = [] - const adminNotificationsServer2: UserNotification[] = [] - const emails: object[] = [] - - const port = await MockSmtpServer.Instance.collectEmails(emails) - - const overrideConfig = { - ...ConfigCommand.getEmailOverrideConfig(port), - - signup: { - limit: 20 - } - } - const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) - - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - await setDefaultChannelAvatar(servers) - await setDefaultAccountAvatar(servers) - - if (servers[1]) { - await servers[1].config.enableStudio() - await servers[1].config.enableLive({ allowReplay: true, transcoding: false }) - } - - if (serversCount > 1) { - await doubleFollow(servers[0], servers[1]) - } - - const user = { username: 'user_1', password: 'super password' } - await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 }) - const userAccessToken = await servers[0].login.getAccessToken(user) - - await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) - await servers[0].users.updateMyAvatar({ token: userAccessToken, fixture: 'avatar.png' }) - await servers[0].channels.updateImage({ channelName: 'user_1_channel', token: userAccessToken, fixture: 'avatar.png', type: 'avatar' }) - - await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) - - if (serversCount > 1) { - await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) - } - - { - const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken }) - socket.on('new-notification', n => userNotifications.push(n)) - } - { - const socket = servers[0].socketIO.getUserNotificationSocket() - socket.on('new-notification', n => adminNotifications.push(n)) - } - - if (serversCount > 1) { - const socket = servers[1].socketIO.getUserNotificationSocket() - socket.on('new-notification', n => adminNotificationsServer2.push(n)) - } - - const { videoChannels } = await servers[0].users.getMyInfo() - const channelId = videoChannels[0].id - - return { - userNotifications, - adminNotifications, - adminNotificationsServer2, - userAccessToken, - emails, - servers, - channelId, - baseOverrideConfig: overrideConfig - } -} - -// --------------------------------------------------------------------------- - -export { - getAllNotificationsSettings, - - CheckerBaseParams, - CheckerType, - checkMyVideoImportIsFinished, - checkUserRegistered, - checkAutoInstanceFollowing, - checkVideoIsPublished, - checkNewVideoFromSubscription, - checkNewActorFollow, - checkNewCommentOnMyVideo, - checkNewBlacklistOnMyVideo, - checkCommentMention, - checkNewVideoAbuseForModerators, - checkVideoAutoBlacklistForModerators, - checkNewAbuseMessage, - checkAbuseStateChange, - checkNewInstanceFollower, - prepareNotificationsTest, - checkNewCommentAbuseForModerators, - checkNewAccountAbuseForModerators, - checkNewPeerTubeVersion, - checkNewPluginVersion, - checkVideoStudioEditionIsFinished, - checkRegistrationRequest -} - -// --------------------------------------------------------------------------- - -async function checkNotification (options: CheckerBaseParams & { - notificationChecker: (notification: UserNotification, checkType: CheckerType) => void - emailNotificationFinder: (email: object) => boolean - checkType: CheckerType -}) { - const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options - - const check = options.check || { web: true, mail: true } - - if (check.web) { - const notification = await server.notifications.getLatest({ token }) - - if (notification || checkType !== 'absence') { - notificationChecker(notification, checkType) - } - - const socketNotification = socketNotifications.find(n => { - try { - notificationChecker(n, 'presence') - return true - } catch { - return false - } - }) - - if (checkType === 'presence') { - const obj = inspect(socketNotifications, { depth: 5 }) - expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined - } else { - const obj = inspect(socketNotification, { depth: 5 }) - expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined - } - } - - if (check.mail) { - // Last email - const email = emails - .slice() - .reverse() - .find(e => emailNotificationFinder(e)) - - if (checkType === 'presence') { - const texts = emails.map(e => e.text) - expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined - } else { - expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined - } - } -} - -function checkVideo (video: any, videoName?: string, shortUUID?: string) { - if (videoName) { - expect(video.name).to.be.a('string') - expect(video.name).to.not.be.empty - expect(video.name).to.equal(videoName) - } - - if (shortUUID) { - expect(video.shortUUID).to.be.a('string') - expect(video.shortUUID).to.not.be.empty - expect(video.shortUUID).to.equal(shortUUID) - } - - expect(video.id).to.be.a('number') -} - -function checkActor (actor: any, options: { withAvatar?: boolean } = {}) { - const { withAvatar = true } = options - - expect(actor.displayName).to.be.a('string') - expect(actor.displayName).to.not.be.empty - expect(actor.host).to.not.be.undefined - - if (withAvatar) { - expect(actor.avatars).to.be.an('array') - expect(actor.avatars).to.have.lengthOf(2) - expect(actor.avatars[0].path).to.exist.and.not.empty - } -} - -function checkComment (comment: any, commentId: number, threadId: number) { - expect(comment.id).to.equal(commentId) - expect(comment.threadId).to.equal(threadId) -} diff --git a/server/tests/shared/peertube-runner-process.ts b/server/tests/shared/peertube-runner-process.ts deleted file mode 100644 index 9304ebcc8..000000000 --- a/server/tests/shared/peertube-runner-process.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { ChildProcess, fork } from 'child_process' -import execa from 'execa' -import { join } from 'path' -import { root } from '@shared/core-utils' -import { PeerTubeServer } from '@shared/server-commands' - -export class PeerTubeRunnerProcess { - private app?: ChildProcess - - constructor (private readonly server: PeerTubeServer) { - - } - - runServer (options: { - hideLogs?: boolean // default true - } = {}) { - const { hideLogs = true } = options - - return new Promise((res, rej) => { - const args = [ 'server', '--verbose', ...this.buildIdArg() ] - - const forkOptions = { - detached: false, - silent: true - } - this.app = fork(this.getRunnerPath(), args, forkOptions) - - this.app.stdout.on('data', data => { - const str = data.toString() as string - - if (!hideLogs) { - console.log(str) - } - }) - - res() - }) - } - - registerPeerTubeInstance (options: { - registrationToken: string - runnerName: string - runnerDescription?: string - }) { - const { registrationToken, runnerName, runnerDescription } = options - - const args = [ - 'register', - '--url', this.server.url, - '--registration-token', registrationToken, - '--runner-name', runnerName, - ...this.buildIdArg() - ] - - if (runnerDescription) { - args.push('--runner-description') - args.push(runnerDescription) - } - - return execa.node(this.getRunnerPath(), args) - } - - unregisterPeerTubeInstance (options: { - runnerName: string - }) { - const { runnerName } = options - - const args = [ 'unregister', '--url', this.server.url, '--runner-name', runnerName, ...this.buildIdArg() ] - return execa.node(this.getRunnerPath(), args) - } - - async listRegisteredPeerTubeInstances () { - const args = [ 'list-registered', ...this.buildIdArg() ] - const { stdout } = await execa.node(this.getRunnerPath(), args) - - return stdout - } - - kill () { - if (!this.app) return - - process.kill(this.app.pid) - - this.app = null - } - - getId () { - return 'test-' + this.server.internalServerNumber - } - - private getRunnerPath () { - return join(root(), 'packages', 'peertube-runner', 'dist', 'peertube-runner.js') - } - - private buildIdArg () { - return [ '--id', this.getId() ] - } -} diff --git a/server/tests/shared/plugins.ts b/server/tests/shared/plugins.ts deleted file mode 100644 index 036fce2ff..000000000 --- a/server/tests/shared/plugins.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { PeerTubeServer } from '@shared/server-commands' - -async function testHelloWorldRegisteredSettings (server: PeerTubeServer) { - const body = await server.plugins.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) - - const registeredSettings = body.registeredSettings - expect(registeredSettings).to.have.length.at.least(1) - - const adminNameSettings = registeredSettings.find(s => s.name === 'admin-name') - expect(adminNameSettings).to.not.be.undefined -} - -export { - testHelloWorldRegisteredSettings -} diff --git a/server/tests/shared/requests.ts b/server/tests/shared/requests.ts deleted file mode 100644 index 0cfeab7b2..000000000 --- a/server/tests/shared/requests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { doRequest } from '@server/helpers/requests' - -export function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) { - const options = { - method: 'POST' as 'POST', - json: body, - httpSignature, - headers - } - - return doRequest(url, options) -} diff --git a/server/tests/shared/sql-command.ts b/server/tests/shared/sql-command.ts deleted file mode 100644 index 5c53a8ac6..000000000 --- a/server/tests/shared/sql-command.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { QueryTypes, Sequelize } from 'sequelize' -import { forceNumber } from '@shared/core-utils' -import { PeerTubeServer } from '@shared/server-commands' - -export class SQLCommand { - private sequelize: Sequelize - - constructor (private readonly server: PeerTubeServer) { - - } - - deleteAll (table: string) { - const seq = this.getSequelize() - - const options = { type: QueryTypes.DELETE } - - return seq.query(`DELETE FROM "${table}"`, options) - } - - async getVideoShareCount () { - const [ { total } ] = await this.selectQuery<{ total: string }>(`SELECT COUNT(*) as total FROM "videoShare"`) - if (total === null) return 0 - - return parseInt(total, 10) - } - - async getInternalFileUrl (fileId: number) { - return this.selectQuery<{ fileUrl: string }>(`SELECT "fileUrl" FROM "videoFile" WHERE id = :fileId`, { fileId }) - .then(rows => rows[0].fileUrl) - } - - setActorField (to: string, field: string, value: string) { - return this.updateQuery(`UPDATE actor SET ${this.escapeColumnName(field)} = :value WHERE url = :to`, { value, to }) - } - - setVideoField (uuid: string, field: string, value: string) { - return this.updateQuery(`UPDATE video SET ${this.escapeColumnName(field)} = :value WHERE uuid = :uuid`, { value, uuid }) - } - - setPlaylistField (uuid: string, field: string, value: string) { - return this.updateQuery(`UPDATE "videoPlaylist" SET ${this.escapeColumnName(field)} = :value WHERE uuid = :uuid`, { value, uuid }) - } - - async countVideoViewsOf (uuid: string) { - const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' + - `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = :uuid` - - const [ { total } ] = await this.selectQuery<{ total: number }>(query, { uuid }) - if (!total) return 0 - - return forceNumber(total) - } - - getActorImage (filename: string) { - return this.selectQuery<{ width: number, height: number }>(`SELECT * FROM "actorImage" WHERE filename = :filename`, { filename }) - .then(rows => rows[0]) - } - - // --------------------------------------------------------------------------- - - setPluginVersion (pluginName: string, newVersion: string) { - return this.setPluginField(pluginName, 'version', newVersion) - } - - setPluginLatestVersion (pluginName: string, newVersion: string) { - return this.setPluginField(pluginName, 'latestVersion', newVersion) - } - - setPluginField (pluginName: string, field: string, value: string) { - return this.updateQuery( - `UPDATE "plugin" SET ${this.escapeColumnName(field)} = :value WHERE "name" = :pluginName`, - { pluginName, value } - ) - } - - // --------------------------------------------------------------------------- - - selectQuery (query: string, replacements: { [id: string]: string | number } = {}) { - const seq = this.getSequelize() - const options = { - type: QueryTypes.SELECT as QueryTypes.SELECT, - replacements - } - - return seq.query(query, options) - } - - updateQuery (query: string, replacements: { [id: string]: string | number } = {}) { - const seq = this.getSequelize() - const options = { type: QueryTypes.UPDATE as QueryTypes.UPDATE, replacements } - - return seq.query(query, options) - } - - // --------------------------------------------------------------------------- - - async getPlaylistInfohash (playlistId: number) { - const query = 'SELECT "p2pMediaLoaderInfohashes" FROM "videoStreamingPlaylist" WHERE id = :playlistId' - - const result = await this.selectQuery<{ p2pMediaLoaderInfohashes: string }>(query, { playlistId }) - if (!result || result.length === 0) return [] - - return result[0].p2pMediaLoaderInfohashes - } - - // --------------------------------------------------------------------------- - - setActorFollowScores (newScore: number) { - return this.updateQuery(`UPDATE "actorFollow" SET "score" = :newScore`, { newScore }) - } - - setTokenField (accessToken: string, field: string, value: string) { - return this.updateQuery( - `UPDATE "oAuthToken" SET ${this.escapeColumnName(field)} = :value WHERE "accessToken" = :accessToken`, - { value, accessToken } - ) - } - - async cleanup () { - if (!this.sequelize) return - - await this.sequelize.close() - this.sequelize = undefined - } - - private getSequelize () { - if (this.sequelize) return this.sequelize - - const dbname = 'peertube_test' + this.server.internalServerNumber - const username = 'peertube' - const password = 'peertube' - const host = '127.0.0.1' - const port = 5432 - - this.sequelize = new Sequelize(dbname, username, password, { - dialect: 'postgres', - host, - port, - logging: false - }) - - return this.sequelize - } - - private escapeColumnName (columnName: string) { - return this.getSequelize().escape(columnName) - .replace(/^'/, '"') - .replace(/'$/, '"') - } -} diff --git a/server/tests/shared/streaming-playlists.ts b/server/tests/shared/streaming-playlists.ts deleted file mode 100644 index e4f88bc25..000000000 --- a/server/tests/shared/streaming-playlists.ts +++ /dev/null @@ -1,296 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { basename, dirname, join } from 'path' -import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' -import { sha256 } from '@shared/extra-utils' -import { HttpStatusCode, VideoPrivacy, VideoResolution, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@shared/models' -import { makeRawRequest, PeerTubeServer } from '@shared/server-commands' -import { expectStartWith } from './checks' -import { hlsInfohashExist } from './tracker' -import { checkWebTorrentWorks } from './webtorrent' - -async function checkSegmentHash (options: { - server: PeerTubeServer - baseUrlPlaylist: string - baseUrlSegment: string - resolution: number - hlsPlaylist: VideoStreamingPlaylist - token?: string -}) { - const { server, baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist, token } = options - const command = server.streamingPlaylists - - const file = hlsPlaylist.files.find(f => f.resolution.id === resolution) - const videoName = basename(file.fileUrl) - - const playlist = await command.get({ url: `${baseUrlPlaylist}/${removeFragmentedMP4Ext(videoName)}.m3u8`, token }) - - const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) - - const length = parseInt(matches[1], 10) - const offset = parseInt(matches[2], 10) - const range = `${offset}-${offset + length - 1}` - - const segmentBody = await command.getFragmentedSegment({ - url: `${baseUrlSegment}/${videoName}`, - expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, - range: `bytes=${range}`, - token - }) - - const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, token }) - expect(sha256(segmentBody)).to.equal(shaBody[videoName][range], `Invalid sha256 result for ${videoName} range ${range}`) -} - -// --------------------------------------------------------------------------- - -async function checkLiveSegmentHash (options: { - server: PeerTubeServer - baseUrlSegment: string - videoUUID: string - segmentName: string - hlsPlaylist: VideoStreamingPlaylist - withRetry?: boolean -}) { - const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist, withRetry = false } = options - const command = server.streamingPlaylists - - const segmentBody = await command.getFragmentedSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}`, withRetry }) - const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, withRetry }) - - expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) -} - -// --------------------------------------------------------------------------- - -async function checkResolutionsInMasterPlaylist (options: { - server: PeerTubeServer - playlistUrl: string - resolutions: number[] - token?: string - transcoded?: boolean // default true - withRetry?: boolean // default false -}) { - const { server, playlistUrl, resolutions, token, withRetry = false, transcoded = true } = options - - const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl, token, withRetry }) - - for (const resolution of resolutions) { - const base = '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution - - if (resolution === VideoResolution.H_NOVIDEO) { - expect(masterPlaylist).to.match(new RegExp(`${base},CODECS="mp4a.40.2"`)) - } else if (transcoded) { - expect(masterPlaylist).to.match(new RegExp(`${base},(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"`)) - } else { - expect(masterPlaylist).to.match(new RegExp(`${base}`)) - } - } - - const playlistsLength = masterPlaylist.split('\n').filter(line => line.startsWith('#EXT-X-STREAM-INF:BANDWIDTH=')) - expect(playlistsLength).to.have.lengthOf(resolutions.length) -} - -async function completeCheckHlsPlaylist (options: { - servers: PeerTubeServer[] - videoUUID: string - hlsOnly: boolean - - resolutions?: number[] - objectStorageBaseUrl?: string -}) { - const { videoUUID, hlsOnly, objectStorageBaseUrl } = options - - const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] - - for (const server of options.servers) { - const videoDetails = await server.videos.getWithToken({ id: videoUUID }) - const requiresAuth = videoDetails.privacy.id === VideoPrivacy.PRIVATE || videoDetails.privacy.id === VideoPrivacy.INTERNAL - - const privatePath = requiresAuth - ? 'private/' - : '' - const token = requiresAuth - ? server.accessToken - : undefined - - const baseUrl = `http://${videoDetails.account.host}` - - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - - const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) - expect(hlsPlaylist).to.not.be.undefined - - const hlsFiles = hlsPlaylist.files - expect(hlsFiles).to.have.lengthOf(resolutions.length) - - if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) - else expect(videoDetails.files).to.have.lengthOf(resolutions.length) - - // Check JSON files - for (const resolution of resolutions) { - const file = hlsFiles.find(f => f.resolution.id === resolution) - expect(file).to.not.be.undefined - - if (file.resolution.id === VideoResolution.H_NOVIDEO) { - expect(file.resolution.label).to.equal('Audio') - } else { - expect(file.resolution.label).to.equal(resolution + 'p') - } - - expect(file.magnetUri).to.have.lengthOf.above(2) - await checkWebTorrentWorks(file.magnetUri) - - { - const nameReg = `${uuidRegex}-${file.resolution.id}` - - expect(file.torrentUrl).to.match(new RegExp(`${server.url}/lazy-static/torrents/${nameReg}-hls.torrent`)) - - if (objectStorageBaseUrl && requiresAuth) { - // eslint-disable-next-line max-len - expect(file.fileUrl).to.match(new RegExp(`${server.url}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoDetails.uuid}/${nameReg}-fragmented.mp4`)) - } else if (objectStorageBaseUrl) { - expectStartWith(file.fileUrl, objectStorageBaseUrl) - } else { - expect(file.fileUrl).to.match( - new RegExp(`${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoDetails.uuid}/${nameReg}-fragmented.mp4`) - ) - } - } - - { - await Promise.all([ - makeRawRequest({ url: file.torrentUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.torrentDownloadUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.metadataUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.fileUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - - makeRawRequest({ - url: file.fileDownloadUrl, - token, - expectedStatus: objectStorageBaseUrl - ? HttpStatusCode.FOUND_302 - : HttpStatusCode.OK_200 - }) - ]) - } - } - - // Check master playlist - { - await checkResolutionsInMasterPlaylist({ server, token, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) - - const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl, token }) - - let i = 0 - for (const resolution of resolutions) { - expect(masterPlaylist).to.contain(`${resolution}.m3u8`) - expect(masterPlaylist).to.contain(`${resolution}.m3u8`) - - const url = 'http://' + videoDetails.account.host - await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) - - i++ - } - } - - // Check resolution playlists - { - for (const resolution of resolutions) { - const file = hlsFiles.find(f => f.resolution.id === resolution) - const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' - - let url: string - if (objectStorageBaseUrl && requiresAuth) { - url = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}` - } else if (objectStorageBaseUrl) { - url = `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` - } else { - url = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}` - } - - const subPlaylist = await server.streamingPlaylists.get({ url, token }) - - expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) - expect(subPlaylist).to.contain(basename(file.fileUrl)) - } - } - - { - let baseUrlAndPath: string - if (objectStorageBaseUrl && requiresAuth) { - baseUrlAndPath = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}` - } else if (objectStorageBaseUrl) { - baseUrlAndPath = `${objectStorageBaseUrl}hls/${videoUUID}` - } else { - baseUrlAndPath = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}` - } - - for (const resolution of resolutions) { - await checkSegmentHash({ - server, - token, - baseUrlPlaylist: baseUrlAndPath, - baseUrlSegment: baseUrlAndPath, - resolution, - hlsPlaylist - }) - } - } - } -} - -async function checkVideoFileTokenReinjection (options: { - server: PeerTubeServer - videoUUID: string - videoFileToken: string - resolutions: number[] - isLive: boolean -}) { - const { server, resolutions, videoFileToken, videoUUID, isLive } = options - - const video = await server.videos.getWithToken({ id: videoUUID }) - const hls = video.streamingPlaylists[0] - - const query = { videoFileToken, reinjectVideoFileToken: 'true' } - const { text } = await makeRawRequest({ url: hls.playlistUrl, query, expectedStatus: HttpStatusCode.OK_200 }) - - for (let i = 0; i < resolutions.length; i++) { - const resolution = resolutions[i] - - const suffix = isLive - ? i - : `-${resolution}` - - expect(text).to.contain(`${suffix}.m3u8?videoFileToken=${videoFileToken}&reinjectVideoFileToken=true`) - } - - const resolutionPlaylists = extractResolutionPlaylistUrls(hls.playlistUrl, text) - expect(resolutionPlaylists).to.have.lengthOf(resolutions.length) - - for (const url of resolutionPlaylists) { - const { text } = await makeRawRequest({ url, query, expectedStatus: HttpStatusCode.OK_200 }) - - const extension = isLive - ? '.ts' - : '.mp4' - - expect(text).to.contain(`${extension}?videoFileToken=${videoFileToken}`) - expect(text).not.to.contain(`reinjectVideoFileToken=true`) - } -} - -function extractResolutionPlaylistUrls (masterPath: string, masterContent: string) { - return masterContent.match(/^([^.]+\.m3u8.*)/mg) - .map(filename => join(dirname(masterPath), filename)) -} - -export { - checkSegmentHash, - checkLiveSegmentHash, - checkResolutionsInMasterPlaylist, - completeCheckHlsPlaylist, - extractResolutionPlaylistUrls, - checkVideoFileTokenReinjection -} diff --git a/server/tests/shared/tests.ts b/server/tests/shared/tests.ts deleted file mode 100644 index d2cb040fb..000000000 --- a/server/tests/shared/tests.ts +++ /dev/null @@ -1,40 +0,0 @@ -const FIXTURE_URLS = { - peertube_long: 'https://peertube2.cpy.re/videos/watch/122d093a-1ede-43bd-bd34-59d2931ffc5e', - peertube_short: 'https://peertube2.cpy.re/w/3fbif9S3WmtTP8gGsC5HBd', - - youtube: 'https://www.youtube.com/watch?v=msX3jv1XdvM', - - /** - * The video is used to check format-selection correctness wrt. HDR, - * which brings its own set of oddities outside of a MediaSource. - * - * The video needs to have the following format_ids: - * (which you can check by using `youtube-dl -F`): - * - (webm vp9) - * - (mp4 avc1) - * - (webm vp9.2 HDR) - */ - youtubeHDR: 'https://www.youtube.com/watch?v=RQgnBB9z_N4', - - youtubeChannel: 'https://youtube.com/channel/UCtnlZdXv3-xQzxiqfn6cjIA', - youtubePlaylist: 'https://youtube.com/playlist?list=PLRGXHPrcPd2yc2KdswlAWOxIJ8G3vgy4h', - - // eslint-disable-next-line max-len - magnet: 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4', - - badVideo: 'https://download.cpy.re/peertube/bad_video.mp4', - goodVideo: 'https://download.cpy.re/peertube/good_video.mp4', - goodVideo720: 'https://download.cpy.re/peertube/good_video_720.mp4', - - file4K: 'https://download.cpy.re/peertube/4k_file.txt' -} - -function buildRequestStub (): any { - return { } -} - -export { - FIXTURE_URLS, - - buildRequestStub -} diff --git a/server/tests/shared/tracker.ts b/server/tests/shared/tracker.ts deleted file mode 100644 index 9c1f0246a..000000000 --- a/server/tests/shared/tracker.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { expect } from 'chai' -import { sha1 } from '@shared/extra-utils' -import { makeGetRequest } from '@shared/server-commands' - -async function hlsInfohashExist (serverUrl: string, masterPlaylistUrl: string, fileNumber: number) { - const path = '/tracker/announce' - - const infohash = sha1(`2${masterPlaylistUrl}+V${fileNumber}`) - - // From bittorrent-tracker - const infohashBinary = escape(Buffer.from(infohash, 'hex').toString('binary')).replace(/[@*/+]/g, function (char) { - return '%' + char.charCodeAt(0).toString(16).toUpperCase() - }) - - const res = await makeGetRequest({ - url: serverUrl, - path, - rawQuery: `peer_id=-WW0105-NkvYO/egUAr4&info_hash=${infohashBinary}&port=42100`, - expectedStatus: 200 - }) - - expect(res.text).to.not.contain('failure') -} - -export { - hlsInfohashExist -} diff --git a/server/tests/shared/video-playlists.ts b/server/tests/shared/video-playlists.ts deleted file mode 100644 index 8db303fd8..000000000 --- a/server/tests/shared/video-playlists.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'chai' -import { readdir } from 'fs-extra' -import { PeerTubeServer } from '@shared/server-commands' - -async function checkPlaylistFilesWereRemoved ( - playlistUUID: string, - server: PeerTubeServer, - directories = [ 'thumbnails' ] -) { - for (const directory of directories) { - const directoryPath = server.getDirectoryPath(directory) - - const files = await readdir(directoryPath) - for (const file of files) { - expect(file).to.not.contain(playlistUUID) - } - } -} - -export { - checkPlaylistFilesWereRemoved -} diff --git a/server/tests/shared/videos.ts b/server/tests/shared/videos.ts deleted file mode 100644 index ac24bb173..000000000 --- a/server/tests/shared/videos.ts +++ /dev/null @@ -1,315 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { basename, join } from 'path' -import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '@server/initializers/constants' -import { getLowercaseExtension, pick, uuidRegex } from '@shared/core-utils' -import { HttpStatusCode, VideoCaption, VideoDetails, VideoPrivacy, VideoResolution } from '@shared/models' -import { makeRawRequest, PeerTubeServer, VideoEdit, waitJobs } from '@shared/server-commands' -import { dateIsValid, expectStartWith, testImageGeneratedByFFmpeg } from './checks' -import { checkWebTorrentWorks } from './webtorrent' - -loadLanguages() - -async function completeWebVideoFilesCheck (options: { - server: PeerTubeServer - originServer: PeerTubeServer - videoUUID: string - fixture: string - files: { - resolution: number - size?: number - }[] - objectStorageBaseUrl?: string -}) { - const { originServer, server, videoUUID, files, fixture, objectStorageBaseUrl } = options - const video = await server.videos.getWithToken({ id: videoUUID }) - const serverConfig = await originServer.config.getConfig() - const requiresAuth = video.privacy.id === VideoPrivacy.PRIVATE || video.privacy.id === VideoPrivacy.INTERNAL - - const transcodingEnabled = serverConfig.transcoding.web_videos.enabled - - for (const attributeFile of files) { - const file = video.files.find(f => f.resolution.id === attributeFile.resolution) - expect(file, `resolution ${attributeFile.resolution} does not exist`).not.to.be.undefined - - let extension = getLowercaseExtension(fixture) - // Transcoding enabled: extension will always be .mp4 - if (transcodingEnabled) extension = '.mp4' - - expect(file.id).to.exist - expect(file.magnetUri).to.have.lengthOf.above(2) - - { - const privatePath = requiresAuth - ? 'private/' - : '' - const nameReg = `${uuidRegex}-${file.resolution.id}` - - expect(file.torrentDownloadUrl).to.match(new RegExp(`${server.url}/download/torrents/${nameReg}.torrent`)) - expect(file.torrentUrl).to.match(new RegExp(`${server.url}/lazy-static/torrents/${nameReg}.torrent`)) - - if (objectStorageBaseUrl && requiresAuth) { - const regexp = new RegExp(`${originServer.url}/object-storage-proxy/web-videos/${privatePath}${nameReg}${extension}`) - expect(file.fileUrl).to.match(regexp) - } else if (objectStorageBaseUrl) { - expectStartWith(file.fileUrl, objectStorageBaseUrl) - } else { - expect(file.fileUrl).to.match(new RegExp(`${originServer.url}/static/web-videos/${privatePath}${nameReg}${extension}`)) - } - - expect(file.fileDownloadUrl).to.match(new RegExp(`${originServer.url}/download/videos/${nameReg}${extension}`)) - } - - { - const token = requiresAuth - ? server.accessToken - : undefined - - await Promise.all([ - makeRawRequest({ url: file.torrentUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.torrentDownloadUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.metadataUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ url: file.fileUrl, token, expectedStatus: HttpStatusCode.OK_200 }), - makeRawRequest({ - url: file.fileDownloadUrl, - token, - expectedStatus: objectStorageBaseUrl ? HttpStatusCode.FOUND_302 : HttpStatusCode.OK_200 - }) - ]) - } - - expect(file.resolution.id).to.equal(attributeFile.resolution) - - if (file.resolution.id === VideoResolution.H_NOVIDEO) { - expect(file.resolution.label).to.equal('Audio') - } else { - expect(file.resolution.label).to.equal(attributeFile.resolution + 'p') - } - - if (attributeFile.size) { - const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) - const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) - expect( - file.size, - 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')' - ).to.be.above(minSize).and.below(maxSize) - } - - await checkWebTorrentWorks(file.magnetUri) - } -} - -async function completeVideoCheck (options: { - server: PeerTubeServer - originServer: PeerTubeServer - videoUUID: string - attributes: { - name: string - category: number - licence: number - language: string - nsfw: boolean - commentsEnabled: boolean - downloadEnabled: boolean - description: string - publishedAt?: string - support: string - originallyPublishedAt?: string - account: { - name: string - host: string - } - isLocal: boolean - tags: string[] - privacy: number - likes?: number - dislikes?: number - duration: number - channel: { - displayName: string - name: string - description: string - isLocal: boolean - } - fixture: string - files: { - resolution: number - size: number - }[] - thumbnailfile?: string - previewfile?: string - } -}) { - const { attributes, originServer, server, videoUUID } = options - - const video = await server.videos.get({ id: videoUUID }) - - if (!attributes.likes) attributes.likes = 0 - if (!attributes.dislikes) attributes.dislikes = 0 - - expect(video.name).to.equal(attributes.name) - expect(video.category.id).to.equal(attributes.category) - expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Unknown') - expect(video.licence.id).to.equal(attributes.licence) - expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown') - expect(video.language.id).to.equal(attributes.language) - expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown') - expect(video.privacy.id).to.deep.equal(attributes.privacy) - expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy]) - expect(video.nsfw).to.equal(attributes.nsfw) - expect(video.description).to.equal(attributes.description) - expect(video.account.id).to.be.a('number') - expect(video.account.host).to.equal(attributes.account.host) - expect(video.account.name).to.equal(attributes.account.name) - expect(video.channel.displayName).to.equal(attributes.channel.displayName) - expect(video.channel.name).to.equal(attributes.channel.name) - expect(video.likes).to.equal(attributes.likes) - expect(video.dislikes).to.equal(attributes.dislikes) - expect(video.isLocal).to.equal(attributes.isLocal) - expect(video.duration).to.equal(attributes.duration) - expect(video.url).to.contain(originServer.host) - expect(dateIsValid(video.createdAt)).to.be.true - expect(dateIsValid(video.publishedAt)).to.be.true - expect(dateIsValid(video.updatedAt)).to.be.true - - if (attributes.publishedAt) { - expect(video.publishedAt).to.equal(attributes.publishedAt) - } - - if (attributes.originallyPublishedAt) { - expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt) - } else { - expect(video.originallyPublishedAt).to.be.null - } - - expect(video.files).to.have.lengthOf(attributes.files.length) - expect(video.tags).to.deep.equal(attributes.tags) - expect(video.account.name).to.equal(attributes.account.name) - expect(video.account.host).to.equal(attributes.account.host) - expect(video.channel.displayName).to.equal(attributes.channel.displayName) - expect(video.channel.name).to.equal(attributes.channel.name) - expect(video.channel.host).to.equal(attributes.account.host) - expect(video.channel.isLocal).to.equal(attributes.channel.isLocal) - expect(dateIsValid(video.channel.createdAt.toString())).to.be.true - expect(dateIsValid(video.channel.updatedAt.toString())).to.be.true - expect(video.commentsEnabled).to.equal(attributes.commentsEnabled) - expect(video.downloadEnabled).to.equal(attributes.downloadEnabled) - - expect(video.thumbnailPath).to.exist - await testImageGeneratedByFFmpeg(server.url, attributes.thumbnailfile || attributes.fixture, video.thumbnailPath) - - if (attributes.previewfile) { - expect(video.previewPath).to.exist - await testImageGeneratedByFFmpeg(server.url, attributes.previewfile, video.previewPath) - } - - await completeWebVideoFilesCheck({ server, originServer, videoUUID: video.uuid, ...pick(attributes, [ 'fixture', 'files' ]) }) -} - -async function checkVideoFilesWereRemoved (options: { - server: PeerTubeServer - video: VideoDetails - captions?: VideoCaption[] - onlyVideoFiles?: boolean // default false -}) { - const { video, server, captions = [], onlyVideoFiles = false } = options - - const webVideoFiles = video.files || [] - const hlsFiles = video.streamingPlaylists[0]?.files || [] - - const thumbnailName = basename(video.thumbnailPath) - const previewName = basename(video.previewPath) - - const torrentNames = webVideoFiles.concat(hlsFiles).map(f => basename(f.torrentUrl)) - - const captionNames = captions.map(c => basename(c.captionPath)) - - const webVideoFilenames = webVideoFiles.map(f => basename(f.fileUrl)) - const hlsFilenames = hlsFiles.map(f => basename(f.fileUrl)) - - let directories: { [ directory: string ]: string[] } = { - videos: webVideoFilenames, - redundancy: webVideoFilenames, - [join('playlists', 'hls')]: hlsFilenames, - [join('redundancy', 'hls')]: hlsFilenames - } - - if (onlyVideoFiles !== true) { - directories = { - ...directories, - - thumbnails: [ thumbnailName ], - previews: [ previewName ], - torrents: torrentNames, - captions: captionNames - } - } - - for (const directory of Object.keys(directories)) { - const directoryPath = server.servers.buildDirectory(directory) - - const directoryExists = await pathExists(directoryPath) - if (directoryExists === false) continue - - const existingFiles = await readdir(directoryPath) - for (const existingFile of existingFiles) { - for (const shouldNotExist of directories[directory]) { - expect(existingFile, `File ${existingFile} should not exist in ${directoryPath}`).to.not.contain(shouldNotExist) - } - } - } -} - -async function saveVideoInServers (servers: PeerTubeServer[], uuid: string) { - for (const server of servers) { - server.store.videoDetails = await server.videos.get({ id: uuid }) - } -} - -function checkUploadVideoParam (options: { - server: PeerTubeServer - token: string - attributes: Partial - expectedStatus?: HttpStatusCode - completedExpectedStatus?: HttpStatusCode - mode?: 'legacy' | 'resumable' -}) { - const { server, token, attributes, completedExpectedStatus, expectedStatus, mode = 'legacy' } = options - - return mode === 'legacy' - ? server.videos.buildLegacyUpload({ token, attributes, expectedStatus: expectedStatus || completedExpectedStatus }) - : server.videos.buildResumeUpload({ - token, - attributes, - expectedStatus, - completedExpectedStatus, - path: '/api/v1/videos/upload-resumable' - }) -} - -// serverNumber starts from 1 -async function uploadRandomVideoOnServers ( - servers: PeerTubeServer[], - serverNumber: number, - additionalParams?: VideoEdit & { prefixName?: string } -) { - const server = servers.find(s => s.serverNumber === serverNumber) - const res = await server.videos.randomUpload({ wait: false, additionalParams }) - - await waitJobs(servers) - - return res -} - -// --------------------------------------------------------------------------- - -export { - completeVideoCheck, - completeWebVideoFilesCheck, - checkUploadVideoParam, - uploadRandomVideoOnServers, - checkVideoFilesWereRemoved, - saveVideoInServers -} diff --git a/server/tests/shared/views.ts b/server/tests/shared/views.ts deleted file mode 100644 index e6b289715..000000000 --- a/server/tests/shared/views.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { FfmpegCommand } from 'fluent-ffmpeg' -import { wait } from '@shared/core-utils' -import { VideoCreateResult, VideoPrivacy } from '@shared/models' -import { - createMultipleServers, - doubleFollow, - PeerTubeServer, - setAccessTokensToServers, - setDefaultVideoChannel, - waitJobs, - waitUntilLivePublishedOnAllServers -} from '@shared/server-commands' - -async function processViewersStats (servers: PeerTubeServer[]) { - await wait(6000) - - for (const server of servers) { - await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) - await server.debug.sendCommand({ body: { command: 'process-video-viewers' } }) - } - - await waitJobs(servers) -} - -async function processViewsBuffer (servers: PeerTubeServer[]) { - for (const server of servers) { - await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) - } - - await waitJobs(servers) -} - -async function prepareViewsServers () { - const servers = await createMultipleServers(2) - await setAccessTokensToServers(servers) - await setDefaultVideoChannel(servers) - - await servers[0].config.updateCustomSubConfig({ - newConfig: { - live: { - enabled: true, - allowReplay: true, - transcoding: { - enabled: false - } - } - } - }) - - await doubleFollow(servers[0], servers[1]) - - return servers -} - -async function prepareViewsVideos (options: { - servers: PeerTubeServer[] - live: boolean - vod: boolean -}) { - const { servers } = options - - const liveAttributes = { - name: 'live video', - channelId: servers[0].store.channel.id, - privacy: VideoPrivacy.PUBLIC - } - - let ffmpegCommand: FfmpegCommand - let live: VideoCreateResult - let vod: VideoCreateResult - - if (options.live) { - live = await servers[0].live.create({ fields: liveAttributes }) - - ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: live.uuid }) - await waitUntilLivePublishedOnAllServers(servers, live.uuid) - } - - if (options.vod) { - vod = await servers[0].videos.quickUpload({ name: 'video' }) - } - - await waitJobs(servers) - - return { liveVideoId: live?.uuid, vodVideoId: vod?.uuid, ffmpegCommand } -} - -export { - processViewersStats, - prepareViewsServers, - processViewsBuffer, - prepareViewsVideos -} diff --git a/server/tests/shared/webtorrent.ts b/server/tests/shared/webtorrent.ts deleted file mode 100644 index d5bd86500..000000000 --- a/server/tests/shared/webtorrent.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { expect } from 'chai' -import { readFile } from 'fs-extra' -import parseTorrent from 'parse-torrent' -import { basename, join } from 'path' -import * as WebTorrent from 'webtorrent' -import { VideoFile } from '@shared/models' -import { PeerTubeServer } from '@shared/server-commands' - -let webtorrent: WebTorrent.Instance - -export async function checkWebTorrentWorks (magnetUri: string, pathMatch?: RegExp) { - const torrent = await webtorrentAdd(magnetUri, true) - - expect(torrent.files).to.be.an('array') - expect(torrent.files.length).to.equal(1) - expect(torrent.files[0].path).to.exist.and.to.not.equal('') - - if (pathMatch) { - expect(torrent.files[0].path).match(pathMatch) - } -} - -export async function parseTorrentVideo (server: PeerTubeServer, file: VideoFile) { - const torrentName = basename(file.torrentUrl) - const torrentPath = server.servers.buildDirectory(join('torrents', torrentName)) - - const data = await readFile(torrentPath) - - return parseTorrent(data) -} - -// --------------------------------------------------------------------------- -// Private -// --------------------------------------------------------------------------- - -function webtorrentAdd (torrentId: string, refreshWebTorrent = false) { - const WebTorrent = require('webtorrent') - - if (webtorrent && refreshWebTorrent) webtorrent.destroy() - if (!webtorrent || refreshWebTorrent) webtorrent = new WebTorrent() - - webtorrent.on('error', err => console.error('Error in webtorrent', err)) - - return new Promise(res => { - const torrent = webtorrent.add(torrentId, res) - - torrent.on('error', err => console.error('Error in webtorrent torrent', err)) - torrent.on('warning', warn => { - const msg = typeof warn === 'string' - ? warn - : warn.message - - if (msg.includes('Unsupported')) return - - console.error('Warning in webtorrent torrent', warn) - }) - }) -} -- cgit v1.2.3