import ./make-test-python.nix ( { pkgs, lib, ... }: { name = "castopod"; meta = with lib.maintainers; { maintainers = [ alexoundos ]; }; nodes.castopod = { nodes, ... }: { # otherwise 500 MiB file upload fails! virtualisation.diskSize = 512 + 3 * 512; networking.firewall.allowedTCPPorts = [ 80 ]; networking.extraHosts = lib.strings.concatStringsSep "\n" ( lib.attrsets.mapAttrsToList ( name: _: "127.0.0.1 ${name}" ) nodes.castopod.services.nginx.virtualHosts ); services.castopod = { enable = true; database.createLocally = true; localDomain = "castopod.example.com"; maxUploadSize = "512M"; }; }; nodes.client = { nodes, pkgs, lib, ... }: let domain = nodes.castopod.services.castopod.localDomain; getIP = node: (builtins.head node.networking.interfaces.eth1.ipv4.addresses).address; targetPodcastSize = 500 * 1024 * 1024; lameMp3Bitrate = 348300; lameMp3FileAdjust = -800; targetPodcastDuration = toString ((targetPodcastSize + lameMp3FileAdjust) / (lameMp3Bitrate / 8)); bannerWidth = 3000; banner = pkgs.runCommand "gen-castopod-cover.jpg" { } '' ${pkgs.imagemagick}/bin/magick ` `-background green -bordercolor white -gravity northwest xc:black ` `-duplicate 99 ` `-seed 1 -resize "%[fx:rand()*72+24]" ` `-seed 0 -rotate "%[fx:rand()*360]" -border 6x6 -splice 16x36 ` `-seed 0 -rotate "%[fx:floor(rand()*4)*90]" -resize "150x50!" ` `+append -crop 10x1@ +repage -roll "+%[fx:(t%2)*72]+0" -append ` `-resize ${toString bannerWidth} -quality 1 $out ''; coverWidth = toString 3000; cover = pkgs.runCommand "gen-castopod-banner.jpg" { } '' ${pkgs.imagemagick}/bin/magick ` `-background white -bordercolor white -gravity northwest xc:black ` `-duplicate 99 ` `-seed 1 -resize "%[fx:rand()*72+24]" ` `-seed 0 -rotate "%[fx:rand()*360]" -border 6x6 -splice 36x36 ` `-seed 0 -rotate "%[fx:floor(rand()*4)*90]" -resize "144x144!" ` `+append -crop 10x1@ +repage -roll "+%[fx:(t%2)*72]+0" -append ` `-resize ${coverWidth} -quality 1 $out ''; in { networking.extraHosts = lib.strings.concatStringsSep "\n" ( lib.attrsets.mapAttrsToList ( name: _: "${getIP nodes.castopod} ${name}" ) nodes.castopod.services.nginx.virtualHosts ); environment.systemPackages = let username = "admin"; email = "admin@${domain}"; password = "Abcd1234"; podcastTitle = "Some Title"; episodeTitle = "Episode Title"; browser-test = pkgs.writers.writePython3Bin "browser-test" { libraries = [ pkgs.python3Packages.selenium ]; flakeIgnore = [ "E124" "E501" ]; } '' from selenium.webdriver.common.by import By from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options from selenium.webdriver.firefox.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from subprocess import STDOUT import logging selenium_logger = logging.getLogger("selenium") selenium_logger.setLevel(logging.DEBUG) selenium_logger.addHandler(logging.StreamHandler()) options = Options() options.add_argument('--headless') service = Service(log_output=STDOUT) driver = Firefox(options=options, service=service) driver = Firefox(options=options) driver.implicitly_wait(30) driver.set_page_load_timeout(60) # install ########################################################## driver.get('http://${domain}/cp-install') wait = WebDriverWait(driver, 20) wait.until(EC.title_contains("installer")) driver.find_element(By.CSS_SELECTOR, '#username').send_keys( '${username}' ) driver.find_element(By.CSS_SELECTOR, '#email').send_keys( '${email}' ) driver.find_element(By.CSS_SELECTOR, '#password').send_keys( '${password}' ) driver.find_element(By.XPATH, "//button[contains(., 'Finish install')]" ).click() wait.until(EC.title_contains("Auth")) driver.find_element(By.CSS_SELECTOR, '#email').send_keys( '${email}' ) driver.find_element(By.CSS_SELECTOR, '#password').send_keys( '${password}' ) driver.find_element(By.XPATH, "//button[contains(., 'Login')]" ).click() wait.until(EC.title_contains("Admin dashboard")) # create podcast ################################################### driver.get('http://${domain}/admin/podcasts/new') wait.until(EC.title_contains("Create podcast")) driver.find_element(By.CSS_SELECTOR, '#cover').send_keys( '${cover}' ) driver.find_element(By.CSS_SELECTOR, '#banner').send_keys( '${banner}' ) driver.find_element(By.CSS_SELECTOR, '#title').send_keys( '${podcastTitle}' ) driver.find_element(By.CSS_SELECTOR, '#handle').send_keys( 'some_handle' ) driver.find_element(By.CSS_SELECTOR, '#description').send_keys( 'Some description' ) driver.find_element(By.CSS_SELECTOR, '#owner_name').send_keys( 'Owner Name' ) driver.find_element(By.CSS_SELECTOR, '#owner_email').send_keys( 'owner@email.xyz' ) driver.find_element(By.XPATH, "//button[contains(., 'Create podcast')]" ).click() wait.until(EC.title_contains("${podcastTitle}")) driver.find_element(By.XPATH, "//span[contains(., 'Add an episode')]" ).click() wait.until(EC.title_contains("Add an episode")) # upload podcast ################################################### driver.find_element(By.CSS_SELECTOR, '#audio_file').send_keys( '/tmp/podcast.mp3' ) driver.find_element(By.CSS_SELECTOR, '#cover').send_keys( '${cover}' ) driver.find_element(By.CSS_SELECTOR, '#description').send_keys( 'Episode description' ) driver.find_element(By.CSS_SELECTOR, '#title').send_keys( '${episodeTitle}' ) driver.find_element(By.XPATH, "//button[contains(., 'Create episode')]" ).click() wait.until(EC.title_contains("${episodeTitle}")) driver.close() driver.quit() ''; in [ pkgs.firefox-unwrapped pkgs.geckodriver browser-test (pkgs.writeShellApplication { name = "build-mp3"; runtimeInputs = with pkgs; [ sox lame ]; text = '' out=/tmp/podcast.mp3 sox -n -r 48000 -t wav - synth ${targetPodcastDuration} sine 440 ` `| lame --noreplaygain --cbr -q 9 -b 320 - $out FILESIZE="$(stat -c%s $out)" [ "$FILESIZE" -gt 0 ] [ "$FILESIZE" -le "${toString targetPodcastSize}" ] ''; }) ]; }; testScript = '' start_all() castopod.wait_for_unit("castopod-setup.service") castopod.wait_for_file("/run/phpfpm/castopod.sock") castopod.wait_for_unit("nginx.service") castopod.wait_for_open_port(80) castopod.wait_until_succeeds("curl -sS -f http://castopod.example.com") client.succeed("build-mp3") with subtest("Create superadmin, log in, create and upload a podcast"): client.succeed(\ "PYTHONUNBUFFERED=1 systemd-cat -t browser-test browser-test") ''; } )