Navegador

navegador / tests / test_cicd.py
Source Blame History 485 lines
aa55498… lmata 1 """Tests for navegador.cicd — CI/CD mode, CICDReporter, and `navegador ci` commands."""
aa55498… lmata 2
aa55498… lmata 3 import json
aa55498… lmata 4 import os
aa55498… lmata 5 from io import StringIO
aa55498… lmata 6 from pathlib import Path
aa55498… lmata 7 from unittest.mock import MagicMock, patch
aa55498… lmata 8
aa55498… lmata 9 import pytest
aa55498… lmata 10 from click.testing import CliRunner
aa55498… lmata 11
aa55498… lmata 12 from navegador.cicd import (
aa55498… lmata 13 EXIT_ERROR,
aa55498… lmata 14 EXIT_SUCCESS,
aa55498… lmata 15 EXIT_WARN,
aa55498… lmata 16 CICDReporter,
aa55498… lmata 17 detect_ci,
aa55498… lmata 18 is_ci,
aa55498… lmata 19 is_github_actions,
aa55498… lmata 20 )
aa55498… lmata 21 from navegador.cli.commands import main
aa55498… lmata 22
aa55498… lmata 23
aa55498… lmata 24 # ── Helpers ───────────────────────────────────────────────────────────────────
aa55498… lmata 25
aa55498… lmata 26
aa55498… lmata 27 def _clear_ci_env(monkeypatch):
aa55498… lmata 28 """Remove all known CI indicator env vars so each test starts clean."""
aa55498… lmata 29 for var in ("GITHUB_ACTIONS", "CI", "GITLAB_CI", "CIRCLECI", "JENKINS_URL"):
aa55498… lmata 30 monkeypatch.delenv(var, raising=False)
aa55498… lmata 31
aa55498… lmata 32
aa55498… lmata 33 def _mock_store():
aa55498… lmata 34 store = MagicMock()
aa55498… lmata 35 store.query.return_value = MagicMock(result_set=[])
aa55498… lmata 36 return store
aa55498… lmata 37
aa55498… lmata 38
aa55498… lmata 39 # ── CI detection ──────────────────────────────────────────────────────────────
aa55498… lmata 40
aa55498… lmata 41
aa55498… lmata 42 class TestDetectCI:
aa55498… lmata 43 def test_returns_none_outside_ci(self, monkeypatch):
aa55498… lmata 44 _clear_ci_env(monkeypatch)
aa55498… lmata 45 assert detect_ci() is None
aa55498… lmata 46
aa55498… lmata 47 def test_detects_github_actions(self, monkeypatch):
aa55498… lmata 48 _clear_ci_env(monkeypatch)
aa55498… lmata 49 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 50 assert detect_ci() == "github_actions"
aa55498… lmata 51
aa55498… lmata 52 def test_detects_generic_ci(self, monkeypatch):
aa55498… lmata 53 _clear_ci_env(monkeypatch)
aa55498… lmata 54 monkeypatch.setenv("CI", "true")
aa55498… lmata 55 assert detect_ci() == "ci"
aa55498… lmata 56
aa55498… lmata 57 def test_detects_gitlab_ci(self, monkeypatch):
aa55498… lmata 58 _clear_ci_env(monkeypatch)
aa55498… lmata 59 monkeypatch.setenv("GITLAB_CI", "true")
aa55498… lmata 60 assert detect_ci() == "gitlab_ci"
aa55498… lmata 61
aa55498… lmata 62 def test_detects_circleci(self, monkeypatch):
aa55498… lmata 63 _clear_ci_env(monkeypatch)
aa55498… lmata 64 monkeypatch.setenv("CIRCLECI", "true")
aa55498… lmata 65 assert detect_ci() == "circleci"
aa55498… lmata 66
aa55498… lmata 67 def test_detects_jenkins(self, monkeypatch):
aa55498… lmata 68 _clear_ci_env(monkeypatch)
aa55498… lmata 69 monkeypatch.setenv("JENKINS_URL", "http://jenkins.local/")
aa55498… lmata 70 assert detect_ci() == "jenkins"
aa55498… lmata 71
aa55498… lmata 72 def test_github_actions_takes_priority_over_ci(self, monkeypatch):
aa55498… lmata 73 _clear_ci_env(monkeypatch)
aa55498… lmata 74 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 75 monkeypatch.setenv("CI", "true")
aa55498… lmata 76 assert detect_ci() == "github_actions"
aa55498… lmata 77
aa55498… lmata 78
aa55498… lmata 79 class TestIsCI:
aa55498… lmata 80 def test_false_outside_ci(self, monkeypatch):
aa55498… lmata 81 _clear_ci_env(monkeypatch)
aa55498… lmata 82 assert is_ci() is False
aa55498… lmata 83
aa55498… lmata 84 def test_true_in_ci(self, monkeypatch):
aa55498… lmata 85 _clear_ci_env(monkeypatch)
aa55498… lmata 86 monkeypatch.setenv("CI", "true")
aa55498… lmata 87 assert is_ci() is True
aa55498… lmata 88
aa55498… lmata 89
aa55498… lmata 90 class TestIsGitHubActions:
aa55498… lmata 91 def test_false_outside_gha(self, monkeypatch):
aa55498… lmata 92 _clear_ci_env(monkeypatch)
aa55498… lmata 93 assert is_github_actions() is False
aa55498… lmata 94
aa55498… lmata 95 def test_false_for_generic_ci(self, monkeypatch):
aa55498… lmata 96 _clear_ci_env(monkeypatch)
aa55498… lmata 97 monkeypatch.setenv("CI", "true")
aa55498… lmata 98 assert is_github_actions() is False
aa55498… lmata 99
aa55498… lmata 100 def test_true_for_github_actions(self, monkeypatch):
aa55498… lmata 101 _clear_ci_env(monkeypatch)
aa55498… lmata 102 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 103 assert is_github_actions() is True
aa55498… lmata 104
aa55498… lmata 105
aa55498… lmata 106 # ── CICDReporter — exit codes ─────────────────────────────────────────────────
aa55498… lmata 107
aa55498… lmata 108
aa55498… lmata 109 class TestExitCodes:
aa55498… lmata 110 def test_success_when_clean(self):
aa55498… lmata 111 r = CICDReporter()
aa55498… lmata 112 assert r.exit_code() == EXIT_SUCCESS
aa55498… lmata 113
aa55498… lmata 114 def test_error_when_error_added(self):
aa55498… lmata 115 r = CICDReporter()
aa55498… lmata 116 r.add_error("something broke")
aa55498… lmata 117 assert r.exit_code() == EXIT_ERROR
aa55498… lmata 118
aa55498… lmata 119 def test_warn_when_only_warnings(self):
aa55498… lmata 120 r = CICDReporter()
aa55498… lmata 121 r.add_warning("heads up")
aa55498… lmata 122 assert r.exit_code() == EXIT_WARN
aa55498… lmata 123
aa55498… lmata 124 def test_error_takes_priority_over_warning(self):
aa55498… lmata 125 r = CICDReporter()
aa55498… lmata 126 r.add_warning("minor issue")
aa55498… lmata 127 r.add_error("fatal issue")
aa55498… lmata 128 assert r.exit_code() == EXIT_ERROR
aa55498… lmata 129
aa55498… lmata 130 def test_exit_code_constants(self):
aa55498… lmata 131 assert EXIT_SUCCESS == 0
aa55498… lmata 132 assert EXIT_ERROR == 1
aa55498… lmata 133 assert EXIT_WARN == 2
aa55498… lmata 134
aa55498… lmata 135
aa55498… lmata 136 # ── CICDReporter — JSON output ────────────────────────────────────────────────
aa55498… lmata 137
aa55498… lmata 138
aa55498… lmata 139 class TestJSONOutput:
a3b55ee… lmata 140 def _emit_to_str(self, reporter, monkeypatch, data=None) -> dict:
a3b55ee… lmata 141 _clear_ci_env(monkeypatch)
aa55498… lmata 142 buf = StringIO()
aa55498… lmata 143 reporter.emit(data=data, file=buf)
aa55498… lmata 144 return json.loads(buf.getvalue())
aa55498… lmata 145
a3b55ee… lmata 146 def test_status_success(self, monkeypatch):
aa55498… lmata 147 r = CICDReporter()
a3b55ee… lmata 148 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 149 assert out["status"] == "success"
aa55498… lmata 150
a3b55ee… lmata 151 def test_status_error(self, monkeypatch):
aa55498… lmata 152 r = CICDReporter()
aa55498… lmata 153 r.add_error("boom")
a3b55ee… lmata 154 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 155 assert out["status"] == "error"
aa55498… lmata 156
a3b55ee… lmata 157 def test_status_warning(self, monkeypatch):
aa55498… lmata 158 r = CICDReporter()
aa55498… lmata 159 r.add_warning("careful")
a3b55ee… lmata 160 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 161 assert out["status"] == "warning"
aa55498… lmata 162
a3b55ee… lmata 163 def test_errors_list_in_payload(self, monkeypatch):
aa55498… lmata 164 r = CICDReporter()
aa55498… lmata 165 r.add_error("err1")
aa55498… lmata 166 r.add_error("err2")
a3b55ee… lmata 167 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 168 assert out["errors"] == ["err1", "err2"]
aa55498… lmata 169
a3b55ee… lmata 170 def test_warnings_list_in_payload(self, monkeypatch):
aa55498… lmata 171 r = CICDReporter()
aa55498… lmata 172 r.add_warning("w1")
a3b55ee… lmata 173 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 174 assert out["warnings"] == ["w1"]
aa55498… lmata 175
a3b55ee… lmata 176 def test_data_included_when_provided(self, monkeypatch):
aa55498… lmata 177 r = CICDReporter()
a3b55ee… lmata 178 out = self._emit_to_str(r, monkeypatch, data={"files": 5, "functions": 20})
aa55498… lmata 179 assert out["data"] == {"files": 5, "functions": 20}
aa55498… lmata 180
a3b55ee… lmata 181 def test_data_absent_when_not_provided(self, monkeypatch):
aa55498… lmata 182 r = CICDReporter()
a3b55ee… lmata 183 out = self._emit_to_str(r, monkeypatch)
aa55498… lmata 184 assert "data" not in out
aa55498… lmata 185
a3b55ee… lmata 186 def test_output_is_valid_json(self, monkeypatch):
a3b55ee… lmata 187 _clear_ci_env(monkeypatch)
aa55498… lmata 188 r = CICDReporter()
aa55498… lmata 189 r.add_error("oops")
aa55498… lmata 190 r.add_warning("watch out")
aa55498… lmata 191 buf = StringIO()
aa55498… lmata 192 r.emit(data={"key": "value"}, file=buf)
aa55498… lmata 193 parsed = json.loads(buf.getvalue())
aa55498… lmata 194 assert isinstance(parsed, dict)
aa55498… lmata 195
aa55498… lmata 196
aa55498… lmata 197 # ── CICDReporter — GitHub Actions annotations ─────────────────────────────────
aa55498… lmata 198
aa55498… lmata 199
aa55498… lmata 200 class TestGitHubActionsAnnotations:
aa55498… lmata 201 def test_annotations_emitted_in_gha(self, monkeypatch):
aa55498… lmata 202 _clear_ci_env(monkeypatch)
aa55498… lmata 203 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 204
aa55498… lmata 205 r = CICDReporter()
aa55498… lmata 206 r.add_error("bad thing")
aa55498… lmata 207 r.add_warning("odd thing")
aa55498… lmata 208
aa55498… lmata 209 buf = StringIO()
aa55498… lmata 210 r.emit(file=buf)
aa55498… lmata 211 output = buf.getvalue()
aa55498… lmata 212
aa55498… lmata 213 assert "::error::bad thing" in output
aa55498… lmata 214 assert "::warning::odd thing" in output
aa55498… lmata 215
aa55498… lmata 216 def test_no_annotations_outside_gha(self, monkeypatch):
aa55498… lmata 217 _clear_ci_env(monkeypatch)
aa55498… lmata 218 monkeypatch.setenv("CI", "true")
aa55498… lmata 219
aa55498… lmata 220 r = CICDReporter()
aa55498… lmata 221 r.add_error("something")
aa55498… lmata 222
aa55498… lmata 223 buf = StringIO()
aa55498… lmata 224 r.emit(file=buf)
aa55498… lmata 225 output = buf.getvalue()
aa55498… lmata 226
aa55498… lmata 227 assert "::error::" not in output
aa55498… lmata 228
aa55498… lmata 229 def test_multiple_errors_all_annotated(self, monkeypatch):
aa55498… lmata 230 _clear_ci_env(monkeypatch)
aa55498… lmata 231 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 232
aa55498… lmata 233 r = CICDReporter()
aa55498… lmata 234 r.add_error("e1")
aa55498… lmata 235 r.add_error("e2")
aa55498… lmata 236
aa55498… lmata 237 buf = StringIO()
aa55498… lmata 238 r.emit(file=buf)
aa55498… lmata 239 output = buf.getvalue()
aa55498… lmata 240
aa55498… lmata 241 assert "::error::e1" in output
aa55498… lmata 242 assert "::error::e2" in output
aa55498… lmata 243
aa55498… lmata 244
aa55498… lmata 245 # ── CICDReporter — GitHub Actions step summary ────────────────────────────────
aa55498… lmata 246
aa55498… lmata 247
aa55498… lmata 248 class TestGitHubStepSummary:
aa55498… lmata 249 def test_writes_summary_file(self, monkeypatch, tmp_path):
aa55498… lmata 250 _clear_ci_env(monkeypatch)
aa55498… lmata 251 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 252 summary = tmp_path / "summary.md"
aa55498… lmata 253 monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(summary))
aa55498… lmata 254
aa55498… lmata 255 r = CICDReporter()
aa55498… lmata 256 r.emit(data={"files": 3}, file=StringIO())
aa55498… lmata 257
aa55498… lmata 258 content = summary.read_text()
aa55498… lmata 259 assert "Navegador" in content
aa55498… lmata 260 assert "files" in content
aa55498… lmata 261
aa55498… lmata 262 def test_summary_includes_errors(self, monkeypatch, tmp_path):
aa55498… lmata 263 _clear_ci_env(monkeypatch)
aa55498… lmata 264 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 265 summary = tmp_path / "summary.md"
aa55498… lmata 266 monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(summary))
aa55498… lmata 267
aa55498… lmata 268 r = CICDReporter()
aa55498… lmata 269 r.add_error("ingest failed")
aa55498… lmata 270 r.emit(file=StringIO())
aa55498… lmata 271
aa55498… lmata 272 content = summary.read_text()
aa55498… lmata 273 assert "ingest failed" in content
aa55498… lmata 274
aa55498… lmata 275 def test_summary_includes_warnings(self, monkeypatch, tmp_path):
aa55498… lmata 276 _clear_ci_env(monkeypatch)
aa55498… lmata 277 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 278 summary = tmp_path / "summary.md"
aa55498… lmata 279 monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(summary))
aa55498… lmata 280
aa55498… lmata 281 r = CICDReporter()
aa55498… lmata 282 r.add_warning("no files found")
aa55498… lmata 283 r.emit(file=StringIO())
aa55498… lmata 284
aa55498… lmata 285 content = summary.read_text()
aa55498… lmata 286 assert "no files found" in content
aa55498… lmata 287
aa55498… lmata 288 def test_no_summary_without_env_var(self, monkeypatch, tmp_path):
aa55498… lmata 289 _clear_ci_env(monkeypatch)
aa55498… lmata 290 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 291 monkeypatch.delenv("GITHUB_STEP_SUMMARY", raising=False)
aa55498… lmata 292
aa55498… lmata 293 r = CICDReporter()
aa55498… lmata 294 # Should not raise even when GITHUB_STEP_SUMMARY is absent
aa55498… lmata 295 r.emit(file=StringIO())
aa55498… lmata 296
aa55498… lmata 297 def test_summary_appends_not_overwrites(self, monkeypatch, tmp_path):
aa55498… lmata 298 _clear_ci_env(monkeypatch)
aa55498… lmata 299 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 300 summary = tmp_path / "summary.md"
aa55498… lmata 301 summary.write_text("# Previous content\n")
aa55498… lmata 302 monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(summary))
aa55498… lmata 303
aa55498… lmata 304 r = CICDReporter()
aa55498… lmata 305 r.emit(file=StringIO())
aa55498… lmata 306
aa55498… lmata 307 content = summary.read_text()
aa55498… lmata 308 assert "# Previous content" in content
aa55498… lmata 309 assert "Navegador" in content
aa55498… lmata 310
aa55498… lmata 311 def test_summary_handles_oserror_gracefully(self, monkeypatch, tmp_path):
aa55498… lmata 312 _clear_ci_env(monkeypatch)
aa55498… lmata 313 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 314 # Point to a directory instead of a file — open() will raise OSError
aa55498… lmata 315 monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(tmp_path))
aa55498… lmata 316
aa55498… lmata 317 r = CICDReporter()
aa55498… lmata 318 # Should not raise
aa55498… lmata 319 r.emit(file=StringIO())
aa55498… lmata 320
aa55498… lmata 321 def test_annotations_default_to_stdout(self, monkeypatch, capsys):
aa55498… lmata 322 _clear_ci_env(monkeypatch)
aa55498… lmata 323 monkeypatch.setenv("GITHUB_ACTIONS", "true")
aa55498… lmata 324 monkeypatch.delenv("GITHUB_STEP_SUMMARY", raising=False)
aa55498… lmata 325
aa55498… lmata 326 r = CICDReporter()
aa55498… lmata 327 r.add_error("test error")
aa55498… lmata 328 r._emit_github_annotations()
aa55498… lmata 329 captured = capsys.readouterr()
aa55498… lmata 330 assert "::error::test error" in captured.out
aa55498… lmata 331
aa55498… lmata 332
aa55498… lmata 333 # ── CLI: navegador ci ingest ──────────────────────────────────────────────────
aa55498… lmata 334
aa55498… lmata 335
aa55498… lmata 336 class TestCIIngestCommand:
a3b55ee… lmata 337 def test_success_outputs_json(self, monkeypatch):
a3b55ee… lmata 338 _clear_ci_env(monkeypatch)
aa55498… lmata 339 runner = CliRunner()
aa55498… lmata 340 with runner.isolated_filesystem():
aa55498… lmata 341 Path("src").mkdir()
aa55498… lmata 342 with patch("navegador.cli.commands._get_store", return_value=_mock_store()), \
aa55498… lmata 343 patch("navegador.ingestion.RepoIngester") as MockRI:
aa55498… lmata 344 MockRI.return_value.ingest.return_value = {"files": 5, "functions": 20}
aa55498… lmata 345 result = runner.invoke(main, ["ci", "ingest", "src"])
aa55498… lmata 346 assert result.exit_code == 0
aa55498… lmata 347 payload = json.loads(result.output)
aa55498… lmata 348 assert payload["status"] == "success"
aa55498… lmata 349 assert payload["data"]["files"] == 5
aa55498… lmata 350
a3b55ee… lmata 351 def test_warning_when_no_files_ingested(self, monkeypatch):
a3b55ee… lmata 352 _clear_ci_env(monkeypatch)
aa55498… lmata 353 runner = CliRunner()
aa55498… lmata 354 with runner.isolated_filesystem():
aa55498… lmata 355 Path("src").mkdir()
aa55498… lmata 356 with patch("navegador.cli.commands._get_store", return_value=_mock_store()), \
aa55498… lmata 357 patch("navegador.ingestion.RepoIngester") as MockRI:
aa55498… lmata 358 MockRI.return_value.ingest.return_value = {"files": 0, "functions": 0}
aa55498… lmata 359 result = runner.invoke(main, ["ci", "ingest", "src"])
aa55498… lmata 360 assert result.exit_code == 2
aa55498… lmata 361 payload = json.loads(result.output)
aa55498… lmata 362 assert payload["status"] == "warning"
aa55498… lmata 363 assert payload["warnings"]
aa55498… lmata 364
a3b55ee… lmata 365 def test_error_on_ingest_exception(self, monkeypatch):
a3b55ee… lmata 366 _clear_ci_env(monkeypatch)
aa55498… lmata 367 runner = CliRunner()
aa55498… lmata 368 with runner.isolated_filesystem():
aa55498… lmata 369 Path("src").mkdir()
aa55498… lmata 370 with patch("navegador.cli.commands._get_store", return_value=_mock_store()), \
aa55498… lmata 371 patch("navegador.ingestion.RepoIngester") as MockRI:
aa55498… lmata 372 MockRI.return_value.ingest.side_effect = RuntimeError("DB unavailable")
aa55498… lmata 373 result = runner.invoke(main, ["ci", "ingest", "src"])
aa55498… lmata 374 assert result.exit_code == 1
aa55498… lmata 375 payload = json.loads(result.output)
aa55498… lmata 376 assert payload["status"] == "error"
aa55498… lmata 377 assert "DB unavailable" in payload["errors"][0]
aa55498… lmata 378
a3b55ee… lmata 379 def test_output_is_valid_json(self, monkeypatch):
a3b55ee… lmata 380 _clear_ci_env(monkeypatch)
aa55498… lmata 381 runner = CliRunner()
aa55498… lmata 382 with runner.isolated_filesystem():
aa55498… lmata 383 Path("src").mkdir()
aa55498… lmata 384 with patch("navegador.cli.commands._get_store", return_value=_mock_store()), \
aa55498… lmata 385 patch("navegador.ingestion.RepoIngester") as MockRI:
aa55498… lmata 386 MockRI.return_value.ingest.return_value = {"files": 1}
aa55498… lmata 387 result = runner.invoke(main, ["ci", "ingest", "src"])
aa55498… lmata 388 parsed = json.loads(result.output)
aa55498… lmata 389 assert isinstance(parsed, dict)
aa55498… lmata 390
aa55498… lmata 391
aa55498… lmata 392 # ── CLI: navegador ci stats ───────────────────────────────────────────────────
aa55498… lmata 393
aa55498… lmata 394
aa55498… lmata 395 class TestCIStatsCommand:
aa55498… lmata 396 def _store_with_counts(self):
aa55498… lmata 397 store = MagicMock()
aa55498… lmata 398
aa55498… lmata 399 def _query(cypher, *args, **kwargs):
aa55498… lmata 400 result = MagicMock()
aa55498… lmata 401 if "NODE" in cypher.upper() or "node" in cypher.lower():
aa55498… lmata 402 result.result_set = [["Function", 10], ["Class", 3]]
aa55498… lmata 403 else:
aa55498… lmata 404 result.result_set = [["CALLS", 25]]
aa55498… lmata 405 return result
aa55498… lmata 406
aa55498… lmata 407 store.query.side_effect = _query
aa55498… lmata 408 return store
aa55498… lmata 409
a3b55ee… lmata 410 def test_outputs_json_stats(self, monkeypatch):
a3b55ee… lmata 411 _clear_ci_env(monkeypatch)
aa55498… lmata 412 runner = CliRunner()
aa55498… lmata 413 with patch("navegador.cli.commands._get_store", return_value=self._store_with_counts()):
aa55498… lmata 414 result = runner.invoke(main, ["ci", "stats"])
aa55498… lmata 415 assert result.exit_code == 0
aa55498… lmata 416 payload = json.loads(result.output)
aa55498… lmata 417 assert payload["status"] == "success"
aa55498… lmata 418 assert "data" in payload
aa55498… lmata 419 assert "total_nodes" in payload["data"]
aa55498… lmata 420 assert "total_edges" in payload["data"]
aa55498… lmata 421
a3b55ee… lmata 422 def test_error_on_store_failure(self, monkeypatch):
a3b55ee… lmata 423 _clear_ci_env(monkeypatch)
aa55498… lmata 424 runner = CliRunner()
aa55498… lmata 425 with patch("navegador.cli.commands._get_store", side_effect=RuntimeError("no db")):
aa55498… lmata 426 result = runner.invoke(main, ["ci", "stats"])
aa55498… lmata 427 assert result.exit_code == 1
aa55498… lmata 428 payload = json.loads(result.output)
aa55498… lmata 429 assert payload["status"] == "error"
aa55498… lmata 430
aa55498… lmata 431
aa55498… lmata 432 # ── CLI: navegador ci check ───────────────────────────────────────────────────
aa55498… lmata 433
aa55498… lmata 434
aa55498… lmata 435 class TestCICheckCommand:
a3b55ee… lmata 436 def test_success_when_schema_current(self, monkeypatch):
a3b55ee… lmata 437 _clear_ci_env(monkeypatch)
aa55498… lmata 438 from navegador.graph.migrations import CURRENT_SCHEMA_VERSION
aa55498… lmata 439
aa55498… lmata 440 store = MagicMock()
aa55498… lmata 441 store.query.return_value = MagicMock(result_set=[[CURRENT_SCHEMA_VERSION]])
aa55498… lmata 442
aa55498… lmata 443 runner = CliRunner()
aa55498… lmata 444 with patch("navegador.cli.commands._get_store", return_value=store):
aa55498… lmata 445 result = runner.invoke(main, ["ci", "check"])
aa55498… lmata 446 assert result.exit_code == 0
aa55498… lmata 447 payload = json.loads(result.output)
aa55498… lmata 448 assert payload["status"] == "success"
aa55498… lmata 449 assert payload["data"]["schema_version"] == CURRENT_SCHEMA_VERSION
aa55498… lmata 450
a3b55ee… lmata 451 def test_warning_when_migration_needed(self, monkeypatch):
a3b55ee… lmata 452 _clear_ci_env(monkeypatch)
aa55498… lmata 453 store = MagicMock()
aa55498… lmata 454 store.query.return_value = MagicMock(result_set=[[0]])
aa55498… lmata 455
aa55498… lmata 456 runner = CliRunner()
aa55498… lmata 457 with patch("navegador.cli.commands._get_store", return_value=store):
aa55498… lmata 458 result = runner.invoke(main, ["ci", "check"])
aa55498… lmata 459 assert result.exit_code == 2
aa55498… lmata 460 payload = json.loads(result.output)
aa55498… lmata 461 assert payload["status"] == "warning"
aa55498… lmata 462 assert payload["warnings"]
aa55498… lmata 463
a3b55ee… lmata 464 def test_error_on_store_failure(self, monkeypatch):
a3b55ee… lmata 465 _clear_ci_env(monkeypatch)
aa55498… lmata 466 runner = CliRunner()
aa55498… lmata 467 with patch("navegador.cli.commands._get_store", side_effect=RuntimeError("no db")):
aa55498… lmata 468 result = runner.invoke(main, ["ci", "check"])
aa55498… lmata 469 assert result.exit_code == 1
aa55498… lmata 470 payload = json.loads(result.output)
aa55498… lmata 471 assert payload["status"] == "error"
aa55498… lmata 472
a3b55ee… lmata 473 def test_payload_includes_version_info(self, monkeypatch):
a3b55ee… lmata 474 _clear_ci_env(monkeypatch)
aa55498… lmata 475 from navegador.graph.migrations import CURRENT_SCHEMA_VERSION
aa55498… lmata 476
aa55498… lmata 477 store = MagicMock()
aa55498… lmata 478 store.query.return_value = MagicMock(result_set=[[CURRENT_SCHEMA_VERSION]])
aa55498… lmata 479
aa55498… lmata 480 runner = CliRunner()
aa55498… lmata 481 with patch("navegador.cli.commands._get_store", return_value=store):
aa55498… lmata 482 result = runner.invoke(main, ["ci", "check"])
aa55498… lmata 483 payload = json.loads(result.output)
aa55498… lmata 484 assert "schema_version" in payload["data"]
aa55498… lmata 485 assert "current_schema_version" in payload["data"]

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button