forked from fediversity/fediversity
		
	see Fediversity/Fediversity#395 (comment) Reviewed-on: Fediversity/Fediversity#396 Reviewed-by: Valentin Gagarin <valentin.gagarin@tweag.io> Co-authored-by: Kiara Grouwstra <kiara@procolix.eu> Co-committed-by: Kiara Grouwstra <kiara@procolix.eu>
		
			
				
	
	
		
			233 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
## This file is a basic test of Peertube functionalities.
 | 
						|
 | 
						|
{ pkgs, ... }:
 | 
						|
 | 
						|
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 = [ "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
 | 
						|
 | 
						|
        options = Options()
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("A", file=sys.stderr)
 | 
						|
        options.add_argument("--headless")
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("B", file=sys.stderr)
 | 
						|
        service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}")
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("C", file=sys.stderr)
 | 
						|
        driver = webdriver.Firefox(options=options, service=service)
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("D", file=sys.stderr)
 | 
						|
        driver.set_window_size(4096, 2160)
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("E", file=sys.stderr)
 | 
						|
        driver.implicitly_wait(360)
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
        print("F", file=sys.stderr)
 | 
						|
        wait = WebDriverWait(driver, timeout=360, poll_frequency=10)
 | 
						|
        print("########################################", file=sys.stderr)
 | 
						|
 | 
						|
        ############################################################
 | 
						|
        # 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
 | 
						|
        #     return bool(re.match(".*#${testVideoColour}.*", displayed_colours, re.S))
 | 
						|
        #
 | 
						|
        # 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
 | 
						|
 | 
						|
{
 | 
						|
  name = "peertube";
 | 
						|
 | 
						|
  nodes = {
 | 
						|
    server =
 | 
						|
      { config, ... }:
 | 
						|
      {
 | 
						|
        imports = [
 | 
						|
          ../fediversity
 | 
						|
          ../vm/garage-vm.nix
 | 
						|
          ../vm/peertube-vm.nix
 | 
						|
          ../vm/interactive-vm.nix
 | 
						|
        ];
 | 
						|
 | 
						|
        virtualisation = {
 | 
						|
          memorySize = lib.mkVMOverride 8192;
 | 
						|
          cores = 8;
 | 
						|
        };
 | 
						|
 | 
						|
        environment.systemPackages = with pkgs; [
 | 
						|
          python3
 | 
						|
          firefox-unwrapped
 | 
						|
          geckodriver
 | 
						|
          toot
 | 
						|
          acquireRootPassword
 | 
						|
          postVideoInBrowser
 | 
						|
          imagemagick
 | 
						|
          ffmpeg # to identify videos
 | 
						|
          expect
 | 
						|
        ];
 | 
						|
 | 
						|
        ## 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;
 | 
						|
 | 
						|
        environment.variables = {
 | 
						|
          AWS_ACCESS_KEY_ID = "$(cat ${config.fediversity.peertube.s3AccessKeyFile})";
 | 
						|
          AWS_SECRET_ACCESS_KEY = "$(cat ${config.fediversity.peertube.s3SecretKeyFile})";
 | 
						|
          PT_INITIAL_ROOT_PASSWORD = "testtest";
 | 
						|
        };
 | 
						|
      };
 | 
						|
  };
 | 
						|
 | 
						|
  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.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.")
 | 
						|
    '';
 | 
						|
}
 |