at 24.11-pre 8.5 kB view raw
1import ./make-test-python.nix ({ pkgs, lib, ... }: 2{ 3 name = "castopod"; 4 meta = with lib.maintainers; { 5 maintainers = [ alexoundos ]; 6 }; 7 8 nodes.castopod = { nodes, ... }: { 9 # otherwise 500 MiB file upload fails! 10 virtualisation.diskSize = 512 + 3 * 512; 11 12 networking.firewall.allowedTCPPorts = [ 80 ]; 13 networking.extraHosts = 14 lib.strings.concatStringsSep "\n" 15 (lib.attrsets.mapAttrsToList 16 (name: _: "127.0.0.1 ${name}") 17 nodes.castopod.services.nginx.virtualHosts); 18 19 services.castopod = { 20 enable = true; 21 database.createLocally = true; 22 localDomain = "castopod.example.com"; 23 maxUploadSize = "512M"; 24 }; 25 }; 26 27 nodes.client = { nodes, pkgs, lib, ... }: 28 let 29 domain = nodes.castopod.services.castopod.localDomain; 30 31 getIP = node: 32 (builtins.head node.networking.interfaces.eth1.ipv4.addresses).address; 33 34 targetPodcastSize = 500 * 1024 * 1024; 35 lameMp3Bitrate = 348300; 36 lameMp3FileAdjust = -800; 37 targetPodcastDuration = toString 38 ((targetPodcastSize + lameMp3FileAdjust) / (lameMp3Bitrate / 8)); 39 bannerWidth = 3000; 40 banner = pkgs.runCommand "gen-castopod-cover.jpg" { } '' 41 ${pkgs.imagemagick}/bin/magick ` 42 `-background green -bordercolor white -gravity northwest xc:black ` 43 `-duplicate 99 ` 44 `-seed 1 -resize "%[fx:rand()*72+24]" ` 45 `-seed 0 -rotate "%[fx:rand()*360]" -border 6x6 -splice 16x36 ` 46 `-seed 0 -rotate "%[fx:floor(rand()*4)*90]" -resize "150x50!" ` 47 `+append -crop 10x1@ +repage -roll "+%[fx:(t%2)*72]+0" -append ` 48 `-resize ${toString bannerWidth} -quality 1 $out 49 ''; 50 51 coverWidth = toString 3000; 52 cover = pkgs.runCommand "gen-castopod-banner.jpg" { } '' 53 ${pkgs.imagemagick}/bin/magick ` 54 `-background white -bordercolor white -gravity northwest xc:black ` 55 `-duplicate 99 ` 56 `-seed 1 -resize "%[fx:rand()*72+24]" ` 57 `-seed 0 -rotate "%[fx:rand()*360]" -border 6x6 -splice 36x36 ` 58 `-seed 0 -rotate "%[fx:floor(rand()*4)*90]" -resize "144x144!" ` 59 `+append -crop 10x1@ +repage -roll "+%[fx:(t%2)*72]+0" -append ` 60 `-resize ${coverWidth} -quality 1 $out 61 ''; 62 in 63 { 64 networking.extraHosts = 65 lib.strings.concatStringsSep "\n" 66 (lib.attrsets.mapAttrsToList 67 (name: _: "${getIP nodes.castopod} ${name}") 68 nodes.castopod.services.nginx.virtualHosts); 69 70 environment.systemPackages = 71 let 72 username = "admin"; 73 email = "admin@${domain}"; 74 password = "Abcd1234"; 75 podcastTitle = "Some Title"; 76 episodeTitle = "Episode Title"; 77 browser-test = pkgs.writers.writePython3Bin "browser-test" 78 { 79 libraries = [ pkgs.python3Packages.selenium ]; 80 flakeIgnore = [ "E124" "E501" ]; 81 } '' 82 from selenium.webdriver.common.by import By 83 from selenium.webdriver import Firefox 84 from selenium.webdriver.firefox.options import Options 85 from selenium.webdriver.firefox.service import Service 86 from selenium.webdriver.support.ui import WebDriverWait 87 from selenium.webdriver.support import expected_conditions as EC 88 from subprocess import STDOUT 89 import logging 90 91 selenium_logger = logging.getLogger("selenium") 92 selenium_logger.setLevel(logging.DEBUG) 93 selenium_logger.addHandler(logging.StreamHandler()) 94 95 options = Options() 96 options.add_argument('--headless') 97 service = Service(log_output=STDOUT) 98 driver = Firefox(options=options, service=service) 99 driver = Firefox(options=options) 100 driver.implicitly_wait(30) 101 driver.set_page_load_timeout(60) 102 103 # install ########################################################## 104 105 driver.get('http://${domain}/cp-install') 106 107 wait = WebDriverWait(driver, 20) 108 109 wait.until(EC.title_contains("installer")) 110 111 driver.find_element(By.CSS_SELECTOR, '#username').send_keys( 112 '${username}' 113 ) 114 driver.find_element(By.CSS_SELECTOR, '#email').send_keys( 115 '${email}' 116 ) 117 driver.find_element(By.CSS_SELECTOR, '#password').send_keys( 118 '${password}' 119 ) 120 driver.find_element(By.XPATH, 121 "//button[contains(., 'Finish install')]" 122 ).click() 123 124 wait.until(EC.title_contains("Auth")) 125 126 driver.find_element(By.CSS_SELECTOR, '#email').send_keys( 127 '${email}' 128 ) 129 driver.find_element(By.CSS_SELECTOR, '#password').send_keys( 130 '${password}' 131 ) 132 driver.find_element(By.XPATH, 133 "//button[contains(., 'Login')]" 134 ).click() 135 136 wait.until(EC.title_contains("Admin dashboard")) 137 138 # create podcast ################################################### 139 140 driver.get('http://${domain}/admin/podcasts/new') 141 142 wait.until(EC.title_contains("Create podcast")) 143 144 driver.find_element(By.CSS_SELECTOR, '#cover').send_keys( 145 '${cover}' 146 ) 147 driver.find_element(By.CSS_SELECTOR, '#banner').send_keys( 148 '${banner}' 149 ) 150 driver.find_element(By.CSS_SELECTOR, '#title').send_keys( 151 '${podcastTitle}' 152 ) 153 driver.find_element(By.CSS_SELECTOR, '#handle').send_keys( 154 'some_handle' 155 ) 156 driver.find_element(By.CSS_SELECTOR, '#description').send_keys( 157 'Some description' 158 ) 159 driver.find_element(By.CSS_SELECTOR, '#owner_name').send_keys( 160 'Owner Name' 161 ) 162 driver.find_element(By.CSS_SELECTOR, '#owner_email').send_keys( 163 'owner@email.xyz' 164 ) 165 driver.find_element(By.XPATH, 166 "//button[contains(., 'Create podcast')]" 167 ).click() 168 169 wait.until(EC.title_contains("${podcastTitle}")) 170 171 driver.find_element(By.XPATH, 172 "//span[contains(., 'Add an episode')]" 173 ).click() 174 175 wait.until(EC.title_contains("Add an episode")) 176 177 # upload podcast ################################################### 178 179 driver.find_element(By.CSS_SELECTOR, '#audio_file').send_keys( 180 '/tmp/podcast.mp3' 181 ) 182 driver.find_element(By.CSS_SELECTOR, '#cover').send_keys( 183 '${cover}' 184 ) 185 driver.find_element(By.CSS_SELECTOR, '#description').send_keys( 186 'Episode description' 187 ) 188 driver.find_element(By.CSS_SELECTOR, '#title').send_keys( 189 '${episodeTitle}' 190 ) 191 driver.find_element(By.XPATH, 192 "//button[contains(., 'Create episode')]" 193 ).click() 194 195 wait.until(EC.title_contains("${episodeTitle}")) 196 197 driver.close() 198 driver.quit() 199 ''; 200 in 201 [ 202 pkgs.firefox-unwrapped 203 pkgs.geckodriver 204 browser-test 205 (pkgs.writeShellApplication { 206 name = "build-mp3"; 207 runtimeInputs = with pkgs; [ sox lame ]; 208 text = '' 209 out=/tmp/podcast.mp3 210 sox -n -r 48000 -t wav - synth ${targetPodcastDuration} sine 440 ` 211 `| lame --noreplaygain --cbr -q 9 -b 320 - $out 212 FILESIZE="$(stat -c%s $out)" 213 [ "$FILESIZE" -gt 0 ] 214 [ "$FILESIZE" -le "${toString targetPodcastSize}" ] 215 ''; 216 }) 217 ]; 218 }; 219 220 testScript = '' 221 start_all() 222 castopod.wait_for_unit("castopod-setup.service") 223 castopod.wait_for_file("/run/phpfpm/castopod.sock") 224 castopod.wait_for_unit("nginx.service") 225 castopod.wait_for_open_port(80) 226 castopod.wait_until_succeeds("curl -sS -f http://castopod.example.com") 227 228 client.succeed("build-mp3") 229 230 with subtest("Create superadmin, log in, create and upload a podcast"): 231 client.succeed(\ 232 "PYTHONUNBUFFERED=1 systemd-cat -t browser-test browser-test") 233 ''; 234})