import tempfile import unittest from pathlib import Path from hydra.profiles import Profile, load_profile, save_profile class ProfilesTests(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory(prefix='hydra-test-') self.addCleanup(self.tmp.cleanup) self.root = Path(self.tmp.name) self.iso = self.root / 'installer with spaces,comma.iso' self.iso.touch() def test_roundtrip_paths_and_defaults(self): profile = Profile('guest', self.iso) save_profile(self.root / 'guest.toml', profile) loaded = load_profile(self.root / 'guest.toml') self.assertEqual(loaded.iso, self.iso) self.assertEqual((loaded.memory, loaded.cpus, loaded.disk_size), (4096, 2, '40G')) self.assertEqual((loaded.graphics, loaded.network, loaded.bridge), ('auto', 'user', 'hydrabr0')) def test_invalid_names_resources_and_modes(self): for name in ('', '../guest', 'Guest', '-guest', 'a' * 33, 'a\n'): with self.subTest(name=name), self.assertRaises(ValueError): Profile(name, self.iso) for field, values in {'memory': (0, -1, True, '4096'), 'cpus': (0, -1, True, 257), 'disk_size': ('0G', '-1G', '40G,evil', '40'), 'graphics': ('gl',), 'network': ('public',), 'bridge': ('../bad', 'a,evil')}.items(): for value in values: with self.subTest(field=field, value=value), self.assertRaises(ValueError): Profile('guest', self.iso, **{field: value}) def test_invalid_media_path_types(self): for iso in (True, 42, ''): with self.subTest(iso=iso), self.assertRaises(ValueError): Profile('guest', iso) def test_duplicate_profile_preserves_existing(self): dest = self.root / 'guest.toml' save_profile(dest, Profile('guest', self.iso)) original = dest.read_bytes() with self.assertRaises(FileExistsError): save_profile(dest, Profile('guest', self.iso, memory=8192)) self.assertEqual(dest.read_bytes(), original) def test_disk_only_profile_roundtrips_without_media(self): dest = self.root / 'guest.toml' save_profile(dest, Profile('guest')) self.assertIsNone(load_profile(dest).iso) self.assertNotIn('iso =', dest.read_text()) def test_missing_media_does_not_block_loading_profile(self): dest = self.root / 'guest.toml' save_profile(dest, Profile('guest', self.iso)) self.iso.unlink() self.assertEqual(load_profile(dest).iso, self.iso) def test_display_bounds_and_types(self): for field, values in {'width': (0, True, 16385), 'height': (0, '1080', 16385), 'refresh_millihz': (-1, True, 1000001)}.items(): for value in values: with self.subTest(field=field, value=value), self.assertRaises(ValueError): Profile('guest', self.iso, **{field: value}) def test_explicit_mac_roundtrip_and_validation(self): dest = self.root / 'guest.toml' save_profile(dest, Profile('guest', mac='02:ab:cd:ef:01:23')) self.assertEqual(load_profile(dest).mac, '02:ab:cd:ef:01:23') for value in ('ff:00:00:00:00:01', '00:00:00:00:00:01', '02:00:00:00:00:zz', '02:00:00:00:00', True): with self.subTest(mac=value), self.assertRaises(ValueError): Profile('guest', mac=value) def test_refresh_vertical_descriptor_boundaries(self): for value in (0, 50000, 255000): path = self.root / 'guest.toml' save_profile(path, Profile('guest', refresh_millihz=value)) self.assertEqual(load_profile(path).refresh_millihz, value) path.unlink() for value in (1, 30000, 49999, 255001, 1000000): with self.subTest(refresh=value), self.assertRaises(ValueError): Profile('guest', refresh_millihz=value) def test_profile_name_must_match_filename(self): path = self.root / 'guest.toml' path.write_text(f'name = "other"\niso = "{self.iso}"\n') with self.assertRaises(ValueError): load_profile(path) if __name__ == '__main__': unittest.main()