Coverage for src/meshadmin/cli/tests/test_host.py: 100%
65 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-22 07:09 +0200
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-22 07:09 +0200
1import httpx
2import pytest
3from typer.testing import CliRunner
5from meshadmin.cli.main import app
7runner = CliRunner()
10@pytest.fixture
11def mock_host_access_token(mocker):
12 return mocker.patch(
13 "meshadmin.cli.commands.host.get_access_token", return_value="fake-token"
14 )
17@pytest.fixture
18def mock_host_context_config(mocker):
19 return mocker.patch(
20 "meshadmin.cli.commands.host.get_context_config",
21 return_value={"endpoint": "http://testserver"},
22 )
25@pytest.fixture
26def mock_download(mocker):
27 return mocker.patch("meshadmin.cli.commands.host.download")
30@pytest.fixture
31def mock_host_get_config_from_mesh(mocker):
32 return mocker.patch(
33 "meshadmin.cli.commands.host.get_config_from_mesh",
34 return_value=(
35 "pki: ca: test-ca-cert cert: test-host-cert key: host.key lighthouse: am_lighthouse: false hosts: - 10.0.0.1 static_host_map: '10.0.0.1': ['lighthouse.example.com:4242']",
36 5,
37 ),
38 )
41@pytest.fixture
42def test_context(temp_config_dir):
43 result = runner.invoke(
44 app,
45 [
46 "--config-path",
47 str(temp_config_dir),
48 "context",
49 "create",
50 "test-context-two",
51 "--endpoint",
52 "http://localhost:8001",
53 ],
54 )
55 return result
58@pytest.fixture
59def mock_enroll_response(mocker):
60 return mocker.patch(
61 "httpx.post",
62 return_value=httpx.Response(
63 status_code=200,
64 request=httpx.Request("POST", "http://testserver/api/v1/enroll"),
65 ),
66 )
69def test_host_enrollment(
70 mock_enroll_response,
71 temp_config_dir,
72 sample_context,
73 mock_download,
74 mock_host_get_config_from_mesh,
75):
76 result = runner.invoke(
77 app,
78 [
79 "--config-path",
80 str(temp_config_dir),
81 "host",
82 "enroll",
83 "test-enrollment-key",
84 "--preferred-hostname",
85 "test-host",
86 "--public-ip",
87 "192.168.1.100",
88 ],
89 )
90 assert result.exit_code == 0
91 network_dir = temp_config_dir / "networks" / "test-context"
92 auth_key_path = temp_config_dir / "auth.key"
93 public_key_path = network_dir / "host.pub"
94 private_key_path = network_dir / "host.key"
95 config_path = network_dir / "config.yaml"
96 assert network_dir.exists()
97 assert auth_key_path.exists()
98 assert public_key_path.exists()
99 assert private_key_path.exists()
100 assert config_path.exists()
101 mock_download.assert_called()
102 mock_host_get_config_from_mesh.assert_called()
103 assert "enrollment finished" in result.stdout
104 result = runner.invoke(
105 app,
106 [
107 "--config-path",
108 str(temp_config_dir),
109 "host",
110 "enroll",
111 "test-enrollment-key",
112 ],
113 )
114 assert result.exit_code == 0
115 assert "private and public nebula key already exists" in result.stdout
118def test_host_enrollment_shared_auth_key(
119 mock_enroll_response,
120 temp_config_dir,
121 sample_context,
122 test_context,
123 mock_download,
124 mock_host_get_config_from_mesh,
125):
126 result = runner.invoke(
127 app,
128 [
129 "--config-path",
130 str(temp_config_dir),
131 "--context",
132 "test-context",
133 "host",
134 "enroll",
135 "test-key",
136 ],
137 )
138 assert result.exit_code == 0
139 assert "enrollment finished" in result.stdout
140 auth_key_path = temp_config_dir / "auth.key"
141 original_auth_key = auth_key_path.read_text()
142 result = runner.invoke(
143 app,
144 [
145 "--config-path",
146 str(temp_config_dir),
147 "--context",
148 "test-context-two",
149 "host",
150 "enroll",
151 "test-key",
152 ],
153 )
154 assert result.exit_code == 0
155 assert "enrollment finished" in result.stdout
156 assert auth_key_path.read_text() == original_auth_key
159def test_delete_host_success(mocker, mock_host_access_token, mock_host_context_config):
160 mock_response = httpx.Response(
161 status_code=200,
162 json={"message": "Host test-host deleted"},
163 request=httpx.Request("DELETE", "http://testserver/api/v1/hosts/test-host"),
164 )
165 mock_delete = mocker.patch("httpx.delete", return_value=mock_response)
166 result = runner.invoke(app, ["host", "delete", "test-host"])
167 assert result.exit_code == 0
168 mock_delete.assert_called_once_with(
169 "http://testserver/api/v1/hosts/test-host",
170 headers={"Authorization": "Bearer fake-token"},
171 )
172 assert "deleted" in result.stdout.lower()
175def test_delete_host_auth_failure(mock_host_access_token, mock_host_context_config):
176 mock_host_access_token.side_effect = Exception("Auth failed")
177 result = runner.invoke(app, ["host", "delete", "test-host"])
178 assert result.exit_code == 1
179 assert "failed to get access token" in result.stdout