test_config.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # This file is part of Radicale - CalDAV and CardDAV server
  2. # Copyright © 2019 Unrud <unrud@outlook.com>
  3. #
  4. # This library is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  16. import os
  17. import shutil
  18. import tempfile
  19. from configparser import RawConfigParser
  20. from typing import List, Tuple
  21. import pytest
  22. from radicale import config, types
  23. from radicale.tests.helpers import configuration_to_dict
  24. class TestConfig:
  25. """Test the configuration."""
  26. colpath: str
  27. def setup_method(self) -> None:
  28. self.colpath = tempfile.mkdtemp()
  29. def teardown_method(self) -> None:
  30. shutil.rmtree(self.colpath)
  31. def _write_config(self, config_dict: types.CONFIG, name: str) -> str:
  32. parser = RawConfigParser()
  33. parser.read_dict(config_dict)
  34. config_path = os.path.join(self.colpath, name)
  35. with open(config_path, "w") as f:
  36. parser.write(f)
  37. return config_path
  38. def test_parse_compound_paths(self) -> None:
  39. assert len(config.parse_compound_paths()) == 0
  40. assert len(config.parse_compound_paths("")) == 0
  41. assert len(config.parse_compound_paths(None, "")) == 0
  42. assert len(config.parse_compound_paths("config", "")) == 0
  43. assert len(config.parse_compound_paths("config", None)) == 1
  44. assert len(config.parse_compound_paths(os.pathsep.join(["", ""]))) == 0
  45. assert len(config.parse_compound_paths(os.pathsep.join([
  46. "", "config", ""]))) == 1
  47. paths = config.parse_compound_paths(os.pathsep.join([
  48. "config1", "?config2", "config3"]))
  49. assert len(paths) == 3
  50. for i, (name, ignore_if_missing) in enumerate([
  51. ("config1", False), ("config2", True), ("config3", False)]):
  52. assert os.path.isabs(paths[i][0])
  53. assert os.path.basename(paths[i][0]) == name
  54. assert paths[i][1] is ignore_if_missing
  55. def test_load_empty(self) -> None:
  56. config_path = self._write_config({}, "config")
  57. config.load([(config_path, False)])
  58. def test_load_full(self) -> None:
  59. config_path = self._write_config(
  60. configuration_to_dict(config.load()), "config")
  61. config.load([(config_path, False)])
  62. def test_load_missing(self) -> None:
  63. config_path = os.path.join(self.colpath, "does_not_exist")
  64. config.load([(config_path, True)])
  65. with pytest.raises(Exception) as exc_info:
  66. config.load([(config_path, False)])
  67. e = exc_info.value
  68. assert "Failed to load config file %r" % config_path in str(e)
  69. def test_load_multiple(self) -> None:
  70. config_path1 = self._write_config({
  71. "server": {"hosts": "192.0.2.1:1111"}}, "config1")
  72. config_path2 = self._write_config({
  73. "server": {"max_connections": 1111}}, "config2")
  74. configuration = config.load([(config_path1, False),
  75. (config_path2, False)])
  76. server_hosts: List[Tuple[str, int]] = configuration.get(
  77. "server", "hosts")
  78. assert len(server_hosts) == 1
  79. assert server_hosts[0] == ("192.0.2.1", 1111)
  80. assert configuration.get("server", "max_connections") == 1111
  81. def test_copy(self) -> None:
  82. configuration1 = config.load()
  83. configuration1.update({"server": {"max_connections": "1111"}}, "test")
  84. configuration2 = configuration1.copy()
  85. configuration2.update({"server": {"max_connections": "1112"}}, "test")
  86. assert configuration1.get("server", "max_connections") == 1111
  87. assert configuration2.get("server", "max_connections") == 1112
  88. def test_invalid_section(self) -> None:
  89. configuration = config.load()
  90. with pytest.raises(Exception) as exc_info:
  91. configuration.update({"does_not_exist": {"x": "x"}}, "test")
  92. e = exc_info.value
  93. assert "Invalid section 'does_not_exist'" in str(e)
  94. def test_invalid_option(self) -> None:
  95. configuration = config.load()
  96. with pytest.raises(Exception) as exc_info:
  97. configuration.update({"server": {"x": "x"}}, "test")
  98. e = exc_info.value
  99. assert "Invalid option 'x'" in str(e)
  100. assert "section 'server'" in str(e)
  101. def test_invalid_option_plugin(self) -> None:
  102. configuration = config.load()
  103. with pytest.raises(Exception) as exc_info:
  104. configuration.update({"auth": {"x": "x"}}, "test")
  105. e = exc_info.value
  106. assert "Invalid option 'x'" in str(e)
  107. assert "section 'auth'" in str(e)
  108. def test_invalid_value(self) -> None:
  109. configuration = config.load()
  110. with pytest.raises(Exception) as exc_info:
  111. configuration.update({"server": {"max_connections": "x"}}, "test")
  112. e = exc_info.value
  113. assert "Invalid positive_int" in str(e)
  114. assert "option 'max_connections" in str(e)
  115. assert "section 'server" in str(e)
  116. assert "'x'" in str(e)
  117. def test_privileged(self) -> None:
  118. configuration = config.load()
  119. configuration.update({"server": {"_internal_server": "True"}},
  120. "test", privileged=True)
  121. with pytest.raises(Exception) as exc_info:
  122. configuration.update(
  123. {"server": {"_internal_server": "True"}}, "test")
  124. e = exc_info.value
  125. assert "Invalid option '_internal_server'" in str(e)
  126. def test_plugin_schema(self) -> None:
  127. plugin_schema: types.CONFIG_SCHEMA = {
  128. "auth": {"new_option": {"value": "False", "type": bool}}}
  129. configuration = config.load()
  130. configuration.update({"auth": {"type": "new_plugin"}}, "test")
  131. plugin_configuration = configuration.copy(plugin_schema)
  132. assert plugin_configuration.get("auth", "new_option") is False
  133. configuration.update({"auth": {"new_option": "True"}}, "test")
  134. plugin_configuration = configuration.copy(plugin_schema)
  135. assert plugin_configuration.get("auth", "new_option") is True
  136. def test_plugin_schema_duplicate_option(self) -> None:
  137. plugin_schema: types.CONFIG_SCHEMA = {
  138. "auth": {"type": {"value": "False", "type": bool}}}
  139. configuration = config.load()
  140. with pytest.raises(Exception) as exc_info:
  141. configuration.copy(plugin_schema)
  142. e = exc_info.value
  143. assert "option already exists in 'auth': 'type'" in str(e)
  144. def test_plugin_schema_invalid(self) -> None:
  145. plugin_schema: types.CONFIG_SCHEMA = {
  146. "server": {"new_option": {"value": "False", "type": bool}}}
  147. configuration = config.load()
  148. with pytest.raises(Exception) as exc_info:
  149. configuration.copy(plugin_schema)
  150. e = exc_info.value
  151. assert "not a plugin section: 'server" in str(e)
  152. def test_plugin_schema_option_invalid(self) -> None:
  153. plugin_schema: types.CONFIG_SCHEMA = {"auth": {}}
  154. configuration = config.load()
  155. configuration.update({"auth": {"type": "new_plugin",
  156. "new_option": False}}, "test")
  157. with pytest.raises(Exception) as exc_info:
  158. configuration.copy(plugin_schema)
  159. e = exc_info.value
  160. assert "Invalid option 'new_option'" in str(e)
  161. assert "section 'auth'" in str(e)