taler-deployment

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

test_package_config.py (4569B)


      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.assertEqual("pnpm-workspace", config.builder_for(library))
     57 
     58     def test_package_builder_override(self):
     59         data = {
     60             **VALID_CONFIG,
     61             "packages": {
     62                 **VALID_CONFIG["packages"],
     63                 "library": {
     64                     **VALID_CONFIG["packages"]["library"],
     65                     "builder": "generic",
     66                 },
     67             },
     68         }
     69         config = parse_config(data)
     70 
     71         self.assertEqual("generic", config.builder_for(config.packages["library"]))
     72 
     73     def test_rejects_unknown_builder(self):
     74         data = {
     75             **VALID_CONFIG,
     76             "repositories": {
     77                 "workspace": {
     78                     **VALID_CONFIG["repositories"]["workspace"],
     79                     "builder": "unknown",
     80                 }
     81             },
     82         }
     83 
     84         with self.assertRaisesRegex(ConfigError, "builder is not supported"):
     85             parse_config(data)
     86 
     87     def test_rejects_unknown_fields_and_references(self):
     88         with self.assertRaisesRegex(ConfigError, "unknown field"):
     89             parse_config({**VALID_CONFIG, "surprise": {}})
     90 
     91         data = {
     92             **VALID_CONFIG,
     93             "packages": {
     94                 **VALID_CONFIG["packages"],
     95                 "library": {
     96                     **VALID_CONFIG["packages"]["library"],
     97                     "repository": "missing",
     98                 },
     99             },
    100         }
    101         with self.assertRaisesRegex(ConfigError, "unknown repository"):
    102             parse_config(data)
    103 
    104     def test_rejects_dependency_cycles(self):
    105         data = {
    106             **VALID_CONFIG,
    107             "packages": {
    108                 **VALID_CONFIG["packages"],
    109                 "library": {
    110                     **VALID_CONFIG["packages"]["library"],
    111                     "dependencies": ["application"],
    112                 },
    113             },
    114         }
    115 
    116         with self.assertRaisesRegex(ConfigError, "application -> library -> application"):
    117             parse_config(data)
    118 
    119     def test_serializer_is_canonical_and_round_trips(self):
    120         config = parse_config(VALID_CONFIG)
    121         serialized = serialize_config(config)
    122 
    123         self.assertEqual(config, parse_config(tomllib.loads(serialized)))
    124         self.assertLess(
    125             serialized.index('[packages."application"]'),
    126             serialized.index('[packages."library"]'),
    127         )
    128         self.assertEqual(serialized, serialize_config(parse_config(tomllib.loads(serialized))))
    129 
    130     def test_write_config_replaces_complete_document(self):
    131         config = parse_config(VALID_CONFIG)
    132         updated_packages = dict(config.packages)
    133         updated_packages["library"] = replace(
    134             updated_packages["library"], tag="v1.2.4"
    135         )
    136         updated = replace(config, packages=updated_packages)
    137 
    138         with tempfile.TemporaryDirectory() as temporary_directory:
    139             path = Path(temporary_directory) / "packages.toml"
    140             path.write_text("old contents\n")
    141             path.chmod(0o640)
    142             write_config(path, updated)
    143 
    144             self.assertEqual(updated, load_config(path))
    145             self.assertEqual(serialize_config(updated), path.read_text())
    146             self.assertEqual(0o640, stat.S_IMODE(path.stat().st_mode))
    147 
    148 
    149 if __name__ == "__main__":
    150     unittest.main()