Skip to content

Testing Best Practices and Guidelines

RunTimeAdmin edited this page Nov 4, 2026 · 32 revisions

Testing Best Practices & Guidelines

**Referenced Files in This Document** - [README.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/README.md) - [foundry.toml](https://github.com/RunTimeAdmin/Sigvara/blob/main/foundry.toml) - [E2E.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/E2E.t.sol) - [SigvaraIdentity.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SigvaraIdentity.t.sol) - [adversarial.test.js](https://github.com/RunTimeAdmin/Sigvara/blob/main/oracle/adversarial.test.js) - [package.json](https://github.com/RunTimeAdmin/Sigvara/blob/main/oracle/package.json) - [integration.test.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/test/integration.test.ts) - [vitest.config.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/vitest.config.ts)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document establishes testing best practices and guidelines for the Sigvara project across Solidity, TypeScript, and JavaScript layers. It codifies naming conventions, test organization, fixture management, shared utilities, security-focused testing, maintainability rules, coverage expectations, CI strategies, performance benchmarking, assertion patterns, debugging techniques, test data lifecycle, environment variable handling, and CI/CD integration. The guidance is grounded in the repository’s existing test suites and configuration.

Project Structure

The repository uses a layered testing approach:

  • Solidity tests under test/ using Foundry (unit, fuzz, invariant, E2E).
  • Oracle Node.js tests under oracle/ using Node’s built-in test runner.
  • TypeScript SDK tests under packages/sdk/test/ using Vitest.

As of 3 November 2026 the contract suite has 740 tests (each of the 21 invariants counts once), the oracle suite 999 and the SDK suite 300. Without a fork URL, 728 of the contract tests run and 12 skip, and 8 of the SDK tests, the integration tests, skip without a live deployment.

graph TB
subgraph "Solidity"
T1["test/E2E.t.sol"]
T2["test/SigvaraIdentity.t.sol"]
F["foundry.toml"]
end
subgraph "Oracle JS"
O1["oracle/adversarial.test.js"]
OP["oracle/package.json"]
end
subgraph "SDK TS"
S1["packages/sdk/test/integration.test.ts"]
VC["packages/sdk/vitest.config.ts"]
end
F --> T1
F --> T2
OP --> O1
VC --> S1
Loading

Diagram sources

Section sources

Core Components

  • Foundry test harness with default and CI profiles, fuzz runs, and RPC endpoints.
  • Five invariant campaigns, StakingInvariantTest, OracleBondInvariantTest, ReputationInvariantTest, EpochFeesInvariantTest and IdentityInvariantTest, with 21 invariants between them.
  • End-to-end Solidity suite covering full agent lifecycle, slash dispute, reputation challenge, unbonding, and multi-agent isolation.
  • Unit suite for identity contract including operator transfer, key rotation, status transitions, storage layout pinning, and access control.
  • Oracle adversarial scoring tests validating economic resistance to wash rings, sybil payers, decay, and flagging.
  • SDK integration tests that optionally run against a live chain when environment variables are present.

Section sources

Architecture Overview

Testing architecture spans three layers with clear separation of concerns:

  • Solidity layer: deterministic in-memory EVM execution, fuzzing, and invariant checks.
  • Oracle layer: pure function and pipeline validation with adversarial inputs.
  • SDK layer: optional live-chain integration guarded by environment variables.
graph TB
A["Foundry Tests<br/>Unit/Fuzz/Invariant/E2E"]
B["Oracle Tests<br/>Adversarial Scoring"]
C["SDK Tests<br/>Vitest Integration"]
D["Contracts<br/>Identity/Staking/Reputation"]
E["Chain<br/>Arc Testnet (optional)"]
A --> D
B --> D
C --> E
C -.-> D
Loading

Detailed Component Analysis

Solidity Testing Patterns

  • Naming conventions:
    • Test files mirror contracts: SigvaraIdentity.t.sol, SigvaraStaking.t.sol, etc.
    • Test functions use descriptive test_ prefixes and state changes: test_updateStatus_reverts_returningToActiveWithoutCollateral.
    • Fuzz tests use testFuzz_ prefix: testFuzz_computeDidHash_unique.
  • Organization:
    • Shared helpers under test/helpers/RegistrationHelper.sol.
    • E2E suite in test/E2E.t.sol orchestrates multiple contracts and roles.
    • Invariant tests target staking/identity safety properties.
  • Fixture management:
    • Contracts deployed in setUp() with proxies and role wiring.
    • Mock token MockSVR used for stake flows.
    • SigvaraReader.t.sol, GatedMarketplace.t.sol, InflowGuard.t.sol, OperatorCustody.t.sol and SmartWalletAgent.t.sol share test/helpers/StackFixture.sol, which deploys the three registries behind proxies wired the way the deploy scripts wire them, a funded operator, and a SigvaraReader pointed at them.
  • Assertions:
    • Explicit revert selectors via abi.encodeWithSelector.
    • State assertions on identity status, stake balances, and reputation totals.
  • Security focus:
    • Collateral checks before reactivation.
    • Slash immutability and terminal state enforcement.
    • Operator transfer integrity and index consistency.
flowchart TD
Start(["Test Entry"]) --> Setup["Deploy Proxies + Roles"]
Setup --> Act["Call Contract Function"]
Act --> AssertState{"Assert State"}
AssertState --> |Pass| Next["Next Scenario"]
AssertState --> |Fail| RevertCheck["Verify Expected Revert"]
RevertCheck --> Next
Next --> End(["Exit"])
Loading

Diagram sources

Section sources

Oracle Adversarial Testing

  • Purpose: Validate scoring resilience against wash rings, sybil payers, time decay, and flagging.
  • Approach: Feed attacker-crafted payment sets through real scoring pipeline without stubs.
  • Key scenarios:
    • Single-payer cap enforcement.
    • Wash ring ceiling bounds.
    • Zero-scored counterparties cannot inflate caps or propagation.
    • Tenure rewards elapsed activity; abandoned farms decay.
    • Flag damage bounded to community factor.
sequenceDiagram
participant T as "adversarial.test.js"
participant P as "payments module"
participant S as "scoring.computeScore"
T->>P : build events (wash ring / dust / flags)
P-->>T : grouped payments + metrics
T->>S : computeScore(measuredInputs)
S-->>T : score breakdown
T->>T : assert caps, decay, bounds
Loading

Diagram sources

Section sources

SDK Integration Testing

  • Optional execution: Skips when required environment variables are absent.
  • Live-chain operations: Registers an agent, verifies signatures, builds DID documents, and checks reputation thresholds.
  • Environment variables:
    • SIGVARA_RPC_URL, SIGVARA_CHAIN_ID, SIGVARA_IDENTITY_ADDRESS, SIGVARA_REPUTATION_ADDRESS, SIGVARA_STAKING_ADDRESS, SIGVARA_OPERATOR_PRIVATE_KEY.
sequenceDiagram
participant V as "integration.test.ts"
participant E as "ethers provider/wallet"
participant I as "Identity contract"
participant R as "Reputation contract"
V->>V : read env vars
V->>E : connect to RPC
V->>I : registerAgent(...)
V->>R : verifySignature(...)
V->>R : meetsThreshold(...)
V-->>V : assert outcomes
Loading

Diagram sources

Section sources

Dependency Analysis

  • Foundry configuration defines source/output paths, remappings, optimizer settings, the EVM version (cancun, set explicitly so a Foundry upgrade cannot change what is compiled), fuzz runs (1,000 by default, 5,000 on the CI profile), and RPC endpoints.
  • Oracle package declares Node test script and dependencies.
  • SDK package configures Vitest globals and Node environment.
graph LR
FT["foundry.toml"] --> SU["Solidity Suite"]
OPJ["oracle/package.json"] --> OT["Oracle Tests"]
VC["packages/sdk/vitest.config.ts"] --> ST["SDK Tests"]
Loading

Diagram sources

Section sources

Performance Considerations

  • Use Foundry’s CI fuzz profile for denser runs: FOUNDRY_PROFILE=ci forge test.
  • Keep unit tests fast and isolated; reserve E2E and integration tests for critical flows.
  • For oracle scoring, prefer adversarial scenarios over heavy network calls; they validate economic constraints deterministically.
  • Avoid unnecessary chain reads in SDK tests; gate integration tests behind environment variables.

Troubleshooting Guide

  • Solidity:
    • Use verbose output for E2E: forge test --match-contract E2EIntegrationTest -vvv.
    • Check expected revert selectors match contract errors.
    • Verify proxy initialization and role grants in setUp().
    • Three suites fork Arc testnet. SlashDrillFork.t.sol and SlashDrillAdversarialFork.t.sol fork it on every run, so they need the arc_testnet endpoint in foundry.toml to answer. SplitAuthorityFork.t.sol skips its twelve tests unless you pass --fork-url https://rpc.testnet.arc.io.
  • Oracle:
    • Confirm configuration values like PAYMENT_VERIFICATION and asset addresses.
    • Inspect console logs from adversarial scenarios to understand score ceilings.
  • SDK:
    • Ensure all required environment variables are set for integration tests.
    • Handle “AlreadyRegistered” errors gracefully during setup.

Section sources

Conclusion

Sigvara’s testing strategy combines deterministic Solidity unit/fuzz/invariant suites, adversarial oracle scoring validation, and optional live-chain SDK integration. Following the naming, organization, fixture, and security guidelines here will keep tests reliable, maintainable, and aligned with mainnet readiness goals.

Appendices

Naming Conventions

  • Solidity:
    • Test file: <ContractName>.t.sol.
    • Test function: test_<action>_<expected_behavior> or testFuzz_<property>_<uniqueness>.
  • Oracle JS:
    • Test file: <module>.test.js.
    • Test names: descriptive strings describing scenario and bound.
  • SDK TS:
    • Test file: <feature>.test.ts.
    • Test names: describe blocks per feature; it blocks describe behavior.

Section sources

Test Organization Patterns

  • Separate unit, E2E, and invariant tests by purpose.
  • Place shared helpers under test/helpers/.
  • Keep oracle tests focused on pure logic and adversarial inputs.
  • Gate SDK integration tests behind environment variables.

Section sources

Fixture Management and Shared Utilities

  • Deploy proxies and wire roles in setUp().
  • Use mock tokens for stake flows.
  • Centralize registration helpers to avoid duplication.

Section sources

Security-Focused Testing Requirements

  • Validate collateral gates before reactivation.
  • Enforce slash immutability and terminal states.
  • Run adversarial scoring tests to bound wash rings and sybil inflation.
  • Prepare for audits by documenting attack surfaces and invariants.

Section sources

Maintainability and Reliability

  • Prefer explicit revert selectors in assertions.
  • Keep tests deterministic; avoid flaky sleeps where possible.
  • Isolate multi-agent scenarios to prevent cross-test interference.

Section sources

Code Coverage and Continuous Integration

  • Run the contract suite with forge test. It runs offline except for the three fork suites described in the Troubleshooting Guide. Fetch the Solidity dependencies first with sh scripts/fetch-deps.sh.
  • Increase fuzz intensity with FOUNDRY_PROFILE=ci forge test.
  • Execute oracle tests with cd oracle && node --test.
  • Execute SDK tests with cd packages/sdk && npx vitest run.

Section sources

Performance Benchmarking Standards

  • Use adversarial scenarios to measure scoring ceilings and decay rates.
  • Track tenure growth across spans to ensure time-based factors resist buying.
  • Monitor community factor impact under flagging to bound blast radius.

Section sources

Examples of Effective Descriptions and Assertion Patterns

  • Clear scenario titles: “one payer cannot buy more than maxPerPayer points”.
  • Bounds assertions: “ring reached <= 60 total”.
  • Selector-based reverts: expectRevert(abi.encodeWithSelector(...)).

Section sources

Debugging Techniques

  • Verbose Forge output for E2E flows.
  • Console logging in adversarial tests to inspect score breakdowns.
  • Conditional skipping of integration tests when environment variables are missing.

Section sources

Test Data Lifecycle Management

  • Generate deterministic keys and addresses with helper utilities.
  • Use mock tokens for stake flows and slashing distributions.
  • Manage time with warp to simulate challenge windows and unbonding periods.

Section sources

Environment Variable Handling

  • Oracle: configuration loaded via module-level config reader.
  • SDK: integration tests gated by environment variables; skip if absent.

Section sources

CI/CD Pipeline Integration

  • Default Foundry profile for local runs; CI profile for fuzz intensity.
  • Node test script for oracle suite.
  • Vitest command for SDK suite.
  • .github/workflows/ci.yml runs on every push to main and every pull request, with read-only repository permissions. It builds the contracts (forge build --sizes) and tests them on the ci profile with 5,000 fuzz runs, including SlashDrillFork. After the build it compares the deployed testnet contracts with it (scripts/check-bytecode.mjs, which reports rather than fails a mismatch once main's contract sources have moved past the commit the deployment file records). It builds and tests the SDK, runs the oracle tests and the simulation plan tests, and runs the repository checks: scripts/check-docs.mjs, scripts/check-authz.mjs, scripts/check-headers.mjs, scripts/check-evidence-fixture.mjs, scripts/check-outcome-vectors.mjs, scripts/check-secrets.mjs (after its self-test) and scripts/check-before-renounce.mjs --self-test. It also runs Slither, which fails the build on High findings only.

Section sources

Overview

Clone this wiki locally