Coverage for testnet/test_integration.py: 32%

76 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-10 16:08 +0200

1import json 

2import subprocess 

3import time 

4from pathlib import Path 

5 

6import pytest 

7 

8 

9def run_docker_compose(command, project_dir, env=None, check=False, text=True): 

10 return subprocess.run( 

11 ["docker", "compose"] + command, 

12 cwd=project_dir, 

13 env=env, 

14 capture_output=True, 

15 text=text, 

16 check=check, 

17 ) 

18 

19 

20@pytest.fixture(scope="session") 

21def mesh_admin(): 

22 return "https://dmeshadmin.hydo.ch" 

23 

24 

25@pytest.fixture(scope="session", autouse=True) 

26def build_test_image(): 

27 run_docker_compose( 

28 ["build", "-t", "meshadmin-testnet", "-f", "testnet/Dockerfile", "."], 

29 project_dir=Path(__file__).parent, 

30 check=True, 

31 ) 

32 

33 

34@pytest.fixture(scope="session") 

35def project_dir(): 

36 return Path(__file__).parent 

37 

38 

39@pytest.fixture(scope="session") 

40def base_env(mesh_admin): 

41 auth_file = Path("auth.json") 

42 if not auth_file.exists(): 

43 pytest.skip("No auth file found. Please run 'meshadmin login' first.") 

44 

45 return { 

46 "MESH_SERVER_URL": mesh_admin, 

47 "KEYCLOAK_BASE_URL": "http://auth.dmeshadmin.hydo.ch", 

48 "KEYCLOAK_REALM": "meshadmin", 

49 "KEYCLOAK_ADMIN_CLIENT": "admin-cli", 

50 } 

51 

52 

53@pytest.fixture(scope="session") 

54def test_templates(base_env, test_network, project_dir): 

55 try: 

56 # Create lighthouse template 

57 result = run_docker_compose( 

58 [ 

59 "run", 

60 "--rm", 

61 "admin", 

62 "meshadmin", 

63 "create-template", 

64 "lighthouse", 

65 test_network, 

66 "true", 

67 "true", 

68 "true", 

69 ], 

70 project_dir, 

71 env=base_env, 

72 ) 

73 assert result.returncode == 0, ( 

74 f"Failed to create lighthouse template: {result.stderr}" 

75 ) 

76 lighthouse_key = json.loads(result.stdout)["enrollment_key"] 

77 

78 # Create host template 

79 result = run_docker_compose( 

80 [ 

81 "run", 

82 "--rm", 

83 "admin", 

84 "meshadmin", 

85 "create-template", 

86 "host", 

87 test_network, 

88 "false", 

89 "false", 

90 "true", 

91 ], 

92 project_dir, 

93 env=base_env, 

94 ) 

95 assert result.returncode == 0, ( 

96 f"Failed to create host template: {result.stderr}" 

97 ) 

98 host_key = json.loads(result.stdout)["enrollment_key"] 

99 

100 yield { 

101 "network_name": test_network, 

102 "lighthouse_key": lighthouse_key, 

103 "host_key": host_key, 

104 } 

105 finally: 

106 # Cleanup 

107 for template in ["lighthouse", "host"]: 

108 run_docker_compose( 

109 [ 

110 "run", 

111 "--rm", 

112 "admin", 

113 "meshadmin", 

114 "delete-template", 

115 template, 

116 ], 

117 project_dir, 

118 env=base_env, 

119 ) 

120 for host in ["lighthouse_hetzner", "host1", "host2"]: 

121 run_docker_compose( 

122 [ 

123 "run", 

124 "--rm", 

125 "admin", 

126 "meshadmin", 

127 "delete-host", 

128 host, 

129 ], 

130 project_dir, 

131 env=base_env, 

132 ) 

133 

134 

135@pytest.fixture(scope="session") 

136def test_env(base_env, test_templates): 

137 full_env = base_env.copy() 

138 full_env.update( 

139 { 

140 "LIGHTHOUSE_ENROLLMENT_KEY": test_templates["lighthouse_key"], 

141 "HOST_ENROLLMENT_KEY": test_templates["host_key"], 

142 "MESH_ADMIN_ENDPOINT": mesh_admin, 

143 "MESH_CONFIG_PATH": "/tmp/", 

144 "LIGHTHOUSE_PUBLIC_IP": "128.140.42.121", 

145 "LIGHTHOUSE_HOSTNAME": "lighthouse_hetzner", 

146 "HOST_PUBLIC_IP": "127.0.0.1", 

147 } 

148 ) 

149 return full_env 

150 

151 

152@pytest.fixture(scope="session") 

153def test_network(test_env, project_dir): 

154 result = run_docker_compose( 

155 [ 

156 "run", 

157 "--rm", 

158 "admin", 

159 "meshadmin", 

160 "create-network", 

161 "test_network", 

162 "100.100.64.0/24", 

163 ], 

164 project_dir, 

165 env=test_env, 

166 ) 

167 assert result.returncode == 0, f"Failed to create network: {result.stderr}" 

168 return "test_network" 

169 

170 

171def print_container_logs(project_dir): 

172 for service in ["lighthouse_hetzner", "host1", "host2"]: 

173 logs = run_docker_compose(["logs", service], project_dir) 

174 print(f"\n=== {service} logs ===\n{logs.stdout}") 

175 

176 

177def wait_for_enrollment(project_dir, service_name, max_attempts=3, delay=5): 

178 for _ in range(max_attempts): 

179 logs = run_docker_compose(["logs", service_name], project_dir) 

180 if "enrollment finished" in logs.stdout: 

181 return True 

182 time.sleep(delay) 

183 return False 

184 

185 

186@pytest.mark.runtime 

187def test_network_setup(project_dir, test_env, mesh_admin, test_templates): 

188 try: 

189 # Check lighthouse enrollment and startup 

190 subprocess.run( 

191 ["docker", "compose", "up", "-d", "lighthouse_hetzner"], 

192 cwd=project_dir, 

193 env=test_env, 

194 capture_output=True, 

195 text=True, 

196 check=True, 

197 ) 

198 time.sleep(10) 

199 assert wait_for_enrollment(project_dir, "lighthouse_hetzner"), ( 

200 "Lighthouse enrollment failed" 

201 ) 

202 assert ( 

203 "starting nebula" 

204 in subprocess.run( 

205 ["docker", "compose", "logs", "lighthouse_hetzner"], 

206 cwd=project_dir, 

207 capture_output=True, 

208 text=True, 

209 ).stdout 

210 ), "Lighthouse nebula startup failed" 

211 

212 # Check host1 enrollment and startup 

213 subprocess.run( 

214 ["docker", "compose", "up", "-d", "host1"], 

215 cwd=project_dir, 

216 env=test_env, 

217 capture_output=True, 

218 text=True, 

219 check=True, 

220 ) 

221 time.sleep(10) 

222 assert wait_for_enrollment(project_dir, "host1"), "Host1 enrollment failed" 

223 assert ( 

224 "starting nebula" 

225 in subprocess.run( 

226 ["docker", "compose", "logs", "host1"], 

227 cwd=project_dir, 

228 capture_output=True, 

229 text=True, 

230 ).stdout 

231 ), "Host1 nebula startup failed" 

232 

233 # Check host2 enrollment and startup 

234 subprocess.run( 

235 ["docker", "compose", "up", "-d", "host2"], 

236 cwd=project_dir, 

237 env=test_env, 

238 capture_output=True, 

239 text=True, 

240 check=True, 

241 ) 

242 time.sleep(10) 

243 assert wait_for_enrollment(project_dir, "host2"), "Host2 enrollment failed" 

244 assert ( 

245 "starting nebula" 

246 in subprocess.run( 

247 ["docker", "compose", "logs", "host2"], 

248 cwd=project_dir, 

249 capture_output=True, 

250 text=True, 

251 ).stdout 

252 ), "Host2 nebula startup failed" 

253 except AssertionError: 

254 print_container_logs(project_dir) 

255 raise 

256 finally: 

257 subprocess.run( 

258 ["docker", "compose", "down", "-v"], 

259 cwd=project_dir, 

260 capture_output=True, 

261 )