A moto-like library for mocking Kubernetes API in Python tests with stateful in-memory behavior
Project description
Mockernetes
A moto-like library for mocking Kubernetes API in Python tests with stateful in-memory behavior.
Features
- Drop-in replacement for
kubernetes.client.ApiClientusing patch requests - Stateful in-memory behavior that simulates real Kubernetes cluster state
- Shared fixtures for test configurations and common scenarios
- Resource lifecycle simulation including pod phases, deployment controllers, etc.
- Owner reference handling with automatic cascading deletion
- Label selector support for realistic resource querying
- Event generation for monitoring and debugging test scenarios
- Custom Resource support for CRDs and Gateway API resources
Installation
pip install mockernetes
Quick Start
from kubernetes import client as k8s_client
from mockernetes import mock_kubernetes
def test_my_kubernetes_code():
with mock_kubernetes() as mock_k8s:
# Your existing Kubernetes client code works unchanged
core_api = k8s_client.CoreV1Api()
# Create a pod
pod = k8s_client.V1Pod(
metadata=k8s_client.V1ObjectMeta(name="test-pod"),
spec=k8s_client.V1PodSpec(
containers=[
k8s_client.V1Container(name="app", image="nginx")
]
)
)
created_pod = core_api.create_namespaced_pod(namespace="default", body=pod)
# All operations are mocked but behave like real Kubernetes
assert created_pod.status.phase == "Running"
assert created_pod.metadata.uid is not None
Advanced Usage
Using as a Decorator
from mockernetes import patch_kubernetes
@patch_kubernetes()
def test_with_decorator():
core_api = k8s_client.CoreV1Api()
# Kubernetes APIs are automatically mocked
pods = core_api.list_namespaced_pod(namespace="default")
assert len(pods.items) == 0
Pre-configured Initial State
initial_state = {
'namespaces': ['production', 'staging'],
'pods': [
{
'metadata': {
'name': 'existing-pod',
'namespace': 'production',
'labels': {'app': 'web'}
},
'spec': {
'containers': [{'name': 'web', 'image': 'nginx:1.20'}]
}
}
]
}
with mock_kubernetes(initial_state) as mock_k8s:
core_api = k8s_client.CoreV1Api()
pod = core_api.read_namespaced_pod(name="existing-pod", namespace="production")
assert pod.metadata.labels['app'] == 'web'
Deployment Controller Simulation
Mockernetes automatically simulates Kubernetes controllers:
with mock_kubernetes() as mock_k8s:
apps_api = k8s_client.AppsV1Api()
core_api = k8s_client.CoreV1Api()
# Create a deployment
deployment = k8s_client.V1Deployment(
metadata=k8s_client.V1ObjectMeta(name="web-app"),
spec=k8s_client.V1DeploymentSpec(
replicas=3,
selector=k8s_client.V1LabelSelector(match_labels={"app": "web"}),
template=k8s_client.V1PodTemplateSpec(
metadata=k8s_client.V1ObjectMeta(labels={"app": "web"}),
spec=k8s_client.V1PodSpec(
containers=[k8s_client.V1Container(name="web", image="nginx")]
)
)
)
)
apps_api.create_namespaced_deployment(namespace="default", body=deployment)
# Pods are automatically created by the simulated controller
pods = core_api.list_namespaced_pod(namespace="default", label_selector="app=web")
assert len(pods.items) == 3 # 3 replicas created automatically
# Each pod has proper owner references
for pod in pods.items:
assert pod.metadata.owner_references[0].kind == "Deployment"
assert pod.metadata.owner_references[0].name == "web-app"
Cascading Deletion
Owner references are automatically handled:
with mock_kubernetes() as mock_k8s:
apps_api = k8s_client.AppsV1Api()
core_api = k8s_client.CoreV1Api()
# Create deployment (creates pods automatically)
deployment = k8s_client.V1Deployment(...)
created_deployment = apps_api.create_namespaced_deployment(namespace="default", body=deployment)
# Create service with owner reference
service = k8s_client.V1Service(
metadata=k8s_client.V1ObjectMeta(
name="web-service",
owner_references=[k8s_client.V1OwnerReference(
api_version='apps/v1',
kind='Deployment',
name=created_deployment.metadata.name,
uid=created_deployment.metadata.uid,
)]
),
spec=k8s_client.V1ServiceSpec(
selector={"app": "web"},
ports=[k8s_client.V1ServicePort(port=80)]
)
)
core_api.create_namespaced_service(namespace="default", body=service)
# Delete deployment - service and pods are automatically deleted
apps_api.delete_namespaced_deployment(name="web-app", namespace="default")
# Verify cascading deletion
pods = core_api.list_namespaced_pod(namespace="default", label_selector="app=web")
assert len(pods.items) == 0 # Pods deleted
with pytest.raises(ApiException):
core_api.read_namespaced_service(name="web-service", namespace="default") # Service deleted
Custom Resources
Mockernetes supports custom resources through the CustomObjectsApi:
with mock_kubernetes() as mock_k8s:
custom_api = k8s_client.CustomObjectsApi()
# Create HTTPRoute (Gateway API)
httproute = {
"apiVersion": "gateway.networking.k8s.io/v1",
"kind": "HTTPRoute",
"metadata": {"name": "my-route", "namespace": "default"},
"spec": {
"hostnames": ["example.com"],
"rules": [{"backendRefs": [{"name": "my-service", "port": 80}]}]
}
}
created_route = custom_api.create_namespaced_custom_object(
group="gateway.networking.k8s.io",
version="v1",
namespace="default",
plural="httproutes",
body=httproute
)
assert created_route["metadata"]["name"] == "my-route"
Supported APIs
Mockernetes currently supports:
- CoreV1Api: Pods, Services, ServiceAccounts, PersistentVolumeClaims, Namespaces
- AppsV1Api: Deployments, ReplicaSets, DaemonSets, StatefulSets
- NetworkingV1Api: Ingresses, NetworkPolicies
- PolicyV1Api: PodDisruptionBudgets
- CustomObjectsApi: Custom Resources (CRDs, Gateway API, etc.)
Simulated Behaviors
Pod Lifecycle
- Pods start in "Running" phase by default
- Container statuses are automatically populated
- Restart counts and ready states are simulated
Deployment Controller
- Automatically creates pods based on replica count
- Sets up proper owner references
- Updates deployment status (ready replicas, etc.)
Service Networking
- Automatically assigns ClusterIP addresses
- Validates port configurations
- Supports different service types
Resource Management
- Generates unique UIDs for all resources
- Handles resource versions and timestamps
- Maintains proper metadata relationships
Testing Patterns
OpenHands Runtime API Pattern
Mockernetes was designed specifically to support the OpenHands runtime-api testing patterns:
def test_runtime_lifecycle():
with mock_kubernetes() as mock_k8s:
runtime_id = "test-runtime-123"
# Create all runtime resources
create_runtime_resources(runtime_id) # Your existing function
# Verify resources exist
pods = get_runtime_pods(runtime_id) # Your existing function
assert len(pods) == 1
assert pods[0].status.phase == "Running"
# Test cleanup
delete_runtime(runtime_id) # Your existing function
# Verify cascading deletion
pods_after = get_runtime_pods(runtime_id)
assert len(pods_after) == 0
Integration with Pytest
import pytest
from mockernetes import MockKubernetes
@pytest.fixture
def k8s_cluster():
"""Provide a clean Kubernetes cluster for each test."""
with MockKubernetes() as mock_k8s:
yield mock_k8s
def test_with_fixture(k8s_cluster):
core_api = k8s_client.CoreV1Api()
# Test your code here
Why Mockernetes?
Testing Kubernetes applications often requires complex setup or expensive cloud resources. Mockernetes provides a lightweight, fast alternative that:
- Runs entirely in memory - No external dependencies
- Provides realistic behavior - Simulates controllers, owner references, etc.
- Supports complex scenarios - Multi-resource interactions, cascading deletion
- Integrates seamlessly - Drop-in replacement for existing code
- Eliminates infrastructure costs - No need for real clusters in unit tests
- Speeds up test execution - In-memory operations are much faster
Examples
See the examples/ directory for comprehensive usage examples, including:
- Basic pod and service operations
- Deployment controller simulation
- OpenHands runtime-api patterns
- Custom resource handling
- Initial state configuration
Contributing
Contributions are welcome! Please see our contributing guidelines for details.
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mockernetes-0.2.0.tar.gz.
File metadata
- Download URL: mockernetes-0.2.0.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f22536f9a7399aa7e32104b3fa240428f191510045878b5c7f034f6fe7d0f3e6
|
|
| MD5 |
e51d0fbab0293ae691473f938bed3162
|
|
| BLAKE2b-256 |
1da9e3a739c349545aca0a112d7d990e75a2bddb25706457fa78b9a0067b7c60
|
File details
Details for the file mockernetes-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mockernetes-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db1cfb259cb129deec5d8936e79e307611ce34ffa784b4b431bb4e58fc10da47
|
|
| MD5 |
9aa3ff461da94ffdee59bfbb2a3983cf
|
|
| BLAKE2b-256 |
3c4ef911be2388bf6e4715f12ed85b4aa7a63adfdb746530cd0d0f40d9c31b2a
|