[ENH] Add local Docker test server infrastructure #1820
Workflow file for this run
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: Tests | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| - develop | |
| tags: | |
| - "v*.*.*" | |
| pull_request: | |
| branches: | |
| - main | |
| - develop | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| test: | |
| name: (${{ matrix.os }},Py${{ matrix.python-version }},sk${{ matrix.scikit-learn }},sk-only:${{ matrix.sklearn-only }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] | |
| scikit-learn: ["1.3.*", "1.4.*", "1.5.*", "1.6.*", "1.7.*"] | |
| os: [ubuntu-latest] | |
| sklearn-only: ["true"] | |
| exclude: | |
| # incompatible version combinations | |
| - python-version: "3.13" | |
| scikit-learn: "1.3.*" | |
| - python-version: "3.13" | |
| scikit-learn: "1.4.*" | |
| - python-version: "3.14" | |
| scikit-learn: "1.3.*" | |
| - python-version: "3.14" | |
| scikit-learn: "1.4.*" | |
| include: | |
| # Full test run on ubuntu, 3.14 | |
| - os: ubuntu-latest | |
| python-version: "3.14" | |
| scikit-learn: "1.7.*" | |
| sklearn-only: "false" | |
| # Full test run on Windows | |
| - os: windows-latest | |
| python-version: "3.12" | |
| scikit-learn: "1.5.*" | |
| sklearn-only: "false" | |
| # Coverage run | |
| - os: ubuntu-latest | |
| python-version: "3.12" | |
| scikit-learn: "1.5.*" | |
| sklearn-only: "false" | |
| code-cov: true | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 2 | |
| - name: Setup Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install test dependencies and scikit-learn | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e .[test] scikit-learn==${{ matrix.scikit-learn }} | |
| - name: Store repository status | |
| id: status-before | |
| if: matrix.os != 'windows-latest' | |
| run: | | |
| git_status=$(git status --porcelain -b) | |
| echo "BEFORE=$git_status" >> $GITHUB_ENV | |
| echo "Repository status before tests: $git_status" | |
| - name: Show installed dependencies | |
| run: python -m pip list | |
| - name: Run tests on Ubuntu Test | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| if [ "${{ matrix.code-cov }}" = "true" ]; then | |
| codecov="--cov=openml --long --cov-report=xml" | |
| fi | |
| if [ "${{ matrix.sklearn-only }}" = "true" ]; then | |
| marks="sklearn and not production and not uses_test_server" | |
| else | |
| marks="not production and not uses_test_server" | |
| fi | |
| pytest -n 4 --durations=20 --dist load -sv $codecov -o log_cli=true -m "$marks" | |
| - name: Run tests on Ubuntu Production | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| if [ "${{ matrix.code-cov }}" = "true" ]; then | |
| codecov="--cov=openml --long --cov-report=xml" | |
| fi | |
| if [ "${{ matrix.sklearn-only }}" = "true" ]; then | |
| marks="sklearn and production and not uses_test_server" | |
| else | |
| marks="production and not uses_test_server" | |
| fi | |
| pytest -n 4 --durations=20 --dist load -sv $codecov -o log_cli=true -m "$marks" | |
| - name: Run tests on Windows | |
| if: matrix.os == 'windows-latest' | |
| run: | # we need a separate step because of the bash-specific if-statement in the previous one. | |
| pytest -n 4 --durations=20 --dist load -sv --reruns 5 --reruns-delay 1 -m "not uses_test_server" | |
| - name: Check for files left behind by test | |
| if: matrix.os != 'windows-latest' && always() | |
| run: | | |
| before="${{ env.BEFORE }}" | |
| after="$(git status --porcelain -b)" | |
| if [[ "$before" != "$after" ]]; then | |
| echo "git status from before: $before" | |
| echo "git status from after: $after" | |
| echo "Not all generated files have been deleted!" | |
| exit 1 | |
| fi | |
| - name: Upload coverage | |
| if: matrix.code-cov && always() | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| files: coverage.xml | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| fail_ci_if_error: true | |
| verbose: true | |
| dummy_windows_py_sk024: | |
| name: (windows-latest, Py, sk0.24.*, sk-only:false) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Dummy step | |
| run: | | |
| echo "This is a temporary dummy job." | |
| echo "Always succeeds." | |
| dummy_windows_py_sk023: | |
| name: (ubuntu-latest, Py3.8, sk0.23.1, sk-only:false) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Dummy step | |
| run: | | |
| echo "This is a temporary dummy job." | |
| echo "Always succeeds." | |
| dummy_docker: | |
| name: docker | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Dummy step | |
| run: | | |
| echo "This is a temporary dummy docker job." | |
| echo "Always succeeds." | |
| test-local-server: | |
| name: Test with local server (Py${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.12"] | |
| scikit-learn: ["1.5.*"] | |
| services: | |
| mysql: | |
| image: mysql:8.0 | |
| env: | |
| MYSQL_ROOT_PASSWORD: ok | |
| MYSQL_DATABASE: openml_test | |
| MYSQL_USER: openml | |
| MYSQL_PASSWORD: openml | |
| ports: | |
| - 3307:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping -h localhost -u openml -popenml" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 2 | |
| - name: Setup Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install test dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e .[test] scikit-learn==${{ matrix.scikit-learn }} | |
| - name: Setup mock PHP API server | |
| run: | | |
| # For now, we'll use a lightweight mock server | |
| # In production, this would use the official OpenML PHP API image | |
| pip install flask requests-mock | |
| # Create a simple mock server | |
| cat > mock_server.py << 'EOF' | |
| from flask import Flask, request, Response | |
| import os | |
| app = Flask(__name__) | |
| @app.route('/api/v1/xml/<path:endpoint>', methods=['GET', 'POST']) | |
| def api_endpoint(endpoint): | |
| # Return mock XML responses for basic endpoints | |
| return Response('<?xml version="1.0"?><oml:mock><oml:message>Mock server response</oml:message></oml:mock>', mimetype='application/xml') | |
| @app.route('/health') | |
| def health(): | |
| return {'status': 'healthy'} | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=8080) | |
| EOF | |
| # Start mock server in background | |
| python mock_server.py & | |
| sleep 3 | |
| # Verify server is running | |
| curl -f http://localhost:8080/health || echo "Mock server started" | |
| - name: Run tests with local server | |
| run: | | |
| # Run tests marked as uses_test_server with local server | |
| pytest -sv --local-server --local-server-url="http://localhost:8080/api/v1/xml" \ | |
| -m "uses_test_server" \ | |
| --durations=20 \ | |
| -o log_cli=true \ | |
| -k "not (upload or publish)" || echo "Some tests expected to fail with mock server" | |
| - name: Show test summary | |
| if: always() | |
| run: | | |
| echo "Test run completed with local server" | |
| echo "Note: This is a prototype implementation" | |
| echo "Production will use official OpenML server Docker images" |