The seven network methods on the wallet API were pass-throughs to the network manager. They now live on the networks service, under the networks_ namespace. The three deprecated ones are carried over rather than dropped: the functional tests still use addEthereumChain to attach the Anvil chain with a user provider, and getEthereumChains to read it back. The python client gains a NetworksService and the two call sites move to it.
Overview
Functional tests for status-go
Table of Contents
Prerequisites
- Install Docker and Docker Compose
- Install Python 3 (tested with 3.10 and 3.12 and it works with both)
- Note: For Python 3.10 compatibility, the codebase uses
Iterator[str]instead ofGenerator[str]for type annotations to avoid typing issues with older Python versions.
- Note: For Python 3.10 compatibility, the codebase uses
- Set up a virtual environment (required for linting):
- In
./test/functional, run:python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt pre-commit install - Important: The virtual environment must be created in the
./test/functionaldirectory for pre-commit linting and type-checking tools like Pyright to work correctly. - Optional (for test development): Use Python virtual environment for better dependency management. You can follow the guide here
- In
How to Run
-
Functional tests will spawn
status-gocontainers as needed, using the docker image name provided in--docker-image. Run this command to build a docker image for local runs in root dirstatus-go:# Note we tag the image with the commit hash. Functional tests will refer to the same when `--docker-image` is empty. docker build --platform linux/amd64 --tag "statusgo-$(git rev-parse --short HEAD)" . -
Functional tests rely on local instances of Waku and Anvil. Run this command to start all environment dependencies:
docker compose -f test/functional/docker-compose.anvil.yml -f test/functional/docker-compose.waku.yml up --build --remove-orphansThis will:
- Start a Waku fleet of 1 boot node + 1 store node
- Start Anvil with ChainID 31337 exposed on
0.0.0.0:8545 - Deploy required Status contracts to Anvil
-
In
./test/functional/testsdirectory run (with thevenvrunning):pytest -m rpcYou can run a single test with the
-kargument. Eg:pytest -k test_logging
Running against a status-backend binary
By default, tests will spawn containers with status-backend when and as needed.
This might be inconvenient when:
- You make changes to the
status-gocode, so you have to rebuild it frequently - You need to run
status-gocode with a debugger
For such cases, you can utilize --status_backend_url argument:
pytest --status_backend_url=http://<host>:<port> --status_backend_url=http://<host>:<port>
When provided, tests will connect to the given URL instead of spawning Docker containers.
NOTE:
- You must provide as many URLs as you need in your test
- URLs are not reused
- URLs are not reusedURLs are selected in the provided order
- Most tests do not call
Logoutin the end of the test, so make sure to restartstatus-backendin between test runs. You can also use--logoutflag to automaticallyLogoutbefore eachInitializeApplicationcall, but it is recommended to restartstatus-backendfor a full clean test.
Options
Running with a custom Waku fleet
status-backend can use a hard-coded list of supported Waku fleets or fleets specified in a config file. Functional tests provide 2 options to specify which Waku fleet to use.
- Use
--waku-fleets-configto override the hard-coded list of supported fleets.
The value will be passed toInitializeApplication.wakuFleetsConfigFilePathparameter. By default, it's set to JSON config for a local waku fleet. To run with a fleet from the hard-coded list use--waku-fleets-config=""and corresponding--waku-fleetvalue, e.g.--waku-fleet=status.prod - Use
--waku-fleetto select a Waku fleet to be used bystatus-go.
Default isstatus-go.testthat will use local waku nodes for functional tests run. The value will be passed to all of these parameters:CreateAccount.wakuV2FleetRestoreAccount.wakuV2Fleet
Please refer to the description of these parameters in status-go for details.
Prerequisites for Mac OSx users
If you see errors at attempt to run tests, try to run in terminal:
sock.connect(self.unix_socket)
If you see
PermissionError: [Errno 13] Permission denied
Please follow this fix: https://github.com/docker/compose/issues/10299#issuecomment-1438247730
If you're on MacOS and /var/run/docker.sock doesn't exist, you need to create a symlink to the docker socket:
sudo ln -s $HOME/.docker/run/docker.sock /var/run/docker.sock
Implementation details
- Functional tests are implemented in
./test/functional/testsbased on pytest - Backend fixtures and test infrastructure are defined in
./test/functional/tests/conftest.py - Every test has the following verifications:
validate_json_rpc_response()checks for status code 200, non-empty response, JSON-RPC structure, presence of theresult/errorfield, and expected ID.
Backend Setup and Cleanup with Pytest Fixtures
Functional tests in this suite rely on robust backend setup and teardown, managed via reusable pytest fixtures defined in tests/conftest.py. These fixtures ensure that backend containers are started, reused, and cleaned up efficiently, preventing resource leaks and test interference.
1. Backend Factory Fixtures
The main backend factory fixture:
-
backend_factory(function-scoped):
Allows you to create and clean up multiple backend instances per test function.
Note: Users/accounts are created from scratch for each backend instance.Example usage:
import pytest class TestMessenger: @pytest.fixture() def sender(self, backend_factory): return backend_factory("sender") @pytest.fixture() def receiver(self, backend_factory): return backend_factory("receiver") def test_send_message(self, sender, receiver): sender.send_message(receiver, "Hello!") assert receiver.has_received_message("Hello!")Or with parameters (using
indirectparametrization ofbackend_factory):@pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_with_params(self, sender, receiver): ... # use sender/receiver created by parametrized backend_factoryAll containers created by this fixture are automatically stopped and removed after the test.
2. Specialized Backend Fixtures
For more specific use cases, you can use these specialized fixtures:
-
backend_new_profile(function-scoped):
Creates a backend with a new user profile from scratch.Example usage:
def test_with_new_profile(self, backend_new_profile): # Create a backend with a new profile client = backend_new_profile("client1") # Or with light client mode light_client = backend_new_profile("light_client", waku_light_client=True) -
backend_recovered_profile(function-scoped):
Creates a backend by recovering an existing user profile from a seed phrase.Example usage:
from resources.constants import user_1 def test_with_recovered_profile(self, backend_recovered_profile): # Recover a backend from an existing user client = backend_recovered_profile("client1", user=user_1) # Or with light client mode light_client = backend_recovered_profile("light_client", user=user_1, waku_light_client=True) -
waku_light_client(function-scoped):
A parametrization fixture for enabling/disabling Waku light client mode. Use@parametrize_waku_light_clientfromwaku_params.pyto run tests with bothwakuV2LightClient_FalseandwakuV2LightClient_True. Example:pytest -m rpc -k 'wakuV2LightClient_True' -v.
3. Manual/Custom Backend Setup
For advanced scenarios where you need full control, use backend_factory.
Key points:
backend_factoryreturns a freshStatusBackendwith no automatic login. You callinit_status_backend()and any RPCs manually.- All backends created by the factory within a test are automatically shutdown on teardown.
- You can parametrize the factory (e.g.,
ipv6,privileged) viapytest.mark.parametrize(..., indirect=True).
Examples:
- Negative validation on restore (pre-login error expected):
import pytest
from clients.api import ApiResponseError
from resources.constants import user_mnemonic_12
import copy
def test_restore_with_empty_mnemonic(backend_factory):
user = copy.deepcopy(user_mnemonic_12)
backend = backend_factory("invalid_mnemonic")
backend.init_status_backend()
backend._set_display_name()
data = backend._create_account_request(password=user.password)
data["mnemonic"] = ""
with pytest.raises(ApiResponseError, match=r"restore-account: mnemonic is not set"):
backend.api_request_json("RestoreAccountAndLogin", data)
- Parametrizing the factory (e.g., enabling IPv6 and privileged mode):
import pytest
@pytest.mark.parametrize("backend_factory", [{"privileged": True, "ipv6": "Yes"}], indirect=True)
def test_with_ipv6_and_privileged(backend_factory):
be = backend_factory("node")
be.init_status_backend()
# ... continue with manual RPCs
4. Summary Table
Note: None of these fixtures are used automatically (
autouse=Falseby default). You must explicitly use them in your test setup for visibility and control.
| Fixture | Scope | Usage | Cleanup | User Creation Type |
|---|---|---|---|---|
backend_factory |
function | Per-test backend creation | Automatic | Created from scratch |
backend_new_profile |
function | New user profile creation | Automatic | Created from scratch |
backend_recovered_profile |
function | Existing profile recovery | Automatic | Recovered from seed phrase |
waku_light_client |
function | Light client parametrization | N/A | N/A (configuration only) |
5. Best Practices
- Prefer the factory fixtures for most tests—they are robust, reusable, and handle cleanup for you.
- Use specialized fixtures (
backend_new_profile,backend_recovered_profile) when you need specific profile creation behavior. - Never leave containers running after a test—always ensure cleanup is in place.
For more details, see the docstrings in tests/conftest.py and the example usages in the test files.
6. Recent Architectural Improvements
The test fixture architecture has been recently improved with the following changes:
- Separation of Concerns: Backend fixtures moved from root
conftest.pytotests/conftest.pyfor better organization - Simplified Architecture: Removed complex class-scoped fixtures in favor of more predictable function-scoped ones
- Better Fixture Wrappers: Added specialized
backend_new_profileandbackend_recovered_profilefixtures for specific use cases - Network Configuration: Network ID is now defined directly in
StatusBackendfor cleaner configuration management - Python Compatibility: Fixed typing issues for better Python 3.10+ compatibility
Linting
We use pre-commit setup for linting. To run linters:
cd test/functional
make lint
or run from the root of status-go repo:
make pytest-lint
Note that pyright uses pyrightconfig.json configuration from the repository root
and expects a Python virtual environment to be in ./test/functional/.venv.
Known issues
Import issues
If you see some import issues, make sure that you have all requirements installed from requirements.txt
For PyCharm users
Make sure that you made test-functional source folder (Right click > Mark directory as > Source folder)
Apple Silicon (macOS): Waku fleet connection failures — disable Rosetta
The wakuorg/nwaku fleet image is amd64-only, so on Apple Silicon it runs under emulation.
With Docker Desktop's Rosetta emulation enabled, the libp2p Noise handshake between the
status-go nodes (go-libp2p) and the nwaku fleet nodes (nim-libp2p) fails, so the app nodes
never connect to boot-1/store. Symptoms:
- status-go logs:
failed to negotiate security protocol: ... chacha20poly1305: message authentication failed - nwaku (boot-1/store) logs:
decryptWithAd failed tag authentication. - Tests that depend on the fleet (store/history sync, communities, anything store-backed) hang or fail, and the store node never receives messages.
The handshake only fails across go-libp2p ↔ nim-libp2p (go↔go and nim↔nim connections work), which points at Rosetta's emulation of the crypto path.
Fix: Docker Desktop → Settings → General → uncheck "Use Rosetta for x86_64/amd64 emulation on Apple Silicon", then restart Docker Desktop and recreate the fleet:
docker compose -f test/functional/docker-compose.anvil.yml -f test/functional/docker-compose.waku.yml up --build --remove-orphans -d
With the default (QEMU) emulation the go↔nim handshake succeeds.
Reliability tests
This framework also hosts a suite of reliability tests. See more info here
RuntimeError: Docker image 'statusgo-xyz:latest' not found
First check with docker images that the image was created. If not, re-run the build command from How to Run
Second, if the image is present in the list, check if you Python env is not connected to the wrong Docker daemon.
Run this in the shell:
echo $DOCKER_HOST
docker context ls
Run this in the Python env (python):
import docker
print(docker.from_env().api.base_url)
You might see that Python is using something like:
- unix:///run/docker.sock
- vs your CLI using unix:///var/run/docker.sock
If that is so, force Python to use the same Docker socket (from docker context ls):
export DOCKER_HOST=unix:///var/run/docker.sock
Add this before launching your test runner
/usr/status-user/wakufleetconfig.json: no such file or directory"
When running tests against status-backend Docker containers, you might see this error:
DEBUG:root:Got response: b'{"error":"failed to open fleets json file: open /usr/status-user/wakufleetconfig.json: no such file or directory"}'
If running with default arguments, this most likely means that you're not running local Waku fleet as described in Prerequisites.