diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index adebda63..def1df54 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,6 +43,25 @@ jobs: - uses: DeterminateSystems/magic-nix-cache-action@v4 - run: cd kiosk && nix-shell --run bin/test + kiosk-smoke-tests: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + - uses: cachix/install-nix-action@v18 + with: + nix_path: nixpkgs=channel:nixos-unstable + - uses: DeterminateSystems/magic-nix-cache-action@v4 + - name: Run Smoke Test + run: cd kiosk && nix-shell --run "python smoke_test.py" + build-vm: runs-on: ubuntu-latest steps: diff --git a/kiosk/test/smoke_test.py b/kiosk/test/smoke_test.py new file mode 100644 index 00000000..b157b7fa --- /dev/null +++ b/kiosk/test/smoke_test.py @@ -0,0 +1,65 @@ +import http.server +import socket +import socketserver +import threading +import subprocess +import time + +PORT = 45678 +request_count = 0 + +def main(): + """Checks that the kiosk-browser does not crash immediately on start and makes a request to the provided URL. + + This serves as a minimal test to make sure the kiosk can run on different platforms. + """ + + # Start dummy web server in thread, with signal to stop + keep_running = threading.Event() + keep_running.set() + server_thread = threading.Thread(target=run_server, args=(keep_running,)) + server_thread.start() + time.sleep(1) + + try: + browser_process = subprocess.Popen(['bin/kiosk-browser', f'http://localhost:{PORT}', f'http://localhost:{PORT}']) + time.sleep(5) + + # Minimal expectations + assert browser_process.poll() is None, "Browser process has crashed." + assert request_count >= 1, "No requests were made to the server." + + print("Smoke test passed successfully.") + + finally: + # Send signal to stop web server and wait for completion + keep_running.clear() + server_thread.join() + + # Terminate the browser process + browser_process.terminate() + +class RequestHandler(http.server.SimpleHTTPRequestHandler): + """Default request handler with added counter.""" + def do_GET(self): + global request_count + request_count += 1 + # Call superclass method to actually serve the request + super().do_GET() + +def run_server(keep_running): + """Run the web server, checking whether to keep running frequently.""" + with socketserver.TCPServer(("", PORT), RequestHandler, bind_and_activate=False) as httpd: + # Let address be reused to avoid failure on repeated runs + httpd.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + httpd.server_bind() + httpd.server_activate() + # Timeout frequently to check if killed + httpd.timeout = 0.5 + try: + while keep_running.is_set(): + httpd.handle_request() + finally: + httpd.server_close() + +main()