{ pkgs, self }: let lib = pkgs.lib; rebuildableTest = import ./rebuildableTest.nix pkgs; email = "test@test.com"; password = "testtest"; # FIXME: Replace all the By.XPATH by By.CSS_SELECTOR. seleniumImports = '' import sys from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options ''; seleniumSetup = '' print("Create and configure driver...", file=sys.stderr) options = Options() # options.add_argument("--headless=new") service = webdriver.ChromeService(executable_path="${lib.getExe pkgs.chromedriver}") # noqa: E501 driver = webdriver.Chrome(options=options, service=service) driver.implicitly_wait(30) driver.set_window_size(1280, 960) ''; seleniumPixelfedLogin = '' print("Open login page...", file=sys.stderr) driver.get("http://pixelfed.localhost/login") print("Enter email...", file=sys.stderr) driver.find_element(By.ID, "email").send_keys("${email}") print("Enter password...", file=sys.stderr) driver.find_element(By.ID, "password").send_keys("${password}") # FIXME: This is disgusting. Find instead the input type submit in the form # with action ending in "/login". print("Click “Login” button...", file=sys.stderr) driver.find_element(By.XPATH, "//button[normalize-space()='Login']").click() ''; ## NOTE: `path` must be a valid python string, either a variable or _quoted_. seleniumTakeScreenshot = path: '' print("Take screenshot...", file=sys.stderr) if not driver.save_screenshot(${path}): raise Exception("selenium could not save screenshot") ''; seleniumQuit = '' print("Quitting...", file=sys.stderr) driver.quit() ''; seleniumScriptPostPicture = pkgs.writers.writePython3Bin "selenium-script-post-picture" { libraries = with pkgs.python3Packages; [ selenium ]; } '' import os import time ${seleniumImports} from selenium.webdriver.support.wait import WebDriverWait ${seleniumSetup} ${seleniumPixelfedLogin} time.sleep(3) media_path = os.environ['POST_MEDIA'] # Find the new post form, fill it in with our pictureand a caption. print("Click on “Create New Post”...", file=sys.stderr) driver.find_element(By.LINK_TEXT, "Create New Post").click() print("Add file to input element...", file=sys.stderr) driver.find_element(By.XPATH, "//input[@type='file']").send_keys(media_path) print("Add a caption", file=sys.stderr) driver.find_element(By.CSS_SELECTOR, ".media-body textarea").send_keys( "Fediversity test of image upload to pixelfed with garage storage." ) time.sleep(3) print("Click on “Post” button...", file=sys.stderr) driver.find_element(By.LINK_TEXT, "Post").click() # Wait until the post loads, and in particular its picture, then take a # screenshot of the whole page. print("Wait for post and image to be loaded...", file=sys.stderr) img = driver.find_element( By.XPATH, "//div[@class='timeline-status-component-content']//img" ) WebDriverWait(driver, timeout=10).until( lambda d: d.execute_script("return arguments[0].complete", img) ) time.sleep(3) ${seleniumTakeScreenshot "\"/home/selenium/screenshot.png\""} ${seleniumQuit}''; seleniumScriptGetSrc = pkgs.writers.writePython3Bin "selenium-script-get-src" { libraries = with pkgs.python3Packages; [ selenium ]; } '' ${seleniumImports} ${seleniumSetup} ${seleniumPixelfedLogin} img = driver.find_element( By.XPATH, "//div[@class='timeline-status-component-content']//img" ) # REVIEW: Need to wait for it to be loaded? print(img.get_attribute('src')) ${seleniumQuit}''; in pkgs.nixosTest { name = "test-pixelfed-garage"; nodes = { server = { config, ... }: { services = { xserver = { enable = true; displayManager.lightdm.enable = true; desktopManager.lxqt.enable = true; }; displayManager.autoLogin = { enable = true; user = "selenium"; }; }; virtualisation.resolution = { x = 1680; y = 1050; }; virtualisation = { memorySize = lib.mkVMOverride 8192; cores = 8; }; imports = with self.nixosModules; [ garage pixelfed pixelfed-vm ]; # TODO: pair down environment.systemPackages = with pkgs; [ python3 chromium chromedriver xh seleniumScriptPostPicture seleniumScriptGetSrc helix imagemagick ]; environment.variables = { POST_MEDIA = ./fediversity.png; AWS_ACCESS_KEY_ID = config.services.garage.ensureKeys.pixelfed.id; AWS_SECRET_ACCESS_KEY = config.services.garage.ensureKeys.pixelfed.secret; }; # chrome does not like being run as root users.users.selenium = { isNormalUser = true; }; }; }; testScript = '' import re server.start() with subtest("Pixelfed starts"): server.wait_for_unit("phpfpm-pixelfed.service") with subtest("Account creation"): server.succeed("pixelfed-manage user:create --name=test --username=test --email=${email} --password=${password} --confirm_email=1") # NOTE: This could in theory give a false positive if pixelfed changes it's # colorscheme to include pure green. (see same problem in pixelfed-garage.nix). # TODO: For instance: post a red image and check that the green pixel IS NOT # there, then post a green image and check that the green pixel IS there. with subtest("Image displays"): server.succeed("su - selenium -c 'selenium-script-post-picture ${email} ${password}'") server.copy_from_vm("/home/selenium/screenshot.png", "") displayed_colors = server.succeed("magick /home/selenium/screenshot.png -define histogram:unique-colors=true -format %c histogram:info:") # check that the green image displayed somewhere image_check = re.match(".*#FF0500.*", displayed_colors, re.S) if image_check is None: raise Exception("cannot detect the uploaded image on pixelfed page.") with subtest("access garage"): server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY") server.succeed("mc ls garage/pixelfed") with subtest("access image in garage"): image = server.succeed("mc find garage --regex '\\.png' --ignore '*_thumb.png'") image = image.rstrip() if image == "": raise Exception("image posted to mastodon did not get stored in garage") server.succeed(f"mc cat {image} >/garage-image.png") garage_image_hash = server.succeed("identify -quiet -format '%#' /garage-image.png") image_hash = server.succeed("identify -quiet -format '%#' $POST_MEDIA") if garage_image_hash != image_hash: raise Exception("image stored in garage did not match image uploaded") with subtest("Check that image comes from garage"): src = server.succeed("su - selenium -c 'selenium-script-get-src ${email} ${password}'") if not src.startswith("http://pixelfed.web.garage.localhost:3902/"): raise Exception("image does not come from garage") ''; }