Skip to main content

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.ApiClient using 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mockernetes-0.2.0.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mockernetes-0.2.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

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

Hashes for mockernetes-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f22536f9a7399aa7e32104b3fa240428f191510045878b5c7f034f6fe7d0f3e6
MD5 e51d0fbab0293ae691473f938bed3162
BLAKE2b-256 1da9e3a739c349545aca0a112d7d990e75a2bddb25706457fa78b9a0067b7c60

See more details on using hashes here.

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

Hashes for mockernetes-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 db1cfb259cb129deec5d8936e79e307611ce34ffa784b4b431bb4e58fc10da47
MD5 9aa3ff461da94ffdee59bfbb2a3983cf
BLAKE2b-256 3c4ef911be2388bf6e4715f12ed85b4aa7a63adfdb746530cd0d0f40d9c31b2a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page