Skip to content

Commit a3ec5b3

Browse files
committed
fix: make status CLI test resilient to real K8s backend
1 parent 3fd731d commit a3ec5b3

2 files changed

Lines changed: 97 additions & 6 deletions

File tree

tests/apps/test_status.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,30 +127,36 @@ def test_status_cli_space_syntax(
127127
assert "=== myapi" in result.output
128128

129129
def test_status_cli_with_release_and_processes(
130-
self, cli_runner: CliRunner, factory: KuberokuFactory
130+
self,
131+
cli_runner: CliRunner,
132+
factory: KuberokuFactory,
133+
request: pytest.FixtureRequest,
131134
) -> None:
132135
"""Status CLI renders release, processes, config, and addons."""
133136
factory.apps.create("myapi")
134137
factory.deploy.deploy("myapi", image="nginx:1.27", wait=False)
135-
_create_fake_pod(factory, "myapi", "web", "pod-a", image="nginx:1.27")
138+
if request.config.getoption("--backend") == "fake":
139+
_create_fake_pod(factory, "myapi", "web", "pod-a", image="nginx:1.27")
136140
factory.config.set("myapi", {"DB": "pg://x"})
137141
factory.config.set("myapi", {"KEY": "secret"}, secret=True)
138142
factory.addons.create("myapi", "postgres")
139143
result = cli_runner.invoke(cli, ["apps:status", "myapi"], obj={"factory": factory})
140144
assert result.exit_code == 0
141145
output = result.output
142-
# Release line with version (v4 because addon+config each create releases)
146+
# Release line
143147
assert "Release:" in output
144148
assert "(Config change" in output or "(Deploy" in output
145-
# Processes section with running count
149+
# Processes section with web
150+
assert "Processes:" in output
146151
assert "web" in output
147-
assert "1/1 running" in output
152+
assert "running" in output
153+
assert "nginx:1.27" in output
148154
assert "ports: 8080/tcp" in output
149155
# Config count
150156
assert "2 vars (1 secrets)" in output
151157
# Addons
152158
assert "postgres (running)" in output
153-
# Domains (none since no ingress controller)
159+
# Domains
154160
assert "Domains:" in output
155161
# Maintenance off
156162
assert "Maintenance: off" in output

tests/deploy/test_deploy_retry.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""Tests for deploy retry on 409 Conflict and command removal paths."""
2+
3+
from __future__ import annotations
4+
5+
from kuberoku.factory import KuberokuFactory
6+
from kuberoku.k8s.resources import safe_name
7+
from tests.backends.fake import FakeK8sClient
8+
9+
10+
def test_update_deployment_retries_on_409() -> None:
11+
"""Deploy update retries on 409 Conflict."""
12+
k8s = FakeK8sClient()
13+
factory = KuberokuFactory(k8s_client=k8s, namespace="test-ns")
14+
factory.apps.create("myapp")
15+
factory.deploy.deploy("myapp", image="myapp:v1", wait=False)
16+
17+
dep_name = safe_name(factory.prefix, "myapp", "web")
18+
k8s.inject_conflict("Deployment", factory.namespace, dep_name, count=2)
19+
20+
factory.deploy.deploy("myapp", image="myapp:v2", wait=False)
21+
dep = k8s.get_deployment(factory.namespace, dep_name)
22+
assert dep["spec"]["template"]["spec"]["containers"][0]["image"] == "myapp:v2"
23+
24+
25+
def test_update_deployment_exhausts_retries() -> None:
26+
"""Deploy update exhausts retry loop, succeeds on final attempt."""
27+
k8s = FakeK8sClient()
28+
factory = KuberokuFactory(k8s_client=k8s, namespace="test-ns")
29+
factory.apps.create("myapp")
30+
factory.deploy.deploy("myapp", image="myapp:v1", wait=False)
31+
32+
dep_name = safe_name(factory.prefix, "myapp", "web")
33+
# 5 conflicts = exhausts retry loop (5 attempts), succeeds on final attempt
34+
k8s.inject_conflict("Deployment", factory.namespace, dep_name, count=5)
35+
36+
factory.deploy.deploy("myapp", image="myapp:v2", wait=False)
37+
dep = k8s.get_deployment(factory.namespace, dep_name)
38+
assert dep["spec"]["template"]["spec"]["containers"][0]["image"] == "myapp:v2"
39+
40+
41+
def test_deploy_removes_command_when_none() -> None:
42+
"""Redeploying without a command removes the previously-set command."""
43+
k8s = FakeK8sClient()
44+
factory = KuberokuFactory(k8s_client=k8s, namespace="test-ns")
45+
factory.apps.create("myapp")
46+
factory.deploy.deploy("myapp", image="myapp:v1", wait=False)
47+
48+
# Manually set a command on the deployment
49+
dep_name = safe_name(factory.prefix, "myapp", "web")
50+
dep = k8s.get_deployment(factory.namespace, dep_name)
51+
dep["spec"]["template"]["spec"]["containers"][0]["command"] = ["/bin/sh", "-c", "old-cmd"]
52+
k8s.update_deployment(factory.namespace, dep_name, dep)
53+
54+
# Redeploy with no command — should remove the command
55+
factory.deploy.deploy("myapp", image="myapp:v2", wait=False)
56+
dep = k8s.get_deployment(factory.namespace, dep_name)
57+
assert "command" not in dep["spec"]["template"]["spec"]["containers"][0]
58+
59+
60+
def test_restart_deployment_retries_on_409() -> None:
61+
"""Restart deployment retries on 409 Conflict."""
62+
k8s = FakeK8sClient()
63+
factory = KuberokuFactory(k8s_client=k8s, namespace="test-ns")
64+
factory.apps.create("myapp")
65+
factory.deploy.deploy("myapp", image="myapp:v1", wait=False)
66+
67+
dep_name = safe_name(factory.prefix, "myapp", "web")
68+
k8s.inject_conflict("Deployment", factory.namespace, dep_name, count=2)
69+
70+
count = factory.deploy._restart_deployments("myapp")
71+
assert count == 1
72+
73+
74+
def test_restart_deployment_exhausts_retries() -> None:
75+
"""Restart deployment exhausts retry loop, succeeds on final attempt."""
76+
k8s = FakeK8sClient()
77+
factory = KuberokuFactory(k8s_client=k8s, namespace="test-ns")
78+
factory.apps.create("myapp")
79+
factory.deploy.deploy("myapp", image="myapp:v1", wait=False)
80+
81+
dep_name = safe_name(factory.prefix, "myapp", "web")
82+
k8s.inject_conflict("Deployment", factory.namespace, dep_name, count=5)
83+
84+
count = factory.deploy._restart_deployments("myapp")
85+
assert count == 1

0 commit comments

Comments
 (0)