Skip to content

Testing and CI Infrastructure

The testing infrastructure for dapcli prioritizes strict hermeticity and static hygiene to ensure code quality and security. By default, the test suite blocks all network connections and subprocess invocations, allowing only specific, read-only git operations required for repository introspection. This approach forces developers to explicitly mock external dependencies, preventing flaky tests and accidental data leakage. Additionally, automated checks enforce a hard limit on source file size to maintain readability and ease of onboarding.

The core of the testing strategy is defined in tests/conftest.py, which provides two autouse session-scope fixtures that enforce a hermetic environment for every test 1.

  1. Network Blocking: The _block_socket_connect fixture patches socket.socket.connect to raise a pytest.fail error if any in-process TCP connection is attempted . This catches pure-Python code that forgets to mock HTTP clients. Tests must explicitly patch libraries like httpx.Client to simulate network responses.
  2. Subprocess Blocking: The _block_subprocess fixture patches subprocess.run, Popen, and check_output to block all subprocess invocations except for specific allowed cases.
    • Git Carveout: git commands are allowed because the hygiene scanner relies on git ls-files to enumerate tracked files, and self-tests may initialize temporary repositories. These git operations are read-only (e.g., ls-files, init, add, commit) and never hit the network.
    • Ceiling Checker Carveout: A specific Python invocation of tools/check_file_ceiling.py is allowed, as this offline checker shells out only to git ls-files.
    • Failures: Any other subprocess invocation raises pytest.fail.

Tests that exercise the runner-proxy (dap.kube.runner) opt into mocked subprocess by patching dap.kube.runner.subprocess directly within the test function.

diagram

The file tests/test_blueprint_client.py contains hermetic tests for the dap.blueprint.client module, locking in the API contract with the orchestrator’s /api/v3.1/* surface 2.

  • Mocking Strategy: Tests use httpx.MockTransport to intercept HTTP requests. A helper _mk_transport handles OIDC token minting by returning a mock token for /api/v1/oidc/token requests.
  • Patch Factory: A _patch_factory function creates httpx.Client instances with the mock transport, patching both dap.auth.token.httpx.Client and dap.orch_client.httpx.Client.
  • Sleep Patching: The _no_sleep helper patches dap.blueprint.client.time.sleep to a no-op, preventing tests from waiting during polling operations.

Key test cases verify:

  • Tar Creation: _tar_blueprint roots the archive at the source directory name and rejects missing directories.
  • Upload: upload_blueprint sends a multipart/form-data request with params and blueprint_archive fields in the correct order. It raises DapError if the upload state fails.
  • List/Delete: list_blueprints returns items from the JSON response. delete_blueprint includes the force=true query parameter when specified.
  • Deployment: create_deployment sends blueprint_id, inputs, and visibility in the PUT body.
  • Workflow Execution: execute_workflow posts a body with force=False by default. wait_execution returns the status or raises DapError on failure. latest_execution returns the first item or None.
  • Runtime Properties: fetch_runtime_properties returns node data. redact_runtime_properties masks secret keys (e.g., bmc_password, client_secret, auth_token, private_key, api_key) while preserving non-secret data.

The repository enforces strict hygiene through automated tests that check file sizes and line counts.

  • Source File Limit: tests/test_file_size_limit.py enforces a hard cap of 1000 lines for any first-party source file in src/ 3. This is intended to keep modules readable in one screen and encourage splitting large modules early. The test iterates over all .py files in src/ and fails if any exceed the limit.
  • Vendored Ceiling Checker: tests/test_file_ceiling.py runs the in-repo, stdlib-only tools/check_file_ceiling.py as a subprocess 4. This checker uses git ls-files to enumerate the tracked file set and fails if any hand-authored code file exceeds the 1000-line ceiling. This test is allowed to run as a subprocess because it is explicitly whitelisted in the hermetic fixtures 1.
diagram