test_core_version.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # Copyright 2021-2025 Avaiga Private Limited
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. # the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. # specific language governing permissions and limitations under the License.
  11. from unittest import mock
  12. import pytest
  13. from taipy.common.config import Config
  14. from taipy.core import Orchestrator, taipy
  15. from taipy.core._init_version import _read_version
  16. from taipy.core.config.core_section import CoreSection
  17. from taipy.core.exceptions import ConfigCoreVersionMismatched
  18. from taipy.core.scenario._scenario_manager import _ScenarioManager
  19. from tests.core.utils.named_temporary_file import NamedTemporaryFile
  20. _MOCK_CORE_VERSION = "3.1.1"
  21. def patch_core_version(mock_core_version: str):
  22. with mock.patch("taipy.core.config.core_section._read_version") as mock_read_version:
  23. mock_read_version.return_value = mock_core_version
  24. CoreSection._CURRENT_CORE_VERSION = mock_core_version
  25. Config._default_config._unique_sections[CoreSection.name] = CoreSection.default_config()
  26. Config._python_config._unique_sections[CoreSection.name] = CoreSection.default_config()
  27. @pytest.fixture(scope="function", autouse=True)
  28. def mock_core_version():
  29. patch_core_version(_MOCK_CORE_VERSION)
  30. yield
  31. CoreSection._CURRENT_CORE_VERSION = _read_version()
  32. class TestCoreVersionInCoreSectionConfig:
  33. major, minor, patch = _MOCK_CORE_VERSION.split(".")
  34. current_version = f"{major}.{minor}.{patch}"
  35. current_dev_version = f"{major}.{minor}.{patch}.dev0"
  36. compatible_future_version = f"{major}.{minor}.{int(patch) + 1}"
  37. compatible_future_dev_version = f"{major}.{minor}.{int(patch) + 1}.dev0"
  38. core_version_is_compatible = [
  39. # Current version and dev version should be compatible
  40. (f"{major}.{minor}.{patch}", True),
  41. (f"{major}.{minor}.{patch}.dev0", True),
  42. # Future versions with same major and minor should be compatible
  43. (f"{major}.{minor}.{int(patch) + 1}", True),
  44. (f"{major}.{minor}.{int(patch) + 1}.dev0", True),
  45. # Past versions with same major and minor should be compatible
  46. (f"{major}.{minor}.{int(patch) - 1}", True),
  47. (f"{major}.{minor}.{int(patch) - 1}.dev0", True),
  48. # Future versions with different minor number should be incompatible
  49. (f"{major}.{int(minor) + 1}.{patch}", False),
  50. (f"{major}.{int(minor) + 1}.{patch}.dev0", False),
  51. # Past versions with different minor number should be incompatible
  52. (f"{major}.{int(minor) - 1}.{patch}", False),
  53. (f"{major}.{int(minor) - 1}.{patch}.dev0", False),
  54. ]
  55. @pytest.mark.parametrize("core_version, is_compatible", core_version_is_compatible)
  56. def test_load_configuration_file(self, core_version, is_compatible):
  57. file_config = NamedTemporaryFile(
  58. f"""
  59. [TAIPY]
  60. [JOB]
  61. mode = "standalone"
  62. max_nb_of_workers = "2:int"
  63. [CORE]
  64. root_folder = "./taipy/"
  65. storage_folder = ".data/"
  66. repository_type = "filesystem"
  67. read_entity_retry = "0:int"
  68. mode = "development"
  69. version_number = ""
  70. force = "False:bool"
  71. core_version = "{core_version}"
  72. """
  73. )
  74. if is_compatible:
  75. Config.load(file_config.filename)
  76. assert Config.unique_sections[CoreSection.name]._core_version == _MOCK_CORE_VERSION
  77. else:
  78. with pytest.raises(ConfigCoreVersionMismatched):
  79. Config.load(file_config.filename)
  80. @pytest.mark.parametrize("core_version,is_compatible", core_version_is_compatible)
  81. def test_override_configuration_file(self, core_version, is_compatible):
  82. file_config = NamedTemporaryFile(
  83. f"""
  84. [TAIPY]
  85. [JOB]
  86. mode = "standalone"
  87. max_nb_of_workers = "2:int"
  88. [CORE]
  89. root_folder = "./taipy/"
  90. storage_folder = ".data/"
  91. repository_type = "filesystem"
  92. read_entity_retry = "0:int"
  93. mode = "development"
  94. version_number = ""
  95. force = "False:bool"
  96. core_version = "{core_version}"
  97. """
  98. )
  99. if is_compatible:
  100. Config.override(file_config.filename)
  101. assert Config.unique_sections[CoreSection.name]._core_version == _MOCK_CORE_VERSION
  102. else:
  103. with pytest.raises(ConfigCoreVersionMismatched):
  104. Config.override(file_config.filename)
  105. def test_load_configuration_file_without_core_section(self):
  106. file_config = NamedTemporaryFile(
  107. """
  108. [TAIPY]
  109. [JOB]
  110. mode = "standalone"
  111. max_nb_of_workers = "2:int"
  112. [CORE]
  113. root_folder = "./taipy/"
  114. storage_folder = ".data/"
  115. repository_type = "filesystem"
  116. read_entity_retry = "0:int"
  117. mode = "development"
  118. version_number = ""
  119. force = "False:bool"
  120. """
  121. )
  122. Config.load(file_config.filename)
  123. assert Config.unique_sections[CoreSection.name]._core_version == _MOCK_CORE_VERSION
  124. def test_run_core_app_with_different_taipy_core_version_in_development_mode(self):
  125. with mock.patch("sys.argv", ["prog", "--development"]):
  126. run_application()
  127. # Run the application with a compatible version should NOT raise any error
  128. patch_core_version(f"{self.major}.{self.minor}.{self.patch}.dev0")
  129. with mock.patch("sys.argv", ["prog", "--development"]):
  130. run_application()
  131. # Run the application with an incompatible version in development mode should NOT raise an error
  132. patch_core_version(f"{self.major}.{int(self.minor) + 1}.{self.patch}.dev0")
  133. with mock.patch("sys.argv", ["prog", "--development"]):
  134. run_application()
  135. def test_run_core_app_with_different_taipy_core_version_in_experiment_mode(self, caplog):
  136. with mock.patch("sys.argv", ["prog", "--experiment", "1.0"]):
  137. run_application()
  138. # Run the application with a compatible version should not raise any error
  139. patch_core_version(f"{self.major}.{self.minor}.{int(self.patch) + 1}.dev0")
  140. with mock.patch("sys.argv", ["prog", "--experiment", "1.0"]):
  141. run_application()
  142. # Run the application with an incompatible version in experiment mode should raise SystemExit and log the error
  143. patch_core_version(f"{self.major}.{int(self.minor) + 1}.{self.patch}.dev0")
  144. with mock.patch("sys.argv", ["prog", "--experiment", "1.0"]):
  145. with pytest.raises(SystemExit):
  146. run_application()
  147. assert (
  148. f"The version {self.major}.{self.minor}.{self.patch} of Taipy's entities does not match version "
  149. f"of the Taipy Version management {self.major}.{int(self.minor) + 1}.{self.patch}.dev0"
  150. ) in caplog.text
  151. def twice(a):
  152. return [a * 2]
  153. def run_application():
  154. Config.configure_data_node(id="d0")
  155. data_node_1_config = Config.configure_data_node(id="d1", storage_type="pickle", default_data="abc")
  156. data_node_2_config = Config.configure_data_node(id="d2", storage_type="csv")
  157. task_config = Config.configure_task("my_task", twice, data_node_1_config, data_node_2_config)
  158. scenario_config = Config.configure_scenario("my_scenario", [task_config])
  159. scenario_config.add_sequences({"my_sequence": [task_config]})
  160. orchestrator = Orchestrator()
  161. orchestrator.run()
  162. scenario = _ScenarioManager._create(scenario_config)
  163. taipy.submit(scenario)
  164. orchestrator.stop()