Sync from dev @ 252c1cf
Source: main (252c1cf) Excluded: live tenant exports, generated artifacts, and dev-only tooling.
This commit is contained in:
157
tests/test_validate_backup_outputs.py
Normal file
157
tests/test_validate_backup_outputs.py
Normal file
@@ -0,0 +1,157 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "validate_backup_outputs.py"
|
||||
|
||||
|
||||
def run_validator(*args: str) -> subprocess.CompletedProcess[str]:
|
||||
cmd = [sys.executable, str(SCRIPT_PATH), *args]
|
||||
return subprocess.run(cmd, check=False, text=True, capture_output=True)
|
||||
|
||||
|
||||
class ValidateBackupOutputsTests(unittest.TestCase):
|
||||
def test_intune_validation_passes_with_required_outputs(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
base = Path(td)
|
||||
root = base / "tenant-state" / "intune"
|
||||
reports = base / "tenant-state" / "reports" / "intune"
|
||||
(root / "Device Configurations").mkdir(parents=True, exist_ok=True)
|
||||
reports.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
(root / "Device Configurations" / "policy__id.json").write_text(
|
||||
json.dumps({"id": "id-1", "displayName": "Policy"}) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(reports / "policy-assignments.md").write_text("# report\n", encoding="utf-8")
|
||||
(reports / "policy-assignments.csv").write_text("a,b\n", encoding="utf-8")
|
||||
(reports / "object-inventory-all.csv").write_text("a,b\n", encoding="utf-8")
|
||||
|
||||
result = run_validator(
|
||||
"--workload",
|
||||
"intune",
|
||||
"--mode",
|
||||
"light",
|
||||
"--root",
|
||||
str(root),
|
||||
"--reports-root",
|
||||
str(reports),
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
|
||||
|
||||
def test_intune_validation_fails_when_assignment_csv_missing(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
base = Path(td)
|
||||
root = base / "tenant-state" / "intune"
|
||||
reports = base / "tenant-state" / "reports" / "intune"
|
||||
(root / "Device Configurations").mkdir(parents=True, exist_ok=True)
|
||||
reports.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
(root / "Device Configurations" / "policy__id.json").write_text("{}", encoding="utf-8")
|
||||
(reports / "policy-assignments.md").write_text("# report\n", encoding="utf-8")
|
||||
(reports / "object-inventory-all.csv").write_text("a,b\n", encoding="utf-8")
|
||||
|
||||
result = run_validator(
|
||||
"--workload",
|
||||
"intune",
|
||||
"--mode",
|
||||
"full",
|
||||
"--root",
|
||||
str(root),
|
||||
"--reports-root",
|
||||
str(reports),
|
||||
)
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("Missing Intune assignment CSV report", result.stdout)
|
||||
|
||||
def test_entra_light_validation_allows_non_effective_enterprise_apps(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
base = Path(td)
|
||||
root = base / "tenant-state" / "entra"
|
||||
reports = base / "tenant-state" / "reports" / "entra"
|
||||
(root / "Named Locations").mkdir(parents=True, exist_ok=True)
|
||||
reports.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
(root / "Named Locations" / "Named Locations.md").write_text("# named\n", encoding="utf-8")
|
||||
(reports / "object-inventory-all.csv").write_text("a,b\n", encoding="utf-8")
|
||||
|
||||
result = run_validator(
|
||||
"--workload",
|
||||
"entra",
|
||||
"--mode",
|
||||
"light",
|
||||
"--root",
|
||||
str(root),
|
||||
"--reports-root",
|
||||
str(reports),
|
||||
"--include-named-locations",
|
||||
"true",
|
||||
"--include-enterprise-applications",
|
||||
"true",
|
||||
"--include-enterprise-applications-effective",
|
||||
"false",
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
|
||||
|
||||
def test_entra_light_validation_allows_non_effective_app_registrations(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
base = Path(td)
|
||||
root = base / "tenant-state" / "entra"
|
||||
reports = base / "tenant-state" / "reports" / "entra"
|
||||
(root / "Named Locations").mkdir(parents=True, exist_ok=True)
|
||||
reports.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
(root / "Named Locations" / "Named Locations.md").write_text("# named\n", encoding="utf-8")
|
||||
(reports / "object-inventory-all.csv").write_text("a,b\n", encoding="utf-8")
|
||||
|
||||
result = run_validator(
|
||||
"--workload",
|
||||
"entra",
|
||||
"--mode",
|
||||
"light",
|
||||
"--root",
|
||||
str(root),
|
||||
"--reports-root",
|
||||
str(reports),
|
||||
"--include-named-locations",
|
||||
"true",
|
||||
"--include-app-registrations",
|
||||
"true",
|
||||
"--include-app-registrations-effective",
|
||||
"false",
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
|
||||
|
||||
def test_entra_validation_fails_when_required_index_missing(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
base = Path(td)
|
||||
root = base / "tenant-state" / "entra"
|
||||
reports = base / "tenant-state" / "reports" / "entra"
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
reports.mkdir(parents=True, exist_ok=True)
|
||||
(reports / "object-inventory-all.csv").write_text("a,b\n", encoding="utf-8")
|
||||
|
||||
result = run_validator(
|
||||
"--workload",
|
||||
"entra",
|
||||
"--mode",
|
||||
"full",
|
||||
"--root",
|
||||
str(root),
|
||||
"--reports-root",
|
||||
str(reports),
|
||||
"--include-named-locations",
|
||||
"true",
|
||||
)
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("Missing Entra export index for 'Named Locations'", result.stdout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user