test_schema.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #
  2. # Copyright 2018-2022 Elyra Authors
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import copy
  17. import os
  18. from typing import List
  19. from typing import Optional
  20. from entrypoints import EntryPoint
  21. import pytest
  22. from elyra.metadata.schema import METADATA_TEST_SCHEMASPACE_ID
  23. from elyra.metadata.schema import SchemaManager
  24. from elyra.metadata.schema import Schemaspace
  25. from elyra.metadata.schema import SchemasProvider
  26. from elyra.tests.metadata.test_utils import BYOSchemaspace
  27. from elyra.tests.metadata.test_utils import NON_EXISTENT_SCHEMASPACE_ID
  28. """ This file contains tests for testing SchemaManager, Schemaspace and SchemasProvider classes """
  29. os.environ["METADATA_TESTING"] = "1" # Enable metadata-tests schemaspace
  30. schemaspace_map = {
  31. "metadata-tests": ("elyra.tests.metadata.test_utils", "MetadataTestSchemaspace"),
  32. "byo_schemaspace_bad_id": ("elyra.tests.metadata.test_utils", "BYOSchemaspaceBadId"),
  33. "byo.schemaspace-bad.name": ("elyra.tests.metadata.test_utils", "BYOSchemaspaceBadName"),
  34. "byo.schemaspace_CaseSensitiveName": ("elyra.tests.metadata.test_utils", "BYOSchemaspaceCaseSensitiveName"),
  35. "byo-schemaspace": ("elyra.tests.metadata.test_utils", "BYOSchemaspace"),
  36. "byo-schemaspace-bad-class": ("elyra.tests.metadata.test_utils", "BYOSchemaspaceBadClass"),
  37. "byo-schemaspace-throws": ("elyra.tests.metadata.test_utils", "BYOSchemaspaceThrows"),
  38. }
  39. schemas_provider_map = {
  40. "metadata-tests": ("elyra.tests.metadata.test_utils", "MetadataTestSchemasProvider"),
  41. "byo-schemas-provider-throws": ("elyra.tests.metadata.test_utils", "BYOSchemasProviderThrows"),
  42. "byo-schemas-provider-bad-class": ("elyra.tests.metadata.test_utils", "BYOSchemasProviderBadClass"),
  43. "byo-schemas-provider": ("elyra.tests.metadata.test_utils", "BYOSchemasProvider"),
  44. }
  45. def mock_get_schemaspaces(ep_map: Optional[dict] = None) -> List[EntryPoint]:
  46. result = []
  47. if ep_map is None:
  48. ep_map = schemaspace_map
  49. for name, epstr in ep_map.items():
  50. result.append(EntryPoint(name, epstr[0], epstr[1]))
  51. return result
  52. def mock_get_schemas_providers(ep_map: Optional[dict] = None) -> List[EntryPoint]:
  53. result = []
  54. if ep_map is None:
  55. ep_map = schemas_provider_map
  56. for name, epstr in ep_map.items():
  57. result.append(EntryPoint(name, epstr[0], epstr[1]))
  58. return result
  59. @pytest.fixture
  60. def byo_schemaspaces(monkeypatch):
  61. """Setup the BYO Schemaspaces and SchemasProviders, returning the SchemaManager instance."""
  62. monkeypatch.setattr(SchemaManager, "_get_schemaspaces", mock_get_schemaspaces)
  63. monkeypatch.setattr(SchemaManager, "_get_schemas_providers", mock_get_schemas_providers)
  64. yield # We must clear the SchemaManager instance else follow-on tests will be side-effected
  65. SchemaManager.clear_instance()
  66. def test_validate_factory_schemas():
  67. # Test that each of our factory schemas meet the minimum requirements.
  68. # This is accomplished by merely accessing the schemas of the schemaspace
  69. # and ensuring their presence.
  70. schema_mgr = SchemaManager.instance() # validation actually happens here
  71. schemaspace_names = schema_mgr.get_schemaspace_names()
  72. for schemaspace_name in schemaspace_names:
  73. schemaspace = schema_mgr.get_schemaspace(schemaspace_name)
  74. for name, schema in schemaspace.schemas.items():
  75. print(f"Schema '{schemaspace_name}/{name}' is valid.")
  76. # ########################## SchemaManager, Schemaspace and SchemasProvider Tests ###########################
  77. def test_schemaspace_display_name():
  78. """Ensures that display_name properly defaults from name (or not when provided itself)."""
  79. schema_mgr = SchemaManager.instance()
  80. # Only metadata-tests have matching name and display_name values
  81. schemaspace = schema_mgr.get_schemaspace("metadata-tests")
  82. assert schemaspace.name == "metadata-tests"
  83. assert schemaspace.display_name == schemaspace.name
  84. # All others have a separate name, we'll check runtime-images
  85. schemaspace = schema_mgr.get_schemaspace("runtime-images")
  86. assert schemaspace.name == "runtime-images"
  87. assert schemaspace.display_name == "Runtime Images"
  88. def test_schema_no_side_effect():
  89. """Ensures that schemas returned from get_schema_schemas can be altered and not side-effect the next access."""
  90. schema_mgr = SchemaManager.instance()
  91. schemas = schema_mgr.get_schemaspace_schemas(METADATA_TEST_SCHEMASPACE_ID)
  92. for name, schema in schemas.items():
  93. if name == "metadata-test":
  94. orig_schema = copy.deepcopy(schema_mgr.get_schema(METADATA_TEST_SCHEMASPACE_ID, name)) # capture good copy
  95. schema["metadata_class_name"] = "bad_class"
  96. assert schema != orig_schema
  97. fresh_schema = schema_mgr.get_schema(METADATA_TEST_SCHEMASPACE_ID, name)
  98. assert fresh_schema == orig_schema
  99. def test_byo_schema(byo_schemaspaces):
  100. """Validates that the expected number of BYO schemas exist (2 of 4 are valid)"""
  101. SchemaManager.clear_instance()
  102. schema_mgr = SchemaManager.instance()
  103. byo_ss = schema_mgr.get_schemaspace(BYOSchemaspace.BYO_SCHEMASPACE_ID)
  104. assert len(byo_ss.schemas) == 2
  105. for name, schema in byo_ss.schemas.items():
  106. assert schema["name"] in ["byo-test-0", "byo-test-1"]
  107. def test_schemaspace_case_sensitive_name_id(byo_schemaspaces, caplog):
  108. """Ensures that a schemaspace with case sensitive name and id has its instance properties unaltered."""
  109. SchemaManager.clear_instance()
  110. schema_mgr = SchemaManager.instance()
  111. byo_ss_name = "byo-schemaspace_CaseSensitiveName"
  112. byo_ss_id = "1b1e461a-c7fa-40f2-a3a3-bf1f2fd48EEA"
  113. schema_mgr_ss_names = schema_mgr.get_schemaspace_names()
  114. # Check schemaspace name is normalized in schema manager reference list
  115. assert byo_ss_name.lower() in schema_mgr_ss_names
  116. byo_ss_instance_name = schema_mgr.get_schemaspace_name(byo_ss_name)
  117. assert byo_ss_instance_name == byo_ss_name
  118. byo_ss_instance_name = schema_mgr.get_schemaspace_name(byo_ss_id)
  119. assert byo_ss_instance_name == byo_ss_name
  120. # Confirm this schemaspace produces an "empty schemaspace warning
  121. assert "The following schemaspaces have no schemas: ['byo-schemaspace_CaseSensitiveName']" in caplog.text
  122. def validate_log_output(caplog: pytest.LogCaptureFixture, expected_entry: str) -> Schemaspace:
  123. """Common negative test pattern that validates expected log output."""
  124. SchemaManager.clear_instance()
  125. schema_mgr = SchemaManager.instance()
  126. assert expected_entry in caplog.text
  127. byo_ss = schema_mgr.get_schemaspace(BYOSchemaspace.BYO_SCHEMASPACE_ID)
  128. # Ensure there are two valid schemas and make sure our bad one is not in the list.
  129. assert len(byo_ss.schemas) == 2
  130. for name, schema in byo_ss.schemas.items():
  131. assert schema["name"] in ["byo-test-0", "byo-test-1"]
  132. return byo_ss # in case caller wants to check other things.
  133. def test_schemaspace_bad_name(byo_schemaspaces, caplog):
  134. """Ensure a Schemaspace with a bad name (not alphanumeric, w/ dash, underscore) is handled cleanly."""
  135. validate_log_output(
  136. caplog, "The 'name' property (byo.schemaspace-bad.name) must " "be alphanumeric with dash or underscore only!"
  137. )
  138. def test_schemaspace_bad_class(byo_schemaspaces, caplog):
  139. """Ensure a Schemaspace that is registered but not a subclass of Schemaspace is handled cleanly."""
  140. validate_log_output(caplog, "'byo-schemaspace-bad-class' is not an instance of 'Schemaspace'")
  141. def test_schemaspace_throws(byo_schemaspaces, caplog):
  142. """Ensure a schemaspace that throws from its constructor doesn't affect the loads of other schemas."""
  143. validate_log_output(caplog, "Test that throw from constructor is not harmful.")
  144. def test_schemasprovider_bad_class(byo_schemaspaces, caplog):
  145. """Ensure a bad SchemasProvider class doesn't affect the loads of other schemas."""
  146. validate_log_output(
  147. caplog,
  148. "SchemasProvider instance 'byo-schemas-provider-bad-class' is not an "
  149. f"instance of '{SchemasProvider.__name__}'!",
  150. )
  151. def test_schemasprovider_throws(byo_schemaspaces, caplog):
  152. """Ensure exception thrown by SchemasProvider doesn't affect the loads of other schemas."""
  153. validate_log_output(caplog, "Error loading schemas for SchemasProvider 'byo-schemas-provider-throws'")
  154. def test_schemasprovider_no_schemaspace(byo_schemaspaces, caplog):
  155. """Ensure SchemasProvider that references a non-existent schemaspace doesn't affect the loads of other schemas."""
  156. byo_ss = validate_log_output(
  157. caplog,
  158. "Schema 'byo-test-unknown_schemaspace' references a schemaspace "
  159. f"'{NON_EXISTENT_SCHEMASPACE_ID}' that is not loaded!",
  160. )
  161. assert len(byo_ss.schemas) == 2
  162. for name, schema in byo_ss.schemas.items():
  163. assert schema["name"] != "byo-test-unknown_schemaspace"