Fediversity/services/tests/peertube.nix

222 lines
8.4 KiB
Nix

## This file is a basic test of Peertube functionalities.
##
## NOTE: This test needs Peertube >= 6.3.
{ pkgs, self }:
let
lib = pkgs.lib;
testVideo = pkgs.copyPathToStore ./green.mp4;
testVideoColour = "#00FF00";
postVideoInBrowser =
pkgs.writers.writePython3Bin "post-video-in-browser"
{
libraries = with pkgs.python3Packages; [ selenium ];
flakeIgnore = [
"E302"
"E305"
"E501" # welcome to the 21st century
];
}
''
import sys
from urllib.parse import urlparse
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
print("Create and configure driver...", file=sys.stderr)
options = Options()
options.add_argument("--headless")
service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}")
driver = webdriver.Firefox(options=options, service=service)
driver.set_window_size(4096, 2160)
driver.implicitly_wait(360)
wait = WebDriverWait(driver, timeout=360, poll_frequency=10)
############################################################
# Login
def load(driver, page):
print(f"Loading page {page}...", file=sys.stderr)
driver.get(page)
print("Waiting until page is loaded...", file=sys.stderr)
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
if urlparse(driver.current_url).path == "/login":
print("Hit a login page.", file=sys.stderr)
print("Enter username...", file=sys.stderr)
driver.find_element(By.ID, "username").send_keys("root")
print("Enter password...", file=sys.stderr)
driver.find_element(By.ID, "password").send_keys(sys.argv[1])
print("Click Login button...", file=sys.stderr)
driver.find_element(By.XPATH, "//input[@value='Login']").click()
print("Waiting until we are logged-in...", file=sys.stderr)
wait.until(lambda d: urlparse(d.current_url).path == urlparse(page).path)
print("Waiting until page is loaded...", file=sys.stderr)
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
print("Clicking the annoying setup wizard away...", file=sys.stderr)
try:
driver.find_element(By.XPATH, "//input[@value='Remind me later']").click()
except NoSuchElementException:
# Somehow, sometimes, the wizard just does not show up; then we
# ignore the error and carry on like nothing happened.
print("Setup wizard did not show up.", file=sys.stderr)
print(f"Done loading page {page}.", file=sys.stderr)
############################################################
# Upload video and take a screenshot
print("Go to the upload page...", file=sys.stderr)
load(driver, "http://peertube.localhost/videos/upload")
print("Submit video file...", file=sys.stderr)
driver.find_element(By.XPATH, "//input[@type='file']").send_keys("${testVideo}")
print("Wait for file to upload, then publish it...", file=sys.stderr)
publish_button = driver.find_element(By.XPATH, "//button[.//span[normalize-space()='Publish']]")
wait.until(lambda _d: "disabled" not in publish_button.get_attribute("class"))
publish_button.click()
print("Waiting until we are redirected...", file=sys.stderr)
wait.until(lambda d: urlparse(d.current_url).path != "/videos/upload")
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
# FIXME: The video cannot play and we get Failed to play video. I
# believe it is a codec problem, and it possibly has to do with video
# codecs enabled in Firefox in headless mode -- after all, who would
# want to play a video? The following is a list of things that I have
# tried without success. Maybe one day we can manage?
#
# video = driver.find_element(By.XPATH, "//video")
# wait.until(lambda _d: not video.get_attribute("src").startswith("blob:"))
# wait.until(lambda d: d.execute_script("return arguments[0].readyState", video) == 4)
# driver.find_element(By.XPATH, "//*[contains(text(), 'Failed to play video')]")
#
# def detect_image_in_screen(d):
# print(" Taking a screenshot...", file=sys.stderr)
# d.save_screenshot("/screenshot.png")
# print(" Checking it...", file=sys.stderr)
# displayed_colours = subprocess.run(
# [
# "magick",
# "/screenshot.png",
# "-define",
# "histogram:unique-colors=true",
# "-format",
# "%c",
# "histogram:info:",
# ],
# capture_output=True,
# text=True,
# check=True,
# ).stdout
# result = bool(re.search("${testVideoColour}", displayed_colours, re.IGNORECASE))
# if not result:
# print(" Could not find the video in the screenshot.", file=sys.stderr)
# return result
#
# print("Wait until the image shows in screen...", file=sys.stderr)
# wait.until(detect_image_in_screen)
############################################################
print("Done; bye!", file=sys.stderr)
driver.close()
'';
acquireRootPassword = pkgs.writeShellScriptBin "acquire-root-password" ''
readonly retry=30
readonly wait=60
for _ in $(seq $retry); do
password=$(journalctl -u peertube | perl -ne '/password: (.*)/ && print $1')
if [ -n "$password" ]; then
echo "$password"
exit 0
fi
sleep $wait
done
echo "Could not acquire root password in $((retry * wait))s."
exit 1
'';
in
pkgs.nixosTest {
name = "peertube";
nodes = {
server =
{ config, ... }:
{
imports = with self.nixosModules; [
fediversity
../vm/garage-vm.nix
../vm/peertube-vm.nix
../vm/interactive-vm.nix
];
environment.systemPackages = with pkgs; [
python3
firefox-unwrapped
geckodriver
toot
acquireRootPassword
postVideoInBrowser
imagemagick
ffmpeg # to identify videos
expect
];
environment.variables = {
AWS_ACCESS_KEY_ID = config.services.garage.ensureKeys.peertube.id;
AWS_SECRET_ACCESS_KEY = config.services.garage.ensureKeys.peertube.secret;
PT_INITIAL_ROOT_PASSWORD = "testtest";
};
## FIXME: The CI is very slow, so the default timeout of 120s is not
## good enough. We bump it drastically.
systemd.services.postgresql.serviceConfig.TimeoutSec = lib.mkForce 3600;
};
};
testScript =
{ nodes, ... }:
''
server.start()
# FIXME: I think this trick to look for a password can be replaced by
# services.peertube.serviceEnvironmentFile.PT_INITIAL_ROOT_PASSWORD=testtest
with subtest("Peertube starts"):
server.wait_for_unit("peertube.service")
root_password = server.succeed("acquire-root-password").rstrip()
with subtest("Post a video in the browser"):
server.succeed(f"post-video-in-browser {root_password}")
with subtest("Find video in garage"):
server.succeed("mc alias set garage ${nodes.server.fediversity.internal.garage.api.url} --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY")
video = server.succeed("mc find garage --regex '\\.mp4'").rstrip()
if video == "":
raise Exception("Could not find any .mp4 video stored in Garage")
server.succeed(f"mc cat {video} > /video.mp4")
garage_hash = server.succeed("identify -quiet -format '%#' /video.mp4")
hash = server.succeed("identify -quiet -format '%#' ${testVideo}")
if garage_hash != hash:
raise Exception("The video stored in Garage does not correspond to the original one.")
'';
}