julee 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. julee/__init__.py +3 -0
  2. julee/api/__init__.py +20 -0
  3. julee/api/app.py +180 -0
  4. julee/api/dependencies.py +257 -0
  5. julee/api/requests.py +175 -0
  6. julee/api/responses.py +43 -0
  7. julee/api/routers/__init__.py +43 -0
  8. julee/api/routers/assembly_specifications.py +212 -0
  9. julee/api/routers/documents.py +182 -0
  10. julee/api/routers/knowledge_service_configs.py +79 -0
  11. julee/api/routers/knowledge_service_queries.py +293 -0
  12. julee/api/routers/system.py +137 -0
  13. julee/api/routers/workflows.py +234 -0
  14. julee/api/services/__init__.py +20 -0
  15. julee/api/services/system_initialization.py +214 -0
  16. julee/api/tests/__init__.py +14 -0
  17. julee/api/tests/routers/__init__.py +17 -0
  18. julee/api/tests/routers/test_assembly_specifications.py +749 -0
  19. julee/api/tests/routers/test_documents.py +301 -0
  20. julee/api/tests/routers/test_knowledge_service_configs.py +234 -0
  21. julee/api/tests/routers/test_knowledge_service_queries.py +738 -0
  22. julee/api/tests/routers/test_system.py +179 -0
  23. julee/api/tests/routers/test_workflows.py +393 -0
  24. julee/api/tests/test_app.py +285 -0
  25. julee/api/tests/test_dependencies.py +245 -0
  26. julee/api/tests/test_requests.py +250 -0
  27. julee/domain/__init__.py +22 -0
  28. julee/domain/models/__init__.py +49 -0
  29. julee/domain/models/assembly/__init__.py +17 -0
  30. julee/domain/models/assembly/assembly.py +103 -0
  31. julee/domain/models/assembly/tests/__init__.py +0 -0
  32. julee/domain/models/assembly/tests/factories.py +37 -0
  33. julee/domain/models/assembly/tests/test_assembly.py +430 -0
  34. julee/domain/models/assembly_specification/__init__.py +24 -0
  35. julee/domain/models/assembly_specification/assembly_specification.py +172 -0
  36. julee/domain/models/assembly_specification/knowledge_service_query.py +123 -0
  37. julee/domain/models/assembly_specification/tests/__init__.py +0 -0
  38. julee/domain/models/assembly_specification/tests/factories.py +78 -0
  39. julee/domain/models/assembly_specification/tests/test_assembly_specification.py +490 -0
  40. julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +310 -0
  41. julee/domain/models/custom_fields/__init__.py +0 -0
  42. julee/domain/models/custom_fields/content_stream.py +68 -0
  43. julee/domain/models/custom_fields/tests/__init__.py +0 -0
  44. julee/domain/models/custom_fields/tests/test_custom_fields.py +53 -0
  45. julee/domain/models/document/__init__.py +17 -0
  46. julee/domain/models/document/document.py +150 -0
  47. julee/domain/models/document/tests/__init__.py +0 -0
  48. julee/domain/models/document/tests/factories.py +76 -0
  49. julee/domain/models/document/tests/test_document.py +297 -0
  50. julee/domain/models/knowledge_service_config/__init__.py +17 -0
  51. julee/domain/models/knowledge_service_config/knowledge_service_config.py +86 -0
  52. julee/domain/models/policy/__init__.py +15 -0
  53. julee/domain/models/policy/document_policy_validation.py +220 -0
  54. julee/domain/models/policy/policy.py +203 -0
  55. julee/domain/models/policy/tests/__init__.py +0 -0
  56. julee/domain/models/policy/tests/factories.py +47 -0
  57. julee/domain/models/policy/tests/test_document_policy_validation.py +420 -0
  58. julee/domain/models/policy/tests/test_policy.py +546 -0
  59. julee/domain/repositories/__init__.py +27 -0
  60. julee/domain/repositories/assembly.py +45 -0
  61. julee/domain/repositories/assembly_specification.py +52 -0
  62. julee/domain/repositories/base.py +146 -0
  63. julee/domain/repositories/document.py +49 -0
  64. julee/domain/repositories/document_policy_validation.py +52 -0
  65. julee/domain/repositories/knowledge_service_config.py +54 -0
  66. julee/domain/repositories/knowledge_service_query.py +44 -0
  67. julee/domain/repositories/policy.py +49 -0
  68. julee/domain/use_cases/__init__.py +17 -0
  69. julee/domain/use_cases/decorators.py +107 -0
  70. julee/domain/use_cases/extract_assemble_data.py +649 -0
  71. julee/domain/use_cases/initialize_system_data.py +842 -0
  72. julee/domain/use_cases/tests/__init__.py +7 -0
  73. julee/domain/use_cases/tests/test_extract_assemble_data.py +548 -0
  74. julee/domain/use_cases/tests/test_initialize_system_data.py +455 -0
  75. julee/domain/use_cases/tests/test_validate_document.py +1228 -0
  76. julee/domain/use_cases/validate_document.py +736 -0
  77. julee/fixtures/assembly_specifications.yaml +70 -0
  78. julee/fixtures/documents.yaml +178 -0
  79. julee/fixtures/knowledge_service_configs.yaml +37 -0
  80. julee/fixtures/knowledge_service_queries.yaml +27 -0
  81. julee/repositories/__init__.py +17 -0
  82. julee/repositories/memory/__init__.py +31 -0
  83. julee/repositories/memory/assembly.py +84 -0
  84. julee/repositories/memory/assembly_specification.py +125 -0
  85. julee/repositories/memory/base.py +227 -0
  86. julee/repositories/memory/document.py +149 -0
  87. julee/repositories/memory/document_policy_validation.py +104 -0
  88. julee/repositories/memory/knowledge_service_config.py +123 -0
  89. julee/repositories/memory/knowledge_service_query.py +120 -0
  90. julee/repositories/memory/policy.py +87 -0
  91. julee/repositories/memory/tests/__init__.py +0 -0
  92. julee/repositories/memory/tests/test_document.py +212 -0
  93. julee/repositories/memory/tests/test_document_policy_validation.py +161 -0
  94. julee/repositories/memory/tests/test_policy.py +443 -0
  95. julee/repositories/minio/__init__.py +31 -0
  96. julee/repositories/minio/assembly.py +103 -0
  97. julee/repositories/minio/assembly_specification.py +170 -0
  98. julee/repositories/minio/client.py +570 -0
  99. julee/repositories/minio/document.py +530 -0
  100. julee/repositories/minio/document_policy_validation.py +120 -0
  101. julee/repositories/minio/knowledge_service_config.py +187 -0
  102. julee/repositories/minio/knowledge_service_query.py +211 -0
  103. julee/repositories/minio/policy.py +106 -0
  104. julee/repositories/minio/tests/__init__.py +0 -0
  105. julee/repositories/minio/tests/fake_client.py +213 -0
  106. julee/repositories/minio/tests/test_assembly.py +374 -0
  107. julee/repositories/minio/tests/test_assembly_specification.py +391 -0
  108. julee/repositories/minio/tests/test_client_protocol.py +57 -0
  109. julee/repositories/minio/tests/test_document.py +591 -0
  110. julee/repositories/minio/tests/test_document_policy_validation.py +192 -0
  111. julee/repositories/minio/tests/test_knowledge_service_config.py +374 -0
  112. julee/repositories/minio/tests/test_knowledge_service_query.py +438 -0
  113. julee/repositories/minio/tests/test_policy.py +559 -0
  114. julee/repositories/temporal/__init__.py +38 -0
  115. julee/repositories/temporal/activities.py +114 -0
  116. julee/repositories/temporal/activity_names.py +34 -0
  117. julee/repositories/temporal/proxies.py +159 -0
  118. julee/services/__init__.py +18 -0
  119. julee/services/knowledge_service/__init__.py +48 -0
  120. julee/services/knowledge_service/anthropic/__init__.py +12 -0
  121. julee/services/knowledge_service/anthropic/knowledge_service.py +331 -0
  122. julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +318 -0
  123. julee/services/knowledge_service/factory.py +138 -0
  124. julee/services/knowledge_service/knowledge_service.py +160 -0
  125. julee/services/knowledge_service/memory/__init__.py +13 -0
  126. julee/services/knowledge_service/memory/knowledge_service.py +278 -0
  127. julee/services/knowledge_service/memory/test_knowledge_service.py +345 -0
  128. julee/services/knowledge_service/test_factory.py +112 -0
  129. julee/services/temporal/__init__.py +38 -0
  130. julee/services/temporal/activities.py +86 -0
  131. julee/services/temporal/activity_names.py +22 -0
  132. julee/services/temporal/proxies.py +41 -0
  133. julee/util/__init__.py +0 -0
  134. julee/util/domain.py +119 -0
  135. julee/util/repos/__init__.py +0 -0
  136. julee/util/repos/minio/__init__.py +0 -0
  137. julee/util/repos/minio/file_storage.py +213 -0
  138. julee/util/repos/temporal/__init__.py +11 -0
  139. julee/util/repos/temporal/client_proxies/file_storage.py +68 -0
  140. julee/util/repos/temporal/data_converter.py +123 -0
  141. julee/util/repos/temporal/minio_file_storage.py +12 -0
  142. julee/util/repos/temporal/proxies/__init__.py +0 -0
  143. julee/util/repos/temporal/proxies/file_storage.py +58 -0
  144. julee/util/repositories.py +55 -0
  145. julee/util/temporal/__init__.py +22 -0
  146. julee/util/temporal/activities.py +123 -0
  147. julee/util/temporal/decorators.py +473 -0
  148. julee/util/tests/__init__.py +1 -0
  149. julee/util/tests/test_decorators.py +770 -0
  150. julee/util/validation/__init__.py +29 -0
  151. julee/util/validation/repository.py +100 -0
  152. julee/util/validation/type_guards.py +369 -0
  153. julee/worker.py +211 -0
  154. julee/workflows/__init__.py +26 -0
  155. julee/workflows/extract_assemble.py +215 -0
  156. julee/workflows/validate_document.py +228 -0
  157. julee-0.1.0.dist-info/METADATA +195 -0
  158. julee-0.1.0.dist-info/RECORD +161 -0
  159. julee-0.1.0.dist-info/WHEEL +5 -0
  160. julee-0.1.0.dist-info/licenses/LICENSE +674 -0
  161. julee-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,455 @@
1
+ """
2
+ Tests for InitializeSystemDataUseCase.
3
+
4
+ This module tests the use case for initializing required system data,
5
+ ensuring it properly loads configurations from the YAML fixture file
6
+ and creates knowledge service configurations correctly.
7
+
8
+ These tests use the actual YAML fixture file to validate the real
9
+ integration rather than mocking the file system operations.
10
+ """
11
+
12
+ from datetime import datetime, timezone
13
+ from pathlib import Path
14
+
15
+ import pytest
16
+ import yaml
17
+
18
+ from julee.domain.models.knowledge_service_config import (
19
+ KnowledgeServiceConfig,
20
+ ServiceApi,
21
+ )
22
+ from julee.domain.use_cases.initialize_system_data import (
23
+ InitializeSystemDataUseCase,
24
+ )
25
+ from julee.repositories.memory.assembly_specification import (
26
+ MemoryAssemblySpecificationRepository,
27
+ )
28
+ from julee.repositories.memory.document import (
29
+ MemoryDocumentRepository,
30
+ )
31
+ from julee.repositories.memory.knowledge_service_config import (
32
+ MemoryKnowledgeServiceConfigRepository,
33
+ )
34
+ from julee.repositories.memory.knowledge_service_query import (
35
+ MemoryKnowledgeServiceQueryRepository,
36
+ )
37
+
38
+
39
+ @pytest.fixture
40
+ def memory_config_repository() -> MemoryKnowledgeServiceConfigRepository:
41
+ """Create memory knowledge service config repository."""
42
+ return MemoryKnowledgeServiceConfigRepository()
43
+
44
+
45
+ @pytest.fixture
46
+ def memory_document_repository() -> MemoryDocumentRepository:
47
+ """Create memory document repository."""
48
+ return MemoryDocumentRepository()
49
+
50
+
51
+ @pytest.fixture
52
+ def memory_query_repository() -> MemoryKnowledgeServiceQueryRepository:
53
+ """Create memory knowledge service query repository."""
54
+ return MemoryKnowledgeServiceQueryRepository()
55
+
56
+
57
+ @pytest.fixture
58
+ def memory_assembly_spec_repository() -> MemoryAssemblySpecificationRepository:
59
+ """Create memory assembly specification repository."""
60
+ return MemoryAssemblySpecificationRepository()
61
+
62
+
63
+ @pytest.fixture
64
+ def use_case(
65
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
66
+ memory_document_repository: MemoryDocumentRepository,
67
+ memory_query_repository: MemoryKnowledgeServiceQueryRepository,
68
+ memory_assembly_spec_repository: MemoryAssemblySpecificationRepository,
69
+ ) -> InitializeSystemDataUseCase:
70
+ """Create use case with memory repositories."""
71
+ return InitializeSystemDataUseCase(
72
+ memory_config_repository,
73
+ memory_document_repository,
74
+ memory_query_repository,
75
+ memory_assembly_spec_repository,
76
+ )
77
+
78
+
79
+ @pytest.fixture
80
+ def fixture_configs() -> list[dict]:
81
+ """Load actual configurations from YAML fixture file."""
82
+ # Get the fixture file path
83
+ current_file = Path(__file__)
84
+ julee_dir = current_file.parent.parent.parent.parent
85
+ fixture_path = julee_dir / "fixtures" / "knowledge_service_configs.yaml"
86
+
87
+ assert fixture_path.exists(), f"Fixture file not found: {fixture_path}"
88
+
89
+ with open(fixture_path, "r", encoding="utf-8") as f:
90
+ fixture_data = yaml.safe_load(f)
91
+
92
+ assert "knowledge_services" in fixture_data
93
+ assert isinstance(fixture_data["knowledge_services"], list)
94
+ assert len(fixture_data["knowledge_services"]) > 0
95
+
96
+ return fixture_data["knowledge_services"]
97
+
98
+
99
+ @pytest.fixture
100
+ def sample_anthropic_config() -> KnowledgeServiceConfig:
101
+ """Create sample Anthropic configuration."""
102
+ return KnowledgeServiceConfig(
103
+ knowledge_service_id="anthropic-claude",
104
+ name="Anthropic Claude",
105
+ description="Claude 3 for general text analysis and extraction",
106
+ service_api=ServiceApi.ANTHROPIC,
107
+ created_at=datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
108
+ updated_at=datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
109
+ )
110
+
111
+
112
+ class TestInitializeSystemDataUseCase:
113
+ """Test the InitializeSystemDataUseCase."""
114
+
115
+ @pytest.mark.asyncio
116
+ async def test_execute_success_creates_configs_from_fixture(
117
+ self,
118
+ use_case: InitializeSystemDataUseCase,
119
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
120
+ fixture_configs: list[dict],
121
+ ) -> None:
122
+ """Test successful execution creates configs from fixture."""
123
+ # Execute use case
124
+ await use_case.execute()
125
+
126
+ # Verify all configs were created
127
+ saved_configs = await memory_config_repository.list_all()
128
+ assert len(saved_configs) == len(fixture_configs)
129
+
130
+ # Verify configs were created with correct IDs from fixture
131
+
132
+ saved_ids = {config.knowledge_service_id for config in saved_configs}
133
+ expected_ids = {config["knowledge_service_id"] for config in fixture_configs}
134
+ assert saved_ids == expected_ids
135
+
136
+ # Verify first config matches fixture data
137
+ first_fixture = fixture_configs[0]
138
+ first_saved = next(
139
+ config
140
+ for config in saved_configs
141
+ if config.knowledge_service_id == first_fixture["knowledge_service_id"]
142
+ )
143
+
144
+ assert first_saved.name == first_fixture["name"]
145
+ assert first_saved.description == first_fixture["description"]
146
+ assert first_saved.service_api.value == first_fixture["service_api"]
147
+
148
+ @pytest.mark.asyncio
149
+ async def test_execute_success_configs_already_exist(
150
+ self,
151
+ use_case: InitializeSystemDataUseCase,
152
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
153
+ sample_anthropic_config: KnowledgeServiceConfig,
154
+ ) -> None:
155
+ """Test successful execution when configs already exist."""
156
+ # Setup - add existing config to repository
157
+ await memory_config_repository.save(sample_anthropic_config)
158
+
159
+ # Execute use case
160
+ await use_case.execute()
161
+
162
+ # Verify only the existing config is in the repository (no duplicates)
163
+ all_configs = await memory_config_repository.list_all()
164
+ config_ids = [c.knowledge_service_id for c in all_configs]
165
+ assert sample_anthropic_config.knowledge_service_id in config_ids
166
+
167
+ @pytest.mark.asyncio
168
+ async def test_execute_mixed_existing_and_new_configs(
169
+ self,
170
+ use_case: InitializeSystemDataUseCase,
171
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
172
+ sample_anthropic_config: KnowledgeServiceConfig,
173
+ fixture_configs: list[dict],
174
+ ) -> None:
175
+ """Test execution with mix of existing and new configs."""
176
+ # Setup - add one existing config to repository
177
+ await memory_config_repository.save(sample_anthropic_config)
178
+
179
+ # Execute use case
180
+ await use_case.execute()
181
+
182
+ # Verify all configs from fixture exist (including pre-existing one)
183
+ final_configs = await memory_config_repository.list_all()
184
+ final_count = len(final_configs)
185
+
186
+ # Should have all fixture configs (some were new, one already existed)
187
+ expected_total = len(fixture_configs)
188
+ assert final_count >= expected_total
189
+
190
+ # Verify the existing config is still there
191
+ config_ids = [c.knowledge_service_id for c in final_configs]
192
+ assert sample_anthropic_config.knowledge_service_id in config_ids
193
+
194
+ # NOTE: Error handling tests commented out as they don't work well with
195
+ # memory repositories. These would need mock repositories or integration
196
+ # tests with actual Minio failures to test error scenarios properly.
197
+
198
+ # @pytest.mark.asyncio
199
+ # async def test_execute_handles_repository_get_error(...)
200
+ # @pytest.mark.asyncio
201
+ # async def test_execute_handles_repository_save_error(...)
202
+
203
+ @pytest.mark.asyncio
204
+ async def test_config_creation_uses_correct_values_from_fixture(
205
+ self,
206
+ use_case: InitializeSystemDataUseCase,
207
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
208
+ fixture_configs: list[dict],
209
+ ) -> None:
210
+ """Test that created configs have correct values from fixture."""
211
+ # Execute use case
212
+ await use_case.execute()
213
+
214
+ # Get all saved configs
215
+ saved_configs = await memory_config_repository.list_all()
216
+
217
+ # Verify each saved config matches fixture data
218
+ for fixture_config in fixture_configs:
219
+ saved_config = next(
220
+ config
221
+ for config in saved_configs
222
+ if config.knowledge_service_id == fixture_config["knowledge_service_id"]
223
+ )
224
+
225
+ # Verify all fixture values are correctly applied
226
+ assert (
227
+ saved_config.knowledge_service_id
228
+ == fixture_config["knowledge_service_id"]
229
+ )
230
+ assert saved_config.name == fixture_config["name"]
231
+ assert saved_config.description == fixture_config["description"]
232
+ assert saved_config.service_api.value == fixture_config["service_api"]
233
+ assert saved_config.created_at is not None
234
+ assert saved_config.updated_at is not None
235
+ assert isinstance(saved_config.created_at, datetime)
236
+ assert isinstance(saved_config.updated_at, datetime)
237
+
238
+ @pytest.mark.asyncio
239
+ async def test_use_case_is_idempotent(
240
+ self,
241
+ use_case: InitializeSystemDataUseCase,
242
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
243
+ fixture_configs: list[dict],
244
+ ) -> None:
245
+ """Test that running the use case multiple times is safe."""
246
+ # First run - configs don't exist, get created
247
+ await use_case.execute()
248
+ first_run_configs = await memory_config_repository.list_all()
249
+ first_run_count = len(first_run_configs)
250
+
251
+ # Second run - configs now exist, should not create duplicates
252
+ await use_case.execute()
253
+ second_run_configs = await memory_config_repository.list_all()
254
+ second_run_count = len(second_run_configs)
255
+
256
+ # Verify idempotency - same number of configs after second run
257
+ assert first_run_count == second_run_count
258
+
259
+ # Verify all fixture configs are present
260
+ config_ids = [c.knowledge_service_id for c in second_run_configs]
261
+ for fixture_config in fixture_configs:
262
+ assert fixture_config["knowledge_service_id"] in config_ids
263
+
264
+ def test_use_case_initialization(
265
+ self,
266
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
267
+ memory_document_repository: MemoryDocumentRepository,
268
+ memory_query_repository: MemoryKnowledgeServiceQueryRepository,
269
+ memory_assembly_spec_repository: MemoryAssemblySpecificationRepository,
270
+ ) -> None:
271
+ """Test use case initialization with repositories."""
272
+ use_case = InitializeSystemDataUseCase(
273
+ memory_config_repository,
274
+ memory_document_repository,
275
+ memory_query_repository,
276
+ memory_assembly_spec_repository,
277
+ )
278
+ assert use_case.config_repo is memory_config_repository
279
+ assert use_case.document_repo is memory_document_repository
280
+ assert use_case.query_repo is memory_query_repository
281
+ assert use_case.assembly_spec_repo is memory_assembly_spec_repository
282
+ assert use_case.logger is not None
283
+
284
+ @pytest.mark.asyncio
285
+ async def test_config_initialization_only(
286
+ self,
287
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
288
+ memory_document_repository: MemoryDocumentRepository,
289
+ memory_query_repository: MemoryKnowledgeServiceQueryRepository,
290
+ memory_assembly_spec_repository: MemoryAssemblySpecificationRepository,
291
+ fixture_configs: list[dict],
292
+ ) -> None:
293
+ """Test only the config initialization part."""
294
+ use_case = InitializeSystemDataUseCase(
295
+ memory_config_repository,
296
+ memory_document_repository,
297
+ memory_query_repository,
298
+ memory_assembly_spec_repository,
299
+ )
300
+
301
+ # Execute the use case to initialize configs
302
+ await use_case.execute()
303
+
304
+ # Verify configs were created
305
+ saved_configs = await memory_config_repository.list_all()
306
+ assert len(saved_configs) == len(fixture_configs)
307
+
308
+
309
+ class TestYamlFixtureIntegration:
310
+ """Test integration with actual YAML fixture file."""
311
+
312
+ def test_fixture_file_exists_and_is_valid(self) -> None:
313
+ """Test that the fixture file exists and contains valid data."""
314
+ # Get the fixture file path
315
+ current_file = Path(__file__)
316
+ julee_dir = current_file.parent.parent.parent.parent
317
+ fixture_path = julee_dir / "fixtures" / "knowledge_service_configs.yaml"
318
+
319
+ # Verify file exists
320
+ assert fixture_path.exists(), f"Fixture file not found: {fixture_path}"
321
+
322
+ # Verify file can be parsed
323
+ with open(fixture_path, "r", encoding="utf-8") as f:
324
+ fixture_data = yaml.safe_load(f)
325
+
326
+ # Verify structure
327
+ assert isinstance(fixture_data, dict)
328
+ assert "knowledge_services" in fixture_data
329
+ assert isinstance(fixture_data["knowledge_services"], list)
330
+ assert len(fixture_data["knowledge_services"]) > 0
331
+
332
+ def test_fixture_configs_have_required_fields(
333
+ self, fixture_configs: list[dict]
334
+ ) -> None:
335
+ """Test that all fixture configs have required fields."""
336
+ required_fields = [
337
+ "knowledge_service_id",
338
+ "name",
339
+ "description",
340
+ "service_api",
341
+ ]
342
+
343
+ for config in fixture_configs:
344
+ for field in required_fields:
345
+ assert field in config, (
346
+ f"Missing required field '{field}' in config "
347
+ f"{config.get('knowledge_service_id', 'unknown')}"
348
+ )
349
+
350
+ # Verify service_api is valid
351
+ assert config["service_api"] in [api.value for api in ServiceApi], (
352
+ f"Invalid service_api '{config['service_api']}' in config "
353
+ f"{config['knowledge_service_id']}"
354
+ )
355
+
356
+ # Verify IDs are not empty
357
+ assert config["knowledge_service_id"].strip(), "Empty knowledge_service_id"
358
+ assert config["name"].strip(), "Empty name"
359
+ assert config["description"].strip(), "Empty description"
360
+
361
+ def test_fixture_configs_have_unique_ids(self, fixture_configs: list[dict]) -> None:
362
+ """Test that all fixture configs have unique IDs."""
363
+ config_ids = [config["knowledge_service_id"] for config in fixture_configs]
364
+ assert len(config_ids) == len(
365
+ set(config_ids)
366
+ ), "Duplicate knowledge_service_id found in fixture"
367
+
368
+ @pytest.mark.asyncio
369
+ async def test_load_fixture_configurations_method(
370
+ self, use_case: InitializeSystemDataUseCase
371
+ ) -> None:
372
+ """Test the _load_fixture_configurations method directly."""
373
+ configs = use_case._load_fixture_configurations()
374
+
375
+ assert isinstance(configs, list)
376
+ assert len(configs) > 0
377
+
378
+ # Verify each config has required structure
379
+ for config in configs:
380
+ assert isinstance(config, dict)
381
+ assert "knowledge_service_id" in config
382
+ assert "name" in config
383
+ assert "description" in config
384
+ assert "service_api" in config
385
+
386
+ @pytest.mark.asyncio
387
+ async def test_create_config_from_fixture_data_method(
388
+ self,
389
+ use_case: InitializeSystemDataUseCase,
390
+ fixture_configs: list[dict],
391
+ ) -> None:
392
+ """Test the _create_config_from_fixture_data method directly."""
393
+ fixture_config = fixture_configs[0]
394
+
395
+ created_config = use_case._create_config_from_fixture_data(fixture_config)
396
+
397
+ assert isinstance(created_config, KnowledgeServiceConfig)
398
+ assert (
399
+ created_config.knowledge_service_id
400
+ == fixture_config["knowledge_service_id"]
401
+ )
402
+ assert created_config.name == fixture_config["name"]
403
+ assert created_config.description == fixture_config["description"]
404
+ assert created_config.service_api.value == fixture_config["service_api"]
405
+ assert created_config.created_at is not None
406
+ assert created_config.updated_at is not None
407
+
408
+
409
+ class TestInitializeSystemDataUseCaseIntegration:
410
+ """Integration-style tests for the use case."""
411
+
412
+ @pytest.mark.asyncio
413
+ async def test_full_workflow_new_system(
414
+ self,
415
+ use_case: InitializeSystemDataUseCase,
416
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
417
+ fixture_configs: list[dict],
418
+ ) -> None:
419
+ """Test complete workflow for a new system with no existing data."""
420
+ # Setup - repository starts empty
421
+
422
+ # Execute initialization
423
+ await use_case.execute()
424
+
425
+ # Verify all configs were created
426
+ saved_configs = await memory_config_repository.list_all()
427
+ assert len(saved_configs) == len(fixture_configs)
428
+
429
+ # Verify configs were created with correct IDs from fixture
430
+ saved_ids = {config.knowledge_service_id for config in saved_configs}
431
+ expected_ids = {config["knowledge_service_id"] for config in fixture_configs}
432
+ assert saved_ids == expected_ids
433
+
434
+ @pytest.mark.asyncio
435
+ async def test_full_workflow_existing_system(
436
+ self,
437
+ use_case: InitializeSystemDataUseCase,
438
+ memory_config_repository: MemoryKnowledgeServiceConfigRepository,
439
+ sample_anthropic_config: KnowledgeServiceConfig,
440
+ fixture_configs: list[dict],
441
+ ) -> None:
442
+ """Test complete workflow for existing system with data present."""
443
+ # Setup - add existing config to repository
444
+ await memory_config_repository.save(sample_anthropic_config)
445
+
446
+ # Execute initialization
447
+ await use_case.execute()
448
+
449
+ # Verify configs exist and no duplicates were created
450
+ final_configs = await memory_config_repository.list_all()
451
+
452
+ # Should have all fixture configs (including pre-existing)
453
+ config_ids = [c.knowledge_service_id for c in final_configs]
454
+ assert sample_anthropic_config.knowledge_service_id in config_ids
455
+ assert len(final_configs) >= len(fixture_configs)