1{ pkgs, lib, ... }: 2{ 3 name = "qbittorrent"; 4 5 meta = with pkgs.lib.maintainers; { 6 maintainers = [ 7 fsnkty 8 undefined-landmark 9 ]; 10 }; 11 12 nodes = { 13 simple = { 14 services.qbittorrent.enable = true; 15 16 specialisation.portChange.configuration = { 17 services.qbittorrent = { 18 enable = true; 19 webuiPort = 5555; 20 torrentingPort = 44444; 21 }; 22 }; 23 24 specialisation.openPorts.configuration = { 25 services.qbittorrent = { 26 enable = true; 27 openFirewall = true; 28 webuiPort = 8080; 29 torrentingPort = 55555; 30 }; 31 }; 32 33 specialisation.serverConfig.configuration = { 34 services.qbittorrent = { 35 enable = true; 36 webuiPort = null; 37 serverConfig.Preferences.WebUI.Port = "8181"; 38 }; 39 }; 40 }; 41 # Seperate vm because it's not possible to reboot into a specialisation with 42 # switch-to-configuration: https://github.com/NixOS/nixpkgs/issues/82851 43 # For one of the test we check if manual changes are overridden during 44 # reboot, therefore it's necessary to reboot into a declarative setup. 45 declarative = { 46 services.qbittorrent = { 47 enable = true; 48 webuiPort = null; 49 serverConfig = { 50 Preferences = { 51 WebUI = { 52 Username = "user"; 53 # Default password: adminadmin 54 Password_PBKDF2 = "@ByteArray(6DIf26VOpTCYbgNiO6DAFQ==:e6241eaAWGzRotQZvVA5/up9fj5wwSAThLgXI2lVMsYTu1StUgX9MgmElU3Sa/M8fs+zqwZv9URiUOObjqJGNw==)"; 55 Port = lib.mkDefault "8181"; 56 }; 57 }; 58 }; 59 }; 60 61 specialisation.serverConfigChange.configuration = { 62 services.qbittorrent = { 63 enable = true; 64 webuiPort = null; 65 serverConfig.Preferences.WebUI.Port = "7171"; 66 }; 67 }; 68 }; 69 }; 70 71 testScript = 72 { nodes, ... }: 73 let 74 simpleSpecPath = "${nodes.simple.system.build.toplevel}/specialisation"; 75 declarativeSpecPath = "${nodes.declarative.system.build.toplevel}/specialisation"; 76 portChange = "${simpleSpecPath}/portChange"; 77 openPorts = "${simpleSpecPath}/openPorts"; 78 serverConfig = "${simpleSpecPath}/serverConfig"; 79 serverConfigChange = "${declarativeSpecPath}/serverConfigChange"; 80 in 81 '' 82 simple.start(allow_reboot=True) 83 declarative.start(allow_reboot=True) 84 85 86 def test_webui(machine, port): 87 machine.wait_for_unit("qbittorrent.service") 88 machine.wait_for_open_port(port) 89 machine.wait_until_succeeds(f"curl --fail http://localhost:{port}") 90 91 92 # To simulate an interactive change in the settings 93 def setPreferences_api(machine, port, post_creds, post_data): 94 qb_url = f"http://localhost:{port}" 95 api_url = f"{qb_url}/api/v2" 96 cookie_path = "/tmp/qbittorrent.cookie" 97 98 machine.succeed( 99 f'curl --header "Referer: {qb_url}" \ 100 --data "{post_creds}" {api_url}/auth/login \ 101 -c {cookie_path}' 102 ) 103 machine.succeed( 104 f'curl --header "Referer: {qb_url}" \ 105 --data "{post_data}" {api_url}/app/setPreferences \ 106 -b {cookie_path}' 107 ) 108 109 110 # A randomly generated password is printed in the service log when no 111 # password it set 112 def get_temp_pass(machine): 113 _, password = machine.execute( 114 "journalctl -u qbittorrent.service |\ 115 grep 'The WebUI administrator password was not set.' |\ 116 awk '{ print $NF }' | tr -d '\n'" 117 ) 118 return password 119 120 121 # Non declarative tests 122 123 with subtest("webui works with all default settings"): 124 test_webui(simple, 8080) 125 126 with subtest("check if manual changes in settings are saved correctly"): 127 temp_pass = get_temp_pass(simple) 128 129 ## Change some settings 130 api_post = [r"json={\"listen_port\": 33333}", r"json={\"web_ui_port\": 9090}"] 131 for x in api_post: 132 setPreferences_api( 133 machine=simple, 134 port=8080, 135 post_creds=f"username=admin&password={temp_pass}", 136 post_data=x, 137 ) 138 139 simple.wait_for_open_port(33333) 140 test_webui(simple, 9090) 141 142 ## Test which settings are reset 143 ## As webuiPort is passed as an cli it should reset after reboot 144 ## As torrentingPort is not passed as an cli it should not reset after 145 ## reboot 146 simple.reboot() 147 test_webui(simple, 8080) 148 simple.wait_for_open_port(33333) 149 150 with subtest("ports are changed on config change"): 151 simple.succeed("${portChange}/bin/switch-to-configuration test") 152 test_webui(simple, 5555) 153 simple.wait_for_open_port(44444) 154 155 with subtest("firewall is opened correctly"): 156 simple.succeed("${openPorts}/bin/switch-to-configuration test") 157 test_webui(simple, 8080) 158 declarative.wait_until_succeeds("curl --fail http://simple:8080") 159 declarative.wait_for_open_port(55555, "simple") 160 161 with subtest("switching from simple to declarative works"): 162 simple.succeed("${serverConfig}/bin/switch-to-configuration test") 163 test_webui(simple, 8181) 164 165 166 # Declarative tests 167 168 with subtest("serverConfig is applied correctly"): 169 test_webui(declarative, 8181) 170 171 with subtest("manual changes are overridden during reboot"): 172 ## Change some settings 173 setPreferences_api( 174 machine=declarative, 175 port=8181, # as set through serverConfig 176 post_creds="username=user&password=adminadmin", 177 post_data=r"json={\"web_ui_port\": 9191}", 178 ) 179 180 test_webui(declarative, 9191) 181 182 ## Test which settings are reset 183 ## The generated qBittorrent.conf is, apparently, reapplied after reboot. 184 ## Because the port is set in `serverConfig` this overrides the manually 185 ## set port. 186 declarative.reboot() 187 test_webui(declarative, 8181) 188 189 with subtest("changes in serverConfig are applied correctly"): 190 declarative.succeed("${serverConfigChange}/bin/switch-to-configuration test") 191 test_webui(declarative, 7171) 192 ''; 193}