taler-deployment

Deployment scripts and configuration files
Log | Files | Refs | README

test_package_config.py (5590B)


      1 #!/usr/bin/env python3
      2 
      3 # This file is in the public domain.
      4 
      5 import sys
      6 import tempfile
      7 import tomllib
      8 import unittest
      9 import stat
     10 from dataclasses import replace
     11 from pathlib import Path
     12 
     13 BUILDSCRIPTS = Path(__file__).parents[1] / "buildscripts"
     14 sys.path.insert(0, str(BUILDSCRIPTS))
     15 
     16 from package_config import (  # noqa: E402
     17     ConfigError,
     18     load_config,
     19     parse_config,
     20     serialize_config,
     21     write_config,
     22 )
     23 
     24 
     25 VALID_CONFIG = {
     26     "repositories": {
     27         "workspace": {
     28             "url": "git://example.test/workspace.git",
     29             "builder": "pnpm-workspace",
     30         }
     31     },
     32     "packages": {
     33         "application": {
     34             "repository": "workspace",
     35             "tag": "v1.2.3",
     36             "debian_path": "packages/application",
     37             "dependencies": ["library"],
     38             "enabled": True,
     39         },
     40         "library": {
     41             "repository": "workspace",
     42             "tag": "v1.2.2",
     43         },
     44     },
     45 }
     46 
     47 
     48 class PackageConfigTests(unittest.TestCase):
     49     def test_defaults_and_builder_inheritance(self):
     50         config = parse_config(VALID_CONFIG)
     51 
     52         library = config.packages["library"]
     53         self.assertEqual("", library.debian_path)
     54         self.assertEqual((), library.dependencies)
     55         self.assertTrue(library.enabled)
     56         self.assertTrue(library.auto_upgrade)
     57         self.assertEqual("pnpm-workspace", config.builder_for(library))
     58 
     59     def test_auto_upgrade_can_be_disabled(self):
     60         data = {
     61             **VALID_CONFIG,
     62             "packages": {
     63                 **VALID_CONFIG["packages"],
     64                 "library": {
     65                     **VALID_CONFIG["packages"]["library"],
     66                     "auto_upgrade": False,
     67                 },
     68             },
     69         }
     70 
     71         config = parse_config(data)
     72 
     73         self.assertFalse(config.packages["library"].auto_upgrade)
     74         self.assertIn("auto_upgrade = false", serialize_config(config))
     75 
     76     def test_rejects_non_boolean_auto_upgrade(self):
     77         data = {
     78             **VALID_CONFIG,
     79             "packages": {
     80                 **VALID_CONFIG["packages"],
     81                 "library": {
     82                     **VALID_CONFIG["packages"]["library"],
     83                     "auto_upgrade": "no",
     84                 },
     85             },
     86         }
     87 
     88         with self.assertRaisesRegex(ConfigError, "auto_upgrade must be a boolean"):
     89             parse_config(data)
     90 
     91     def test_package_builder_override(self):
     92         data = {
     93             **VALID_CONFIG,
     94             "packages": {
     95                 **VALID_CONFIG["packages"],
     96                 "library": {
     97                     **VALID_CONFIG["packages"]["library"],
     98                     "builder": "generic",
     99                 },
    100             },
    101         }
    102         config = parse_config(data)
    103 
    104         self.assertEqual("generic", config.builder_for(config.packages["library"]))
    105 
    106     def test_rejects_unknown_builder(self):
    107         data = {
    108             **VALID_CONFIG,
    109             "repositories": {
    110                 "workspace": {
    111                     **VALID_CONFIG["repositories"]["workspace"],
    112                     "builder": "unknown",
    113                 }
    114             },
    115         }
    116 
    117         with self.assertRaisesRegex(ConfigError, "builder is not supported"):
    118             parse_config(data)
    119 
    120     def test_rejects_unknown_fields_and_references(self):
    121         with self.assertRaisesRegex(ConfigError, "unknown field"):
    122             parse_config({**VALID_CONFIG, "surprise": {}})
    123 
    124         data = {
    125             **VALID_CONFIG,
    126             "packages": {
    127                 **VALID_CONFIG["packages"],
    128                 "library": {
    129                     **VALID_CONFIG["packages"]["library"],
    130                     "repository": "missing",
    131                 },
    132             },
    133         }
    134         with self.assertRaisesRegex(ConfigError, "unknown repository"):
    135             parse_config(data)
    136 
    137     def test_rejects_dependency_cycles(self):
    138         data = {
    139             **VALID_CONFIG,
    140             "packages": {
    141                 **VALID_CONFIG["packages"],
    142                 "library": {
    143                     **VALID_CONFIG["packages"]["library"],
    144                     "dependencies": ["application"],
    145                 },
    146             },
    147         }
    148 
    149         with self.assertRaisesRegex(ConfigError, "application -> library -> application"):
    150             parse_config(data)
    151 
    152     def test_serializer_is_canonical_and_round_trips(self):
    153         config = parse_config(VALID_CONFIG)
    154         serialized = serialize_config(config)
    155 
    156         self.assertEqual(config, parse_config(tomllib.loads(serialized)))
    157         self.assertLess(
    158             serialized.index('[packages."application"]'),
    159             serialized.index('[packages."library"]'),
    160         )
    161         self.assertEqual(serialized, serialize_config(parse_config(tomllib.loads(serialized))))
    162 
    163     def test_write_config_replaces_complete_document(self):
    164         config = parse_config(VALID_CONFIG)
    165         updated_packages = dict(config.packages)
    166         updated_packages["library"] = replace(
    167             updated_packages["library"], tag="v1.2.4"
    168         )
    169         updated = replace(config, packages=updated_packages)
    170 
    171         with tempfile.TemporaryDirectory() as temporary_directory:
    172             path = Path(temporary_directory) / "packages.toml"
    173             path.write_text("old contents\n")
    174             path.chmod(0o640)
    175             write_config(path, updated)
    176 
    177             self.assertEqual(updated, load_config(path))
    178             self.assertEqual(serialize_config(updated), path.read_text())
    179             self.assertEqual(0o640, stat.S_IMODE(path.stat().st_mode))
    180 
    181 
    182 if __name__ == "__main__":
    183     unittest.main()