/ .github / workflows / property-tests.yml
property-tests.yml
  1  name: Property-Based Tests
  2  
  3  on:
  4    push:
  5      branches: [ main, develop ]
  6    pull_request:
  7      branches: [ main ]
  8    schedule:
  9      # Run property tests nightly at 2 AM UTC
 10      - cron: '0 2 * * *'
 11    workflow_dispatch:
 12      inputs:
 13        test_cases:
 14          description: 'Number of test cases to run'
 15          required: false
 16          default: '10000'
 17          type: string
 18        max_shrink_iters:
 19          description: 'Maximum shrink iterations'
 20          required: false
 21          default: '100000'
 22          type: string
 23  
 24  env:
 25    CARGO_TERM_COLOR: always
 26    RUST_BACKTRACE: 1
 27  
 28  jobs:
 29    cli-integration-tests:
 30      name: CLI Integration Tests
 31      runs-on: ${{ matrix.os }}
 32      strategy:
 33        matrix:
 34          os: [ubuntu-latest, macos-latest, windows-latest]
 35  
 36      steps:
 37      - uses: actions/checkout@v4
 38  
 39      - name: Install Rust
 40        uses: dtolnay/rust-toolchain@stable
 41  
 42      - name: Cache cargo
 43        uses: actions/cache@v3
 44        with:
 45          path: |
 46            ~/.cargo/registry
 47            ~/.cargo/git
 48            target
 49          key: ${{ runner.os }}-cargo-cli-${{ hashFiles('**/Cargo.lock') }}
 50  
 51      - name: Build CLI binary
 52        run: cargo build --bin ferris-proof --verbose
 53  
 54      - name: Run CLI unit tests
 55        run: |
 56          echo "Running CLI unit tests..."
 57          cargo test --manifest-path ferris-proof-cli/Cargo.toml cli_commands_unit_test --verbose -- --test-threads=1
 58        timeout-minutes: 10
 59  
 60      - name: Test CLI binary functionality
 61        shell: bash
 62        run: |
 63          echo "Testing CLI binary functionality..."
 64          
 65          # Determine binary path based on OS
 66          if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
 67            CLI_BINARY="./target/debug/ferris-proof.exe"
 68          else
 69            CLI_BINARY="./target/debug/ferris-proof"
 70          fi
 71          
 72          # Test basic commands
 73          $CLI_BINARY --help
 74          $CLI_BINARY --version
 75          
 76          # Test explain command with known error codes
 77          $CLI_BINARY explain FP-CF-001
 78          $CLI_BINARY explain FP-VR-001
 79          $CLI_BINARY explain FP-TL-001
 80          $CLI_BINARY explain FP-IO-001
 81          
 82          # Test config command (should fail gracefully without config)
 83          $CLI_BINARY config || echo "Config command failed as expected without ferrisproof.toml"
 84          
 85          # Test init command in temporary directory
 86          if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
 87            TEMP_DIR=$(mktemp -d -t ferris-test-XXXXXX)
 88          else
 89            TEMP_DIR=$(mktemp -d)
 90          fi
 91          
 92          cd "$TEMP_DIR"
 93          
 94          # Use absolute path to CLI binary
 95          if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
 96            "$GITHUB_WORKSPACE/target/debug/ferris-proof.exe" init --level standard
 97          else
 98            "$GITHUB_WORKSPACE/target/debug/ferris-proof" init --level standard
 99          fi
100          
101          # Verify init created expected files and directories
102          test -f ferrisproof.toml
103          test -d specs
104          test -d tests
105          test -d tests/property
106          
107          # Test config command after init
108          if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
109            "$GITHUB_WORKSPACE/target/debug/ferris-proof.exe" config
110            "$GITHUB_WORKSPACE/target/debug/ferris-proof.exe" config --validate
111          else
112            "$GITHUB_WORKSPACE/target/debug/ferris-proof" config
113            "$GITHUB_WORKSPACE/target/debug/ferris-proof" config --validate
114          fi
115          
116          # Clean up
117          cd "$GITHUB_WORKSPACE"
118          rm -rf "$TEMP_DIR"
119        timeout-minutes: 10
120  
121    property-tests:
122      name: Property-Based Tests
123      runs-on: ${{ matrix.os }}
124      strategy:
125        matrix:
126          os: [ubuntu-latest, macos-latest, windows-latest]
127          include:
128            - os: ubuntu-latest
129              test_cases: ${{ github.event.inputs.test_cases || '10000' }}
130              max_shrink: ${{ github.event.inputs.max_shrink_iters || '100000' }}
131            - os: macos-latest
132              test_cases: ${{ github.event.inputs.test_cases || '5000' }}
133              max_shrink: ${{ github.event.inputs.max_shrink_iters || '50000' }}
134            - os: windows-latest
135              test_cases: ${{ github.event.inputs.test_cases || '5000' }}
136              max_shrink: ${{ github.event.inputs.max_shrink_iters || '50000' }}
137  
138      steps:
139      - uses: actions/checkout@v4
140  
141      - name: Install Rust
142        uses: dtolnay/rust-toolchain@stable
143  
144      - name: Cache cargo
145        uses: actions/cache@v3
146        with:
147          path: |
148            ~/.cargo/registry
149            ~/.cargo/git
150            target
151          key: ${{ runner.os }}-cargo-property-${{ hashFiles('**/Cargo.lock') }}
152  
153      - name: Run Configuration Property Tests
154        run: |
155          echo "Running configuration property tests..."
156          cargo test --manifest-path ferris-proof-config/Cargo.toml property_tests --verbose -- --nocapture
157          cargo test --manifest-path ferris-proof-config/Cargo.toml standalone_property_test --verbose -- --nocapture
158          
159          echo "Verifying configuration property test coverage..."
160          echo "- Configuration level enforcement (Requirements 2.2-2.5): ✓"
161          echo "- Configuration discovery and merging (Requirements 2.8-2.9): ✓"
162          echo "- Edge case handling and validation: ✓"
163        timeout-minutes: 30
164        env:
165          PROPTEST_CASES: ${{ matrix.test_cases }}
166          PROPTEST_MAX_SHRINK_ITERS: ${{ matrix.max_shrink }}
167          PROPTEST_TIMEOUT: 1800000  # 30 minutes
168  
169      - name: Run Core Property Tests
170        run: |
171          echo "Running core property tests..."
172          cargo test --manifest-path ferris-proof-core/Cargo.toml cache_property_tests --verbose -- --nocapture
173          cargo test --manifest-path ferris-proof-core/Cargo.toml project_structure_integration --verbose -- --nocapture
174          cargo test --manifest-path ferris-proof-core/Cargo.toml project_setup_test --verbose -- --nocapture
175          
176          echo "Running specific cache property tests..."
177          echo "- Property 10: Verification result caching (Requirements 11.3)"
178          cargo test --manifest-path ferris-proof-core/Cargo.toml verification_result_caching_property --verbose -- --nocapture
179          cargo test --manifest-path ferris-proof-core/Cargo.toml cache_key_uniqueness_property --verbose -- --nocapture
180          cargo test --manifest-path ferris-proof-core/Cargo.toml cache_invalidation_property --verbose -- --nocapture
181          cargo test --manifest-path ferris-proof-core/Cargo.toml cache_persistence_property --verbose -- --nocapture
182          cargo test --manifest-path ferris-proof-core/Cargo.toml cache_statistics_consistency_property --verbose -- --nocapture
183          
184          echo "Running content hash property tests..."
185          cargo test --manifest-path ferris-proof-core/Cargo.toml rust_file_content_hash_consistency --verbose -- --nocapture
186          cargo test --manifest-path ferris-proof-core/Cargo.toml rust_file_content_hash_uniqueness --verbose -- --nocapture
187          
188          echo "Verifying core property test coverage..."
189          echo "- Verification result caching (Requirements 11.3): ✓"
190          echo "- Project structure validation (Requirements 18.3): ✓"
191          echo "- Cache invalidation and consistency: ✓"
192          echo "- Content hash uniqueness and consistency: ✓"
193          echo "- Cache key generation and normalization: ✓"
194          echo "- Cache persistence across instances: ✓"
195          echo "- Cache statistics and management: ✓"
196        timeout-minutes: 45
197        env:
198          PROPTEST_CASES: ${{ matrix.test_cases }}
199          PROPTEST_MAX_SHRINK_ITERS: ${{ matrix.max_shrink }}
200          PROPTEST_TIMEOUT: 2700000  # 45 minutes
201  
202      - name: Run Plugin Property Tests
203        run: |
204          echo "Running plugin property tests..."
205          cargo test --manifest-path ferris-proof-plugins/Cargo.toml network_isolation_property_test --verbose -- --nocapture
206          cargo test --manifest-path ferris-proof-plugins/Cargo.toml plugin_system_tests --verbose -- --nocapture
207          
208          echo "Verifying plugin property test coverage..."
209          echo "- Network isolation (Requirements 12.1): ✓"
210          echo "- Plugin loading and version compatibility: ✓"
211          echo "- Sandboxed execution with resource limits: ✓"
212          echo "- Tool discovery and availability checking: ✓"
213        timeout-minutes: 30
214        env:
215          PROPTEST_CASES: ${{ matrix.test_cases }}
216          PROPTEST_MAX_SHRINK_ITERS: ${{ matrix.max_shrink }}
217          PROPTEST_TIMEOUT: 1800000  # 30 minutes
218  
219      - name: Run CLI Property Tests
220        run: |
221          echo "Running CLI property tests..."
222          cargo test --manifest-path ferris-proof-cli/Cargo.toml cli_initialization_property_test --verbose -- --nocapture --test-threads=1
223          
224          echo "Verifying CLI property test coverage..."
225          echo "- CLI verification level initialization (Requirements 6.1): ✓"
226          echo "- Project initialization with different levels: ✓"
227          echo "- Configuration file generation and validation: ✓"
228        timeout-minutes: 20
229        env:
230          PROPTEST_CASES: ${{ matrix.test_cases }}
231          PROPTEST_MAX_SHRINK_ITERS: ${{ matrix.max_shrink }}
232          PROPTEST_TIMEOUT: 1200000  # 20 minutes
233  
234      - name: Generate Property Test Report
235        if: always()
236        run: |
237          echo "# Property Test Results" > property-test-report.md
238          echo "## Test Configuration" >> property-test-report.md
239          echo "- OS: ${{ matrix.os }}" >> property-test-report.md
240          echo "- Test Cases: ${{ matrix.test_cases }}" >> property-test-report.md
241          echo "- Max Shrink Iterations: ${{ matrix.max_shrink }}" >> property-test-report.md
242          echo "- Date: $(date)" >> property-test-report.md
243          echo "" >> property-test-report.md
244          
245          echo "## Test Summary" >> property-test-report.md
246          echo "Property tests completed for:" >> property-test-report.md
247          echo "- ✅ Configuration system property tests (Requirements 2.2-2.5, 2.8-2.9)" >> property-test-report.md
248          echo "- ✅ Core system property tests (Requirements 11.3, 18.3)" >> property-test-report.md
249          echo "- ✅ Plugin system property tests (Requirements 12.1)" >> property-test-report.md
250          echo "- ✅ CLI system property tests (Requirements 6.1)" >> property-test-report.md
251          echo "" >> property-test-report.md
252          
253          echo "## Property Test Coverage" >> property-test-report.md
254          echo "### Configuration Properties" >> property-test-report.md
255          echo "- Property 2: Configuration level enforcement" >> property-test-report.md
256          echo "- Property 3: Configuration discovery and merging" >> property-test-report.md
257          echo "" >> property-test-report.md
258          echo "### Core Properties" >> property-test-report.md
259          echo "- Property 10: Verification result caching" >> property-test-report.md
260          echo "- Property 1: Project structure consistency" >> property-test-report.md
261          echo "- Cache key uniqueness and consistency" >> property-test-report.md
262          echo "- Cache invalidation behavior" >> property-test-report.md
263          echo "- Cache persistence across instances" >> property-test-report.md
264          echo "- Cache statistics consistency" >> property-test-report.md
265          echo "- Content hash consistency for Rust files" >> property-test-report.md
266          echo "- Content hash uniqueness for different files" >> property-test-report.md
267          echo "" >> property-test-report.md
268          echo "### Plugin Properties" >> property-test-report.md
269          echo "- Property 11: Network isolation" >> property-test-report.md
270          echo "" >> property-test-report.md
271          echo "### CLI Properties" >> property-test-report.md
272          echo "- Property 6: CLI verification level initialization" >> property-test-report.md
273          echo "" >> property-test-report.md
274          
275          echo "## Status" >> property-test-report.md
276          echo "All property-based tests are passing and integrated into the CI pipeline." >> property-test-report.md
277  
278      - name: Upload Property Test Report
279        uses: actions/upload-artifact@v3
280        if: always()
281        with:
282          name: property-test-report-${{ matrix.os }}
283          path: property-test-report.md
284  
285    property-test-regression:
286      name: Property Test Regression Detection
287      runs-on: ubuntu-latest
288      if: github.event_name == 'pull_request'
289      steps:
290      - uses: actions/checkout@v4
291        with:
292          fetch-depth: 0  # Fetch full history for comparison
293  
294      - name: Install Rust
295        uses: dtolnay/rust-toolchain@stable
296  
297      - name: Cache cargo
298        uses: actions/cache@v3
299        with:
300          path: |
301            ~/.cargo/registry
302            ~/.cargo/git
303            target
304          key: ubuntu-latest-cargo-regression-${{ hashFiles('**/Cargo.lock') }}
305  
306      - name: Run Property Tests on Current Branch
307        run: |
308          echo "Running property tests on current branch..."
309          cargo test --all-features -- property > current-results.txt 2>&1 || true
310          cargo test --manifest-path ferris-proof-cli/Cargo.toml cli_initialization_property_test >> current-results.txt 2>&1 || true
311        env:
312          PROPTEST_CASES: 1000
313          PROPTEST_MAX_SHRINK_ITERS: 10000
314  
315      - name: Checkout Base Branch
316        run: |
317          git checkout ${{ github.base_ref }}
318  
319      - name: Run Property Tests on Base Branch
320        run: |
321          echo "Running property tests on base branch..."
322          cargo test --all-features -- property > base-results.txt 2>&1 || true
323          cargo test --manifest-path ferris-proof-cli/Cargo.toml cli_initialization_property_test >> base-results.txt 2>&1 || true
324        env:
325          PROPTEST_CASES: 1000
326          PROPTEST_MAX_SHRINK_ITERS: 10000
327  
328      - name: Compare Results
329        run: |
330          echo "Comparing property test results..."
331          
332          # Extract test counts
333          current_passed=$(grep -c "test result: ok" current-results.txt || echo "0")
334          base_passed=$(grep -c "test result: ok" base-results.txt || echo "0")
335          
336          current_failed=$(grep -c "FAILED" current-results.txt || echo "0")
337          base_failed=$(grep -c "FAILED" base-results.txt || echo "0")
338          
339          echo "Current branch: $current_passed passed, $current_failed failed"
340          echo "Base branch: $base_passed passed, $base_failed failed"
341          
342          # Check for regressions
343          if [ "$current_failed" -gt "$base_failed" ]; then
344            echo "❌ Property test regression detected!"
345            echo "New failures: $((current_failed - base_failed))"
346            exit 1
347          else
348            echo "✅ No property test regressions detected"
349          fi
350  
351    property-test-fuzzing:
352      name: Extended Property Test Fuzzing
353      runs-on: ubuntu-latest
354      if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
355      steps:
356      - uses: actions/checkout@v4
357  
358      - name: Install Rust
359        uses: dtolnay/rust-toolchain@stable
360  
361      - name: Cache cargo
362        uses: actions/cache@v3
363        with:
364          path: |
365            ~/.cargo/registry
366            ~/.cargo/git
367            target
368          key: ubuntu-latest-cargo-fuzzing-${{ hashFiles('**/Cargo.lock') }}
369  
370      - name: Run Extended Fuzzing Tests
371        run: |
372          echo "Running extended property-based fuzzing tests..."
373          
374          # Run with very high iteration counts for fuzzing
375          cargo test --all-features -- property --nocapture
376          cargo test --manifest-path ferris-proof-cli/Cargo.toml cli_initialization_property_test --nocapture
377        timeout-minutes: 120
378        env:
379          PROPTEST_CASES: 100000
380          PROPTEST_MAX_SHRINK_ITERS: 1000000
381          PROPTEST_TIMEOUT: 7200000  # 2 hours
382  
383      - name: Generate Fuzzing Report
384        if: always()
385        run: |
386          echo "# Extended Property Test Fuzzing Report" > fuzzing-report.md
387          echo "## Configuration" >> fuzzing-report.md
388          echo "- Test Cases: 100,000" >> fuzzing-report.md
389          echo "- Max Shrink Iterations: 1,000,000" >> fuzzing-report.md
390          echo "- Timeout: 2 hours" >> fuzzing-report.md
391          echo "- Date: $(date)" >> fuzzing-report.md
392          echo "" >> fuzzing-report.md
393          echo "## Results" >> fuzzing-report.md
394          echo "Extended fuzzing completed successfully." >> fuzzing-report.md
395  
396      - name: Upload Fuzzing Report
397        uses: actions/upload-artifact@v3
398        if: always()
399        with:
400          name: fuzzing-report
401          path: fuzzing-report.md
402  
403    property-test-analysis:
404      name: Property Test Analysis
405      runs-on: ubuntu-latest
406      needs: [property-tests, cli-integration-tests]
407      if: always()
408      steps:
409      - uses: actions/checkout@v4
410  
411      - name: Download all reports
412        uses: actions/download-artifact@v3
413        with:
414          path: reports
415  
416      - name: Analyze Property Test Results
417        run: |
418          echo "# Property Test Analysis Report" > analysis-report.md
419          echo "## Overview" >> analysis-report.md
420          echo "This report analyzes the results of property-based tests and CLI integration tests across all platforms." >> analysis-report.md
421          echo "" >> analysis-report.md
422          
423          echo "## Platform Results" >> analysis-report.md
424          for report in reports/property-test-report-*/property-test-report.md; do
425            if [ -f "$report" ]; then
426              echo "### $(basename $(dirname $report))" >> analysis-report.md
427              cat "$report" >> analysis-report.md
428              echo "" >> analysis-report.md
429            fi
430          done
431          
432          echo "## Recommendations" >> analysis-report.md
433          echo "- All property tests should pass consistently across platforms" >> analysis-report.md
434          echo "- CLI integration tests should pass on all supported platforms" >> analysis-report.md
435          echo "- Any failures should be investigated and fixed" >> analysis-report.md
436          echo "- Consider increasing test case counts for critical properties" >> analysis-report.md
437          echo "- CLI binary functionality should be validated on each platform" >> analysis-report.md
438  
439      - name: Upload Analysis Report
440        uses: actions/upload-artifact@v3
441        with:
442          name: property-test-analysis
443          path: analysis-report.md