Adds BDD instructions and upgrade go to 1.26.3 #461
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: CI | |
| on: | |
| push: | |
| paths: | |
| - '.github/workflows/ci.yml' | |
| - 'cmd/**' | |
| - 'internal/**' | |
| - 'scripts/**' | |
| - 'test/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| workflow_dispatch: | |
| env: | |
| GO_VERSION: '1.26.3' | |
| jobs: | |
| # Build the binary once and share it across all jobs | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Download dependencies | |
| run: | | |
| go mod download | |
| go mod verify | |
| - name: Build cqlai binary | |
| run: | | |
| go build -v -o cqlai cmd/cqlai/main.go | |
| chmod +x cqlai | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cqlai-binary | |
| path: cqlai | |
| retention-days: 1 | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Download dependencies | |
| run: | | |
| go mod download | |
| go mod vendor | |
| - name: Install and run golangci-lint | |
| run: | | |
| curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /tmp v2.11.4 | |
| /tmp/golangci-lint run --timeout=5m | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Run unit tests | |
| run: | | |
| # Run tests excluding integration tests (which require Cassandra). | |
| # test/bdd is in-process godog and is run by the dedicated bdd-tests | |
| # job below — keep it out of the unit suite so coverage only counts | |
| # the production packages. | |
| go test -v -race -coverprofile=coverage.out -covermode=atomic $(go list ./... | grep -v /test/) | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./coverage.out | |
| flags: unittests | |
| fail_ci_if_error: false | |
| bdd-tests: | |
| name: BDD Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Download dependencies | |
| run: | | |
| go mod download | |
| go mod tidy | |
| - name: Run godog BDD suites | |
| run: | | |
| # Pure in-process godog scenarios — no Cassandra required. | |
| # Covers test/bdd/steps (validation, splitter, save, ai, ssl-flags) | |
| # plus internal/router (COPY options, in-package so it can see | |
| # unexported helpers). | |
| go test -v -count=1 -run BDD ./test/bdd/... ./internal/router/... | |
| parquet-tests: | |
| name: Parquet Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Download dependencies | |
| run: | | |
| go mod download | |
| go mod tidy | |
| - name: Run Parquet tests | |
| run: | | |
| echo "Running Parquet COPY TO/FROM tests" | |
| go test -v -timeout 60s ./test/parquet/... | |
| env: | |
| CI: true | |
| - name: Run Parquet test suite with script | |
| run: | | |
| chmod +x ./test/parquet/run_tests.sh | |
| ./test/parquet/run_tests.sh | |
| env: | |
| CI: true | |
| # Cassandra integration tests using the pre-built binary | |
| cassandra-tests: | |
| name: Cassandra ${{ matrix.cassandra.version }} | |
| needs: build # Wait for binary to be built | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| cassandra: | |
| - { version: "2.1", image: "cassandra:2.1" } | |
| - { version: "3.0", image: "cassandra:3.0" } | |
| - { version: "3.11", image: "cassandra:3.11" } | |
| - { version: "4.0", image: "cassandra:4.0" } | |
| - { version: "4.1", image: "cassandra:4.1" } | |
| - { version: "5.0", image: "cassandra:5.0" } | |
| services: | |
| cassandra: | |
| image: ${{ matrix.cassandra.image }} | |
| ports: | |
| - 9042:9042 | |
| options: >- | |
| --health-cmd "cqlsh -e 'describe cluster'" | |
| --health-interval 30s | |
| --health-timeout 10s | |
| --health-retries 10 | |
| --health-start-period 60s | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download pre-built binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: cqlai-binary | |
| - name: Make binary executable | |
| run: chmod +x ./cqlai | |
| - name: Wait for Cassandra to be fully ready | |
| run: | | |
| echo "Waiting for Cassandra to be fully ready..." | |
| for i in {1..30}; do | |
| if docker exec $(docker ps -q -f ancestor=${{ matrix.cassandra.image }}) cqlsh -e "DESCRIBE CLUSTER" 2>/dev/null; then | |
| echo "Cassandra is ready!" | |
| break | |
| fi | |
| echo "Waiting for Cassandra... ($i/30)" | |
| sleep 5 | |
| done | |
| - name: Create configuration file | |
| run: | | |
| cat > cqlai.json <<EOF | |
| { | |
| "host": "127.0.0.1", | |
| "port": 9042, | |
| "username": "", | |
| "password": "", | |
| "keyspace": "", | |
| "consistency": "ONE", | |
| "pageSize": 100, | |
| "timeout": "10s", | |
| "connectTimeout": "10s" | |
| } | |
| EOF | |
| - name: Run basic connectivity test | |
| run: | | |
| echo "Running basic connectivity test..." | |
| cat > basic_connectivity_test.cql <<EOF | |
| CREATE KEYSPACE IF NOT EXISTS test_connectivity | |
| WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1}; | |
| USE test_connectivity; | |
| CREATE TABLE IF NOT EXISTS test_table ( | |
| id uuid PRIMARY KEY, | |
| data text | |
| ); | |
| INSERT INTO test_table (id, data) VALUES (uuid(), 'test data'); | |
| SELECT * FROM test_table; | |
| DROP KEYSPACE test_connectivity; | |
| EOF | |
| ./cqlai -f basic_connectivity_test.cql | |
| if [ $? -eq 0 ]; then | |
| echo "✅ Basic connectivity test passed" | |
| else | |
| echo "❌ Basic connectivity test failed" | |
| exit 1 | |
| fi | |
| - name: Run COPY command tests | |
| run: | | |
| echo "Running COPY TO/FROM command tests..." | |
| # Create test keyspace and table | |
| ./cqlai -e "CREATE KEYSPACE IF NOT EXISTS copy_test WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1};" | |
| ./cqlai -k copy_test -e "CREATE TABLE IF NOT EXISTS test_copy (id int PRIMARY KEY, name text, value int, active boolean);" | |
| # Insert test data | |
| ./cqlai -k copy_test -e "INSERT INTO test_copy (id, name, value, active) VALUES (1, 'Alice', 100, true);" | |
| ./cqlai -k copy_test -e "INSERT INTO test_copy (id, name, value, active) VALUES (2, 'Bob', 200, false);" | |
| ./cqlai -k copy_test -e "INSERT INTO test_copy (id, name, value, active) VALUES (3, 'Charlie', 300, true);" | |
| # Test COPY TO | |
| echo "Testing COPY TO..." | |
| ./cqlai -k copy_test -e "COPY test_copy TO '/tmp/test_export.csv' WITH HEADER=true" | |
| if [ -f /tmp/test_export.csv ]; then | |
| echo "✅ COPY TO created file successfully" | |
| echo "File contents:" | |
| head -5 /tmp/test_export.csv | |
| else | |
| echo "❌ COPY TO failed to create file" | |
| exit 1 | |
| fi | |
| # Test COPY FROM | |
| echo "Testing COPY FROM..." | |
| ./cqlai -k copy_test -e "TRUNCATE test_copy;" | |
| ./cqlai -k copy_test -e "COPY test_copy FROM '/tmp/test_export.csv' WITH HEADER=true" | |
| # Verify data was imported | |
| count=$(./cqlai -k copy_test -e "SELECT COUNT(*) FROM test_copy;" | grep -o '[0-9]\+' | head -1) | |
| if [ "$count" = "3" ]; then | |
| echo "✅ COPY FROM imported $count rows successfully" | |
| else | |
| echo "❌ COPY FROM failed: expected 3 rows, got $count" | |
| exit 1 | |
| fi | |
| # Clean up | |
| ./cqlai -e "DROP KEYSPACE copy_test;" | |
| rm -f /tmp/test_export.csv | |
| echo "✅ All COPY command tests passed" | |
| - name: Run COPY FROM benchmark (issue #63) | |
| run: | | |
| echo "Running COPY FROM benchmark with 100k rows (use ROWS=1000000 for full test)..." | |
| chmod +x ./test/benchmark_copy_from.sh | |
| CQLAI=./cqlai ROWS=100000 ./test/benchmark_copy_from.sh | |
| - name: Run version-specific tests (if exists) | |
| run: | | |
| TEST_FILE="test/cassandra_${{ matrix.cassandra.version }}_test.cql" | |
| if [ -f "$TEST_FILE" ]; then | |
| echo "Running version-specific tests: $TEST_FILE" | |
| ./cqlai -f "$TEST_FILE" | |
| else | |
| echo "No version-specific tests found for Cassandra ${{ matrix.cassandra.version }}" | |
| fi | |
| # ------------------------------------------------------------------ | |
| # Full Go integration suite against Cassandra 5.0 only. | |
| # These tests are gated by the `integration` build tag (see | |
| # test/integration/*.go) and require a live cluster. Running on every | |
| # matrix entry would multiply CI time for little extra signal — the | |
| # logic under test is server-version-agnostic. | |
| # ------------------------------------------------------------------ | |
| - name: Setup Go (integration suite) | |
| if: matrix.cassandra.version == '5.0' | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Run Go integration tests against Cassandra 5 | |
| if: matrix.cassandra.version == '5.0' | |
| run: | | |
| go test -v -tags integration -timeout 10m -count=1 ./test/integration/... | |
| security-scan: | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@0.35.0 | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: '.' | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| severity: 'CRITICAL,HIGH' | |
| - name: Upload Trivy results to GitHub Security tab | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| continue-on-error: true | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| category: 'trivy' | |
| - name: Setup Go for gosec | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Run gosec security scanner | |
| run: | | |
| go install github.com/securego/gosec/v2/cmd/gosec@v2.23.0 | |
| gosec -no-fail -fmt sarif -out gosec-results.sarif ./... | |
| - name: Upload gosec results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| continue-on-error: true | |
| with: | |
| sarif_file: 'gosec-results.sarif' | |
| category: 'gosec' | |
| dependency-check: | |
| name: Dependency Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Check for outdated dependencies | |
| run: | | |
| go list -u -m all | |
| - name: Check for security vulnerabilities | |
| continue-on-error: true | |
| run: | | |
| go install golang.org/x/vuln/cmd/govulncheck@latest | |
| govulncheck -show verbose ./... | |
| # Summary job that runs after all tests | |
| test-summary: | |
| name: Test Summary | |
| needs: [lint, unit-tests, parquet-tests, cassandra-tests, security-scan] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Test Summary | |
| run: | | |
| echo "## CI Test Summary" | |
| echo "" | |
| echo "All CI checks have completed." | |
| echo "" | |
| echo "### Tests Run:" | |
| echo "- ✅ Linting" | |
| echo "- ✅ Unit Tests" | |
| echo "- ✅ Parquet Tests" | |
| echo "- ✅ Cassandra Integration Tests (6 versions)" | |
| echo "- ✅ Security Scans" | |
| echo "- ✅ Dependency Checks" | |
| echo "" | |
| echo "Note: Cross-platform builds are verified in the release workflow" |