Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing Pincer

This document outlines the testing architecture and procedures for the Pincer RPC server.


Why Python for Testing?

Using Python (specifically unittest.IsolatedAsyncioTestCase and websockets) allows us to perform black-box integration testing. By interacting with Pincer over WebSockets exactly as a real client would, we ensure that the compiled Rust binary and its RPC interface function correctly in real-world scenarios. It also allows us to quickly validate JSON-RPC structures without the boilerplate of a compiled test harness.


Test Suite Architecture

The test suite is located in the tests/ directory and is split into two parts:

  1. tests/test_rpc.py: Tests the WebSocket JSON-RPC server daemon.
  2. tests/test_cli.py: Tests the direct Command Line Interface (CLI) downloads.

It utilizes Python’s built-in unittest module to minimize external dependencies.

What is Tested?

The test suite covers the active features exposed by the modular src/rpc/ backend, grouped into logical blocks:

  1. System & Info (test_01_get_version, test_06_misc):
    • pin.getVersion, pin.resolveUrl, pin.resolveTorrent, pin.saveSession
  2. Global Options (test_02_global_options):
    • pin.getGlobalOption, pin.changeGlobalOption
  3. Task Lifecycle (test_03_lifecycle, test_08_pause_resume_integrity):
    • pin.addUri, pin.addTorrent, pin.addMetalink, pin.tellStatus, pin.pause, pin.unpause, pin.changeOption, pin.getOption, pin.remove, pin.removeAndFile, pin.forceRemove
  4. Bulk Operations & Stats (test_04_bulk_and_stats):
    • pin.pauseAll, pin.unpauseAll, pin.tellActive, pin.tellWaiting, pin.tellStopped, pin.getGlobalStat
  5. Result Management (test_05_cleanup):
    • pin.purgeDownloadResult, pin.removeDownloadResult
  6. Security & Path Traversal (test_07_path_traversal):
    • Path escaping mitigation and filename sanitization verification.

CLI Tests (tests/test_cli.py)

This suite tests the direct binary execution (pincer [URL] [OPTIONS]) without starting the daemon. It covers:

  1. Help & Version: Output of --help and --version.
  2. Direct Downloads: Downloading a file directly via CLI arguments (--out, --split, --dir, etc.) and verifying the file is written to disk successfully.

How to Run the Tests

The easiest and recommended way to run the entire test suite is using the automated test runner script.

Note

If your goal is to validate the codebase before cutting a new release, please refer to Build & Release. The automated release script delegates its checks directly to the unified test runner discussed below.

The Automated Test Runner (scripts/run_tests.py)

Pincer includes an all-in-one test runner script at scripts/run_tests.py. This script manages the entire lifecycle of CI verification, compilation, execution, and cleanup.

What the Runner Does:

  1. Conflicting Process Check: Automatically scans for and terminates any pre-existing running Pincer processes to prevent port bind conflicts on 6842.
  2. CI Verification Checks:
    • Runs cargo fmt --all -- --check (attempts to auto-format using cargo fmt if check fails).
    • Runs cargo check --all-targets to verify code compiles.
    • Runs cargo clippy --all-targets -- -D warnings to verify zero lint warnings.
  3. Build Stage: Builds the debug binary (cargo build).
  4. Session Cleanup: Removes any stale/leftover session file from ~/.pincer/pincer.session.
  5. CLI Tests: Runs tests/test_cli.py to verify direct download functionality.
  6. Background Server: Spawns Pincer in the background, waiting for it to spin up and bind the socket.
  7. RPC Tests: Runs tests/test_rpc.py to test websocket JSON-RPC methods end-to-end.
  8. Server Shutdown: Properly terminates the background server.
  9. Cleanup Prompt: Asks if you want to clean up temporary test files in tests/temporary.

How to Run:

# Ensure dependency is installed
pip install websockets

# Run the test suite
python3 scripts/run_tests.py

Running Tests Manually

If you prefer to run CLI or RPC tests independently:

RPC Tests (tests/test_rpc.py)

The Pincer server must be running in a separate process.

  1. Start the Rust backend:

    cargo run
    

    The server should log that it is listening on ws://0.0.0.0:6842/jsonrpc.

  2. In a separate terminal:

    python3 -m unittest tests/test_rpc.py
    

CLI Tests (tests/test_cli.py)

These do not require the server to be running:

python3 -m unittest tests/test_cli.py