Integration Tests #83
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Integration Tests | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_run: | |
| workflows: ["Build and Push Images", "Build and Push TSan Image"] | |
| types: [completed] | |
| workflow_dispatch: | |
| # Container jobs run as root (required by actions/checkout), so we must | |
| # point opam at the vscode user's opam root and add its bin to PATH. | |
| env: | |
| OPAMROOT: /home/vscode/.opam | |
| jobs: | |
| # ============================================================================ | |
| # Test OCaml compiler and tools (single "ocaml" switch) | |
| # ============================================================================ | |
| test-ocaml: | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: [ubuntu-latest] | |
| # Uncomment to add ARM runners: | |
| # runner: [ubuntu-latest, ubuntu-24.04-arm] | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run OCaml tests | |
| run: | | |
| ./test/test-ocaml.sh ocaml | |
| # ============================================================================ | |
| # Test LSP server | |
| # ============================================================================ | |
| test-lsp: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run LSP tests | |
| run: | | |
| ./test/test-lsp.sh ocaml | |
| # ============================================================================ | |
| # Test profiling tools | |
| # ============================================================================ | |
| test-profiling: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run profiling tests | |
| run: | | |
| ./test/test-profiling.sh ocaml | |
| # ============================================================================ | |
| # Test OCaml TSan image (matrix: ocaml + ocaml+tsan switches) | |
| # ============================================================================ | |
| test-ocaml-tsan: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| switch: ['ocaml', 'ocaml+tsan'] | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer-tsan:latest | |
| options: >- | |
| --user root | |
| ${{ contains(matrix.switch, 'tsan') && '--privileged' || '' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Configure ASLR for TSan | |
| if: contains(matrix.switch, 'tsan') | |
| run: sysctl -w vm.mmap_rnd_bits=28 | |
| - name: Run OCaml tests | |
| run: | | |
| ./test/test-ocaml.sh ${{ matrix.switch }} | |
| test-lsp-tsan: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| switch: ['ocaml', 'ocaml+tsan'] | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer-tsan:latest | |
| options: >- | |
| --user root | |
| ${{ contains(matrix.switch, 'tsan') && '--privileged' || '' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Configure ASLR for TSan | |
| if: contains(matrix.switch, 'tsan') | |
| run: sysctl -w vm.mmap_rnd_bits=28 | |
| - name: Run LSP tests | |
| run: | | |
| ./test/test-lsp.sh ${{ matrix.switch }} | |
| test-profiling-tsan: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| switch: ['ocaml', 'ocaml+tsan'] | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer-tsan:latest | |
| options: >- | |
| --user root | |
| ${{ contains(matrix.switch, 'tsan') && '--privileged' || '' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Configure ASLR for TSan | |
| if: contains(matrix.switch, 'tsan') | |
| run: sysctl -w vm.mmap_rnd_bits=28 | |
| - name: Run profiling tests | |
| run: | | |
| ./test/test-profiling.sh ${{ matrix.switch }} | |
| # ============================================================================ | |
| # Test dune package management | |
| # ============================================================================ | |
| test-dune-pkg: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run dune pkg tests | |
| run: | | |
| ./test/test-dune-pkg.sh | |
| # ============================================================================ | |
| # Test editor integrations | |
| # ============================================================================ | |
| test-vscode: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install devcontainer CLI | |
| run: npm install -g @devcontainers/cli | |
| - name: Validate .devcontainer/devcontainer.json | |
| run: devcontainer read-configuration --workspace-folder . | |
| - name: Validate .devcontainer-from-scratch/devcontainer.json | |
| run: devcontainer read-configuration --workspace-folder . --config .devcontainer-from-scratch/devcontainer.json | |
| - name: Validate .devcontainer-tsan/devcontainer.json | |
| run: devcontainer read-configuration --workspace-folder . --config .devcontainer-tsan/devcontainer.json | |
| - name: Validate .devcontainer-tsan-from-scratch/devcontainer.json | |
| run: devcontainer read-configuration --workspace-folder . --config .devcontainer-tsan-from-scratch/devcontainer.json | |
| - name: Run VS Code tests | |
| run: | | |
| ./test/test-vscode.sh | |
| test-emacs: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run Emacs tests | |
| run: | | |
| ./test/test-emacs.sh | |
| test-neovim: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run Neovim tests | |
| run: | | |
| ./test/test-neovim.sh | |
| test-claude: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/ocaml-devcontainer:latest | |
| options: --user root | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Run Claude Code tests | |
| run: | | |
| ./test/test-claude.sh | |
| # ============================================================================ | |
| # Functional test: spin up devcontainer and run smoke tests | |
| # ============================================================================ | |
| test-devcontainer: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Build and run devcontainer | |
| uses: devcontainers/ci@v0.3 | |
| with: | |
| runCmd: | | |
| ocaml -version | |
| dune --version | |
| opam switch list | |
| cd examples/hello && dune build && dune exec ./hello.exe | |
| push: never | |
| # ============================================================================ | |
| # Test devcontainer workflow with Podman (smoke test) | |
| # ============================================================================ | |
| test-podman: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Replace Docker with Podman | |
| run: | | |
| # Stop Docker (mirrors a system without Docker installed) | |
| sudo systemctl disable --now docker.service docker.socket containerd.service | |
| sudo rm /usr/bin/docker | |
| # Alias podman as docker (same as macOS Homebrew setup) | |
| sudo ln -s /usr/bin/podman /usr/bin/docker | |
| # Start Podman API socket for devcontainer CLI | |
| sudo systemctl start podman.socket | |
| echo "DOCKER_HOST=unix:///run/podman/podman.sock" >> "$GITHUB_ENV" | |
| - name: Verify Podman as Docker | |
| run: | | |
| docker --version | |
| docker info | |
| - name: Install devcontainer CLI | |
| run: npm install -g @devcontainers/cli | |
| - name: Fix workspace permissions for Podman | |
| run: | | |
| # Rootful Podman maps UIDs 1:1; the container's vscode user (UID 1000) | |
| # needs write access to the workspace owned by runner (UID 1001). | |
| # Docker's updateRemoteUserUID handles this automatically but Podman | |
| # does not, so we open permissions on the workspace. | |
| chmod -R a+rwX . | |
| - name: Start devcontainer with Podman | |
| run: devcontainer up --workspace-folder . | |
| - name: Run smoke tests | |
| run: | | |
| devcontainer exec --workspace-folder . ocaml -version | |
| devcontainer exec --workspace-folder . dune --version | |
| devcontainer exec --workspace-folder . opam switch list | |
| devcontainer exec --workspace-folder . bash -c \ | |
| 'cd examples/hello && dune build && dune exec ./hello.exe' | |
| - name: Clean up | |
| if: always() | |
| run: | | |
| docker stop $(docker ps -q) 2>/dev/null || true | |
| # ============================================================================ | |
| # Summary job (for required status checks) | |
| # ============================================================================ | |
| test-summary: | |
| runs-on: ubuntu-latest | |
| needs: | |
| - test-ocaml | |
| - test-lsp | |
| - test-profiling | |
| - test-ocaml-tsan | |
| - test-lsp-tsan | |
| - test-profiling-tsan | |
| - test-dune-pkg | |
| - test-vscode | |
| - test-emacs | |
| - test-neovim | |
| - test-claude | |
| - test-devcontainer | |
| - test-podman | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| if [ "${{ needs.test-ocaml.result }}" != "success" ]; then | |
| echo "test-ocaml failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.test-lsp.result }}" != "success" ]; then | |
| echo "test-lsp failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.test-devcontainer.result }}" != "success" ]; then | |
| echo "test-devcontainer failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.test-podman.result }}" != "success" ]; then | |
| echo "::warning::test-podman failed (Podman support is best-effort)" | |
| fi | |
| # TSan image tests are best-effort (image may not exist yet) | |
| if [ "${{ needs.test-ocaml-tsan.result }}" != "success" ]; then | |
| echo "::warning::test-ocaml-tsan failed (TSan image may not be available)" | |
| fi | |
| echo "All critical tests passed" |