End to End Tests #364
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: End to End Tests | |
| on: | |
| schedule: | |
| # run daily at 2:00 AM UTC | |
| - cron: '0 2 * * *' | |
| # allow manual triggering for testing purposes | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| test-symfony-cli-installation: | |
| name: Test Symfony CLI Installation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| coverage: none | |
| extensions: none, ctype, dom, iconv, intl, mbstring, pdo_sqlite, simplexml, tokenizer, xml, xmlwriter | |
| php-version: '8.4' | |
| tools: symfony-cli | |
| - name: Configure environment | |
| run: | | |
| git config --global init.defaultBranch main | |
| git config --global user.email "noreply@example.com" | |
| git config --global user.name "Symfony Demo" | |
| - name: Create project using Symfony CLI | |
| run: symfony new --demo ${{ github.job }} | |
| - name: Test application | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php bin/console about | |
| symfony server:start -d --no-tls | |
| curl --fail --max-time 5 --no-progress-meter --output home.html -v http://127.0.0.1:8000/ | |
| symfony server:stop | |
| - name: Show diagnostics on failure | |
| if: ${{ failure() }} | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php -v | |
| php -i | grep -E "memory_limit|opcache.enable|opcache.jit" || true | |
| # retry without --fail to see if the failure is first-request-only | |
| curl -sS --max-time 15 -o /tmp/retry.html -w 'retry: %{http_code} in %{time_total}s\n' http://127.0.0.1:8000/ || true | |
| head -c 300 /tmp/retry.html || true | |
| echo '===== app logs (filtered) =====' | |
| grep -hvE "security.DEBUG|http_client.INFO|cache.INFO" var/log/*.log | tail -n 60 || true | |
| echo '===== symfony CLI / PHP-FPM logs =====' | |
| find "$HOME" -maxdepth 6 -type d -name "*symfony5*" 2>/dev/null || true | |
| for f in $(find "$HOME/.symfony5" "${XDG_DATA_HOME:-$HOME/.local/share}/symfony5" "${XDG_CONFIG_HOME:-$HOME/.config}/symfony5" -type f -name "*.log" 2>/dev/null); do echo "--- $f"; cat "$f"; done | |
| echo '===== kernel messages (crashes / OOM) =====' | |
| sudo dmesg 2>/dev/null | tail -n 30 || true | |
| test-composer-create-project: | |
| name: Test Composer Create Project | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| coverage: none | |
| extensions: none, ctype, dom, iconv, intl, mbstring, pdo_sqlite, simplexml, tokenizer, xml, xmlwriter | |
| # setup-php enables the opcache JIT by default, but stock PHP disables it. | |
| # The tracing JIT crashes PHP-FPM while serving the first request of a | |
| # Symfony 8.1 app (reproduced with PHP 8.4 and 8.5, on x86_64 and arm64), | |
| # which made this job fail with a 502 error. Disable the JIT to test the | |
| # default PHP configuration that users actually run. | |
| ini-values: opcache.jit=disable | |
| php-version: latest | |
| tools: symfony-cli | |
| - name: Create project using Composer | |
| run: composer create-project symfony/symfony-demo ${{ github.job }} | |
| - name: Test application | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php bin/console about | |
| symfony server:start -d --no-tls | |
| curl --fail --max-time 5 --no-progress-meter --output home.html -v http://127.0.0.1:8000/ | |
| symfony server:stop | |
| - name: Show diagnostics on failure | |
| if: ${{ failure() }} | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php -v | |
| php -i | grep -E "memory_limit|opcache.enable|opcache.jit" || true | |
| # retry without --fail to see if the failure is first-request-only | |
| curl -sS --max-time 15 -o /tmp/retry.html -w 'retry: %{http_code} in %{time_total}s\n' http://127.0.0.1:8000/ || true | |
| head -c 300 /tmp/retry.html || true | |
| echo '===== app logs (filtered) =====' | |
| grep -hvE "security.DEBUG|http_client.INFO|cache.INFO" var/log/*.log | tail -n 60 || true | |
| echo '===== symfony CLI / PHP-FPM logs =====' | |
| find "$HOME" -maxdepth 6 -type d -name "*symfony5*" 2>/dev/null || true | |
| for f in $(find "$HOME/.symfony5" "${XDG_DATA_HOME:-$HOME/.local/share}/symfony5" "${XDG_CONFIG_HOME:-$HOME/.config}/symfony5" -type f -name "*.log" 2>/dev/null); do echo "--- $f"; cat "$f"; done | |
| echo '===== kernel messages (crashes / OOM) =====' | |
| sudo dmesg 2>/dev/null | tail -n 30 || true | |
| test-git-clone-installation: | |
| name: Test Git Clone Installation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| coverage: none | |
| extensions: none, ctype, dom, iconv, intl, mbstring, pdo_sqlite, simplexml, tokenizer, xml, xmlwriter | |
| php-version: '8.4' | |
| tools: symfony-cli | |
| - name: Clone repository and install dependencies | |
| run: | | |
| git clone https://github.com/symfony/demo.git ${{ github.job }} | |
| cd ${{ github.job }} | |
| composer install | |
| - name: Test application | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php bin/console about | |
| symfony server:start -d --no-tls | |
| curl --fail --max-time 5 --no-progress-meter --output home.html -v http://127.0.0.1:8000/ | |
| symfony server:stop | |
| - name: Show diagnostics on failure | |
| if: ${{ failure() }} | |
| working-directory: ${{ github.job }} | |
| run: | | |
| php -v | |
| php -i | grep -E "memory_limit|opcache.enable|opcache.jit" || true | |
| # retry without --fail to see if the failure is first-request-only | |
| curl -sS --max-time 15 -o /tmp/retry.html -w 'retry: %{http_code} in %{time_total}s\n' http://127.0.0.1:8000/ || true | |
| head -c 300 /tmp/retry.html || true | |
| echo '===== app logs (filtered) =====' | |
| grep -hvE "security.DEBUG|http_client.INFO|cache.INFO" var/log/*.log | tail -n 60 || true | |
| echo '===== symfony CLI / PHP-FPM logs =====' | |
| find "$HOME" -maxdepth 6 -type d -name "*symfony5*" 2>/dev/null || true | |
| for f in $(find "$HOME/.symfony5" "${XDG_DATA_HOME:-$HOME/.local/share}/symfony5" "${XDG_CONFIG_HOME:-$HOME/.config}/symfony5" -type f -name "*.log" 2>/dev/null); do echo "--- $f"; cat "$f"; done | |
| echo '===== kernel messages (crashes / OOM) =====' | |
| sudo dmesg 2>/dev/null | tail -n 30 || true | |
| notify-on-failure: | |
| if: ${{ always() && contains(needs.*.result, 'failure') }} | |
| name: Notify on Failure | |
| needs: [test-symfony-cli-installation, test-composer-create-project, test-git-clone-installation] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Create Issue on Failure | |
| uses: actions/github-script@v7 | |
| env: | |
| NEEDS_CONTEXT: ${{ toJSON(needs) }} | |
| with: | |
| script: | | |
| const needsContext = JSON.parse(process.env.NEEDS_CONTEXT); | |
| // Map job ids to human-readable names used in the workflow UI | |
| const jobNames = { | |
| 'test-symfony-cli-installation': 'Test Symfony CLI Installation', | |
| 'test-composer-create-project': 'Test Composer Create Project', | |
| 'test-git-clone-installation': 'Test Git Clone Installation', | |
| }; | |
| const failedJobs = Object.entries(needsContext) | |
| .filter(([, v]) => v.result === 'failure') | |
| .map(([id]) => `- **${jobNames[id] || id}**: failed`); | |
| const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`; | |
| const date = new Date().toISOString().split('T')[0]; | |
| const title = `E2E Test Failure: ${date}`; | |
| const body = [ | |
| 'The daily end-to-end test workflow has failed.', | |
| '', | |
| 'This may indicate users are experiencing issues installing the Symfony Demo application.', | |
| '', | |
| `**Run**: ${runUrl}`, | |
| '', | |
| '### Failed Jobs', | |
| failedJobs.join('\n'), | |
| '', | |
| 'Please investigate and fix the installation issues as soon as possible.' | |
| ].join('\n'); | |
| // Ensure label exists | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const labelName = 'bug'; | |
| try { | |
| await github.rest.issues.getLabel({ owner, repo, name: labelName }); | |
| } catch { | |
| await github.rest.issues.createLabel({ | |
| owner, repo, name: labelName, color: 'd73a4a', description: 'Something is broken' | |
| }); | |
| } | |
| // Skip if any E2E failure issue is already open, to avoid daily noise | |
| const { data: issues } = await github.rest.issues.listForRepo({ | |
| owner, repo, state: 'open', per_page: 100 | |
| }); | |
| const existing = issues.find(i => i.title.startsWith('E2E Test Failure')); | |
| if (existing) { | |
| core.info(`Issue #${existing.number} about E2E failures is still open; not creating another one.`); | |
| return; | |
| } | |
| await github.rest.issues.create({ owner, repo, title, body, labels: [labelName] }); |