test_inventory_wizard.py (5570B)
1 import importlib.util 2 import os 3 import tempfile 4 import unittest 5 from pathlib import Path 6 from unittest import mock 7 8 9 MODULE_PATH = Path(__file__).parents[1] / "inventory-wizard.py" 10 SPEC = importlib.util.spec_from_file_location("inventory_wizard", MODULE_PATH) 11 assert SPEC and SPEC.loader 12 inventory_wizard = importlib.util.module_from_spec(SPEC) 13 SPEC.loader.exec_module(inventory_wizard) 14 15 16 class InventoryWriteTests(unittest.TestCase): 17 def test_targets_are_independent_and_private(self): 18 with tempfile.TemporaryDirectory() as temporary_directory: 19 directory = Path(temporary_directory) 20 first = inventory_wizard.write_target( 21 directory, 22 "first", 23 {"ansible_host": "first.example", "custom_value": "preserved"}, 24 ) 25 second = inventory_wizard.write_target( 26 directory, "second", {"ansible_host": "second.example"} 27 ) 28 29 first_values, first_legacy = inventory_wizard.load_target( 30 directory, "first" 31 ) 32 first_values["ansible_host"] = "new-first.example" 33 inventory_wizard.write_target(directory, "first", first_values) 34 first_values, _ = inventory_wizard.load_target(directory, "first") 35 second_values, second_legacy = inventory_wizard.load_target( 36 directory, "second" 37 ) 38 39 self.assertEqual(first_values["ansible_host"], "new-first.example") 40 self.assertEqual(first_values["custom_value"], "preserved") 41 self.assertEqual(second_values["ansible_host"], "second.example") 42 self.assertFalse(first_legacy) 43 self.assertFalse(second_legacy) 44 self.assertEqual(first.stat().st_mode & 0o777, 0o600) 45 self.assertEqual(second.stat().st_mode & 0o777, 0o600) 46 47 def test_failed_replace_preserves_existing_inventory(self): 48 with tempfile.TemporaryDirectory() as temporary_directory: 49 directory = Path(temporary_directory) 50 target = inventory_wizard.write_target( 51 directory, "target", {"ansible_host": "old.example"} 52 ) 53 original = target.read_bytes() 54 55 with mock.patch.object(os, "replace", side_effect=OSError("failed")): 56 with self.assertRaises(OSError): 57 inventory_wizard.write_target( 58 directory, "target", {"ansible_host": "new.example"} 59 ) 60 61 self.assertEqual(target.read_bytes(), original) 62 self.assertEqual(list(directory.glob(".target.yml.*")), []) 63 64 65 class InventoryPromptTests(unittest.TestCase): 66 def test_conversion_test_mode_keeps_nexus_services_disabled(self): 67 answers = { 68 "SSH host name or address": "conversion.example", 69 "SSH user": "root", 70 "Base domain for the service hosts and optional landing page": "conversion.example", 71 "Human-readable bank name": "Test Bank", 72 "Fiat bank name": "Synthetic Bank", 73 "Fiat account legal name": "Synthetic Account", 74 } 75 matching_answers = { 76 "Inventory host name to add or update": "conversion-test", 77 "Regional currency code": "FLODOS", 78 "Fiat currency code": "CHF", 79 "Fiat account IBAN": "CH8615624QG38ANY0UVER", 80 "Fiat account BIC": "TSTRCHZZXXX", 81 } 82 boolean_answers = { 83 "Configure a testing deployment": True, 84 "Configure a landing page on the base domain": True, 85 "Obtain TLS certificates using Let's Encrypt": False, 86 "Configure conversion to a fiat currency": True, 87 "Use simulated conversion test mode (no EBICS bank connection)": True, 88 "Configure Telesign SMS authentication": False, 89 "Configure exchange terms of service": False, 90 "Configure an exchange privacy policy": False, 91 "Use the GNU Taler testing APT repository (Debian only)": True, 92 } 93 94 def ask(message, default=None, **_kwargs): 95 return answers.get(message, default) 96 97 def ask_matching(message, _pattern, default=None, **_kwargs): 98 return matching_answers.get(message, default) 99 100 def ask_yes_no(message, _default): 101 if message.startswith("Enable Nexus services"): 102 self.fail("test mode must not offer to enable Nexus services") 103 return boolean_answers[message] 104 105 with tempfile.TemporaryDirectory() as temporary_directory: 106 with ( 107 mock.patch.object(inventory_wizard, "ask", side_effect=ask), 108 mock.patch.object( 109 inventory_wizard, "ask_matching", side_effect=ask_matching 110 ), 111 mock.patch.object( 112 inventory_wizard, "ask_yes_no", side_effect=ask_yes_no 113 ), 114 mock.patch.object( 115 inventory_wizard, "ask_int", side_effect=lambda _m, d: d 116 ), 117 mock.patch.object( 118 inventory_wizard.getpass, "getpass", return_value="secret" 119 ), 120 ): 121 _, _, variables, _, _, _ = inventory_wizard.collect_configuration( 122 Path(temporary_directory) 123 ) 124 125 self.assertTrue(variables["regional_currency_conversion_test_mode"]) 126 self.assertFalse(variables["regional_currency_enable_nexus_services"]) 127 128 129 if __name__ == "__main__": 130 unittest.main()