forked from fediversity/fediversity
		
	Add a test for Peertube (#45)
This commit is contained in:
		
						commit
						e8b7c23366
					
				
					 8 changed files with 270 additions and 8 deletions
				
			
		|  | @ -21,3 +21,9 @@ jobs: | |||
|       - uses: actions/checkout@v4 | ||||
|       - run: cd website && nix-build -A tests | ||||
|       - run: cd website && nix-build -A build | ||||
| 
 | ||||
|   check-peertube: | ||||
|     runs-on: native | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - run: nix build .#checks.x86_64-linux.peertube -L | ||||
|  |  | |||
							
								
								
									
										6
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							|  | @ -836,11 +836,11 @@ | |||
|     }, | ||||
|     "nixpkgs_6": { | ||||
|       "locked": { | ||||
|         "lastModified": 1732350895, | ||||
|         "narHash": "sha256-GcOQbOgmwlsRhpLGSwZJwLbo3pu9ochMETuRSS1xpz4=", | ||||
|         "lastModified": 1734323986, | ||||
|         "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=", | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "0c582677378f2d9ffcb01490af2f2c678dcb29d3", | ||||
|         "rev": "394571358ce82dff7411395829aa6a3aad45b907", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  |  | |||
|  | @ -11,6 +11,10 @@ lib.mkIf (config.fediversity.enable && config.fediversity.peertube.enable) { | |||
|   networking.firewall.allowedTCPPorts = [ | ||||
|     80 | ||||
|     443 | ||||
| 
 | ||||
|     ## For Live streaming and Live streaming when RTMPS is enabled. | ||||
|     1935 | ||||
|     1936 | ||||
|   ]; | ||||
| 
 | ||||
|   services.garage = { | ||||
|  | @ -70,6 +74,8 @@ lib.mkIf (config.fediversity.enable && config.fediversity.peertube.enable) { | |||
|         enabled = true; | ||||
|         endpoint = config.fediversity.internal.garage.api.url; | ||||
|         region = "garage"; | ||||
|         upload_acl.public = null; # Garage does not support ACL | ||||
|         upload_acl.private = null; # Garage does not support ACL | ||||
| 
 | ||||
|         # not supported by garage | ||||
|         # SEE: https://garagehq.deuxfleurs.fr/documentation/connect/apps/#peertube | ||||
|  | @ -101,7 +107,11 @@ lib.mkIf (config.fediversity.enable && config.fediversity.peertube.enable) { | |||
| 
 | ||||
|   ## Proxying through Nginx | ||||
| 
 | ||||
|   services.peertube.configureNginx = true; | ||||
|   services.peertube = { | ||||
|     configureNginx = true; | ||||
|     listenWeb = 443; | ||||
|     enableWebHttps = true; | ||||
|   }; | ||||
|   services.nginx.virtualHosts.${config.services.peertube.localDomain} = { | ||||
|     forceSSL = true; | ||||
|     enableACME = true; | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
|       checks = { | ||||
|         mastodon = import ./tests/mastodon.nix { inherit self pkgs; }; | ||||
|         pixelfed-garage = import ./tests/pixelfed-garage.nix { inherit self pkgs; }; | ||||
|         peertube = import ./tests/peertube.nix { inherit self pkgs; }; | ||||
|       }; | ||||
|     }; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								services/tests/green.mp4
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								services/tests/green.mp4
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -43,7 +43,7 @@ let | |||
| in | ||||
| 
 | ||||
| pkgs.nixosTest { | ||||
|   name = "test-mastodon-garage"; | ||||
|   name = "mastodon"; | ||||
| 
 | ||||
|   nodes = { | ||||
|     server = | ||||
|  |  | |||
							
								
								
									
										233
									
								
								services/tests/peertube.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								services/tests/peertube.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,233 @@ | |||
| ## This file is a basic test of Peertube functionalities. | ||||
| 
 | ||||
| { 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 = [ "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 | ||||
| 
 | ||||
| pkgs.nixosTest { | ||||
|   name = "peertube"; | ||||
| 
 | ||||
|   nodes = { | ||||
|     server = | ||||
|       { config, ... }: | ||||
|       { | ||||
|         imports = with self.nixosModules; [ | ||||
|           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 = config.services.garage.ensureKeys.peertube.id; | ||||
|           AWS_SECRET_ACCESS_KEY = config.services.garage.ensureKeys.peertube.secret; | ||||
|           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.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.") | ||||
|     ''; | ||||
| } | ||||
|  | @ -1,11 +1,23 @@ | |||
| { modulesPath, ... }: | ||||
| { | ||||
|   modulesPath, | ||||
|   pkgs, | ||||
|   ... | ||||
| }: | ||||
| 
 | ||||
| { | ||||
| 
 | ||||
|   imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ]; | ||||
| 
 | ||||
|   fediversity = { | ||||
|     enable = true; | ||||
|     domain = "localhost"; | ||||
|     peertube.enable = true; | ||||
| 
 | ||||
|     temp.peertubeSecretsFile = pkgs.writeText "secret" '' | ||||
|       574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24 | ||||
|     ''; | ||||
|   }; | ||||
| 
 | ||||
|   services.peertube = { | ||||
|     enableWebHttps = false; | ||||
|     settings = { | ||||
|       listen.hostname = "0.0.0.0"; | ||||
|       instance.name = "PeerTube Test VM"; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue