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,391 @@
1
+ """
2
+ Tests for MinioAssemblySpecificationRepository implementation.
3
+
4
+ This module provides comprehensive tests for the Minio-based assembly
5
+ specification repository implementation, using the fake client to avoid
6
+ external dependencies during testing.
7
+ """
8
+
9
+ import pytest
10
+ from datetime import datetime, timezone
11
+
12
+
13
+ from julee.domain.models.assembly_specification import (
14
+ AssemblySpecification,
15
+ AssemblySpecificationStatus,
16
+ )
17
+ from julee.repositories.minio.assembly_specification import (
18
+ MinioAssemblySpecificationRepository,
19
+ )
20
+ from .fake_client import FakeMinioClient
21
+
22
+
23
+ @pytest.fixture
24
+ def fake_client() -> FakeMinioClient:
25
+ """Create a fresh fake Minio client for each test."""
26
+ return FakeMinioClient()
27
+
28
+
29
+ @pytest.fixture
30
+ def specification_repo(
31
+ fake_client: FakeMinioClient,
32
+ ) -> MinioAssemblySpecificationRepository:
33
+ """Create assembly specification repository with fake client."""
34
+ return MinioAssemblySpecificationRepository(fake_client)
35
+
36
+
37
+ @pytest.fixture
38
+ def sample_specification() -> AssemblySpecification:
39
+ """Create a sample assembly specification for testing."""
40
+ return AssemblySpecification(
41
+ assembly_specification_id="spec-123",
42
+ name="Meeting Minutes",
43
+ applicability="Corporate meeting recordings and transcripts",
44
+ jsonschema={
45
+ "type": "object",
46
+ "properties": {
47
+ "title": {"type": "string"},
48
+ "attendees": {"type": "array", "items": {"type": "string"}},
49
+ "action_items": {
50
+ "type": "array",
51
+ "items": {
52
+ "type": "object",
53
+ "properties": {
54
+ "description": {"type": "string"},
55
+ "assignee": {"type": "string"},
56
+ "due_date": {"type": "string"},
57
+ },
58
+ },
59
+ },
60
+ },
61
+ "required": ["title"],
62
+ },
63
+ status=AssemblySpecificationStatus.ACTIVE,
64
+ knowledge_service_queries={
65
+ "/properties/title": "extract-meeting-title",
66
+ "/properties/attendees": "extract-attendees",
67
+ "/properties/action_items": "extract-action-items",
68
+ },
69
+ version="1.0.0",
70
+ created_at=datetime.now(timezone.utc),
71
+ updated_at=datetime.now(timezone.utc),
72
+ )
73
+
74
+
75
+ @pytest.fixture
76
+ def inactive_specification() -> AssemblySpecification:
77
+ """Create an inactive assembly specification for testing."""
78
+ return AssemblySpecification(
79
+ assembly_specification_id="spec-inactive-456",
80
+ name="Inactive Spec",
81
+ applicability="This is an inactive specification",
82
+ jsonschema={
83
+ "type": "object",
84
+ "properties": {"test": {"type": "string"}},
85
+ },
86
+ status=AssemblySpecificationStatus.INACTIVE,
87
+ version="1.0.0",
88
+ created_at=datetime.now(timezone.utc),
89
+ updated_at=datetime.now(timezone.utc),
90
+ )
91
+
92
+
93
+ class TestMinioAssemblySpecificationRepositoryBasicOperations:
94
+ """Test basic CRUD operations on assembly specifications."""
95
+
96
+ @pytest.mark.asyncio
97
+ async def test_save_and_get_specification(
98
+ self,
99
+ specification_repo: MinioAssemblySpecificationRepository,
100
+ sample_specification: AssemblySpecification,
101
+ ) -> None:
102
+ """Test saving and retrieving an assembly specification."""
103
+ # Save specification
104
+ await specification_repo.save(sample_specification)
105
+
106
+ # Retrieve specification
107
+ retrieved = await specification_repo.get(
108
+ sample_specification.assembly_specification_id
109
+ )
110
+
111
+ assert retrieved is not None
112
+ assert (
113
+ retrieved.assembly_specification_id
114
+ == sample_specification.assembly_specification_id
115
+ )
116
+ assert retrieved.name == sample_specification.name
117
+ assert retrieved.applicability == sample_specification.applicability
118
+ assert retrieved.jsonschema == sample_specification.jsonschema
119
+ assert retrieved.status == sample_specification.status
120
+ assert (
121
+ retrieved.knowledge_service_queries
122
+ == sample_specification.knowledge_service_queries
123
+ )
124
+ assert retrieved.version == sample_specification.version
125
+
126
+ @pytest.mark.asyncio
127
+ async def test_get_nonexistent_specification(
128
+ self, specification_repo: MinioAssemblySpecificationRepository
129
+ ) -> None:
130
+ """Test retrieving a non-existent specification returns None."""
131
+ result = await specification_repo.get("nonexistent-spec")
132
+ assert result is None
133
+
134
+ @pytest.mark.asyncio
135
+ async def test_generate_id(
136
+ self, specification_repo: MinioAssemblySpecificationRepository
137
+ ) -> None:
138
+ """Test generating unique specification IDs."""
139
+ id1 = await specification_repo.generate_id()
140
+ id2 = await specification_repo.generate_id()
141
+
142
+ assert isinstance(id1, str)
143
+ assert isinstance(id2, str)
144
+ assert id1 != id2
145
+ assert len(id1) > 0
146
+ assert len(id2) > 0
147
+
148
+ @pytest.mark.asyncio
149
+ async def test_save_updates_timestamp(
150
+ self,
151
+ specification_repo: MinioAssemblySpecificationRepository,
152
+ sample_specification: AssemblySpecification,
153
+ ) -> None:
154
+ """Test that save operations update the updated_at timestamp."""
155
+ original_updated_at = sample_specification.updated_at
156
+
157
+ # Save specification
158
+ await specification_repo.save(sample_specification)
159
+
160
+ # Retrieve and check timestamp was updated
161
+ retrieved = await specification_repo.get(
162
+ sample_specification.assembly_specification_id
163
+ )
164
+ assert retrieved is not None
165
+ assert retrieved.updated_at is not None
166
+ assert original_updated_at is not None
167
+ assert retrieved.updated_at > original_updated_at
168
+
169
+
170
+ class TestMinioAssemblySpecificationRepositoryStatusManagement:
171
+ """Test specification status management."""
172
+
173
+ @pytest.mark.asyncio
174
+ async def test_update_specification_status(
175
+ self,
176
+ specification_repo: MinioAssemblySpecificationRepository,
177
+ sample_specification: AssemblySpecification,
178
+ ) -> None:
179
+ """Test updating specification status."""
180
+ # Save initial specification
181
+ await specification_repo.save(sample_specification)
182
+
183
+ # Update status to draft
184
+ sample_specification.status = AssemblySpecificationStatus.DRAFT
185
+ await specification_repo.save(sample_specification)
186
+
187
+ # Verify update
188
+ retrieved = await specification_repo.get(
189
+ sample_specification.assembly_specification_id
190
+ )
191
+ assert retrieved is not None
192
+ assert retrieved.status == AssemblySpecificationStatus.DRAFT
193
+
194
+ # Update to deprecated
195
+ sample_specification.status = AssemblySpecificationStatus.DEPRECATED
196
+ await specification_repo.save(sample_specification)
197
+
198
+ # Verify final state
199
+ retrieved = await specification_repo.get(
200
+ sample_specification.assembly_specification_id
201
+ )
202
+ assert retrieved is not None
203
+ assert retrieved.status == AssemblySpecificationStatus.DEPRECATED
204
+
205
+
206
+ class TestMinioAssemblySpecificationRepositoryComplexScenarios:
207
+ """Test complex scenarios and edge cases."""
208
+
209
+ @pytest.mark.asyncio
210
+ async def test_complete_specification_lifecycle(
211
+ self, specification_repo: MinioAssemblySpecificationRepository
212
+ ) -> None:
213
+ """Test complete specification lifecycle from creation to
214
+ deprecation."""
215
+ # Generate new specification
216
+ spec_id = await specification_repo.generate_id()
217
+
218
+ # Create and save new specification
219
+ specification = AssemblySpecification(
220
+ assembly_specification_id=spec_id,
221
+ name="Test Lifecycle Spec",
222
+ applicability="Test specification for lifecycle testing",
223
+ jsonschema={
224
+ "type": "object",
225
+ "properties": {"test_field": {"type": "string"}},
226
+ "required": ["test_field"],
227
+ },
228
+ status=AssemblySpecificationStatus.DRAFT,
229
+ knowledge_service_queries={"/properties/test_field": "test-query"},
230
+ version="0.1.0",
231
+ created_at=datetime.now(timezone.utc),
232
+ updated_at=datetime.now(timezone.utc),
233
+ )
234
+ await specification_repo.save(specification)
235
+
236
+ # Activate specification
237
+ specification.status = AssemblySpecificationStatus.ACTIVE
238
+ specification.version = "1.0.0"
239
+ await specification_repo.save(specification)
240
+
241
+ # Deprecate specification
242
+ specification.status = AssemblySpecificationStatus.DEPRECATED
243
+ await specification_repo.save(specification)
244
+
245
+ # Verify can still be retrieved directly
246
+ retrieved = await specification_repo.get(spec_id)
247
+ assert retrieved is not None
248
+ assert retrieved.status == AssemblySpecificationStatus.DEPRECATED
249
+
250
+ @pytest.mark.asyncio
251
+ async def test_complex_json_schema_handling(
252
+ self, specification_repo: MinioAssemblySpecificationRepository
253
+ ) -> None:
254
+ """Test handling of complex JSON schemas."""
255
+ complex_schema = {
256
+ "type": "object",
257
+ "properties": {
258
+ "metadata": {
259
+ "type": "object",
260
+ "properties": {
261
+ "title": {"type": "string"},
262
+ "date": {"type": "string", "format": "date"},
263
+ "participants": {
264
+ "type": "array",
265
+ "items": {
266
+ "type": "object",
267
+ "properties": {
268
+ "name": {"type": "string"},
269
+ "role": {"type": "string"},
270
+ "email": {
271
+ "type": "string",
272
+ "format": "email",
273
+ },
274
+ },
275
+ "required": ["name"],
276
+ },
277
+ },
278
+ },
279
+ "required": ["title", "date"],
280
+ },
281
+ "content": {
282
+ "type": "object",
283
+ "properties": {
284
+ "summary": {"type": "string"},
285
+ "action_items": {
286
+ "type": "array",
287
+ "items": {
288
+ "type": "object",
289
+ "properties": {
290
+ "task": {"type": "string"},
291
+ "assignee": {"type": "string"},
292
+ "due_date": {
293
+ "type": "string",
294
+ "format": "date",
295
+ },
296
+ "priority": {
297
+ "type": "string",
298
+ "enum": ["low", "medium", "high"],
299
+ },
300
+ },
301
+ "required": ["task", "assignee"],
302
+ },
303
+ },
304
+ "decisions": {
305
+ "type": "array",
306
+ "items": {"type": "string"},
307
+ },
308
+ },
309
+ },
310
+ "attachments": {
311
+ "type": "array",
312
+ "items": {
313
+ "type": "object",
314
+ "properties": {
315
+ "filename": {"type": "string"},
316
+ "url": {"type": "string", "format": "uri"},
317
+ },
318
+ },
319
+ },
320
+ },
321
+ "required": ["metadata", "content"],
322
+ }
323
+
324
+ complex_queries = {
325
+ "/properties/metadata/properties/title": "extract-title",
326
+ "/properties/metadata/properties/participants": ("extract-participants"),
327
+ "/properties/content/properties/action_items": ("extract-action-items"),
328
+ "/properties/content/properties/summary": "extract-summary",
329
+ }
330
+
331
+ specification = AssemblySpecification(
332
+ assembly_specification_id="complex-spec",
333
+ name="Complex Meeting Assembly",
334
+ applicability="Detailed meeting documentation with full metadata",
335
+ jsonschema=complex_schema,
336
+ status=AssemblySpecificationStatus.ACTIVE,
337
+ knowledge_service_queries=complex_queries,
338
+ version="2.0.0",
339
+ created_at=datetime.now(timezone.utc),
340
+ updated_at=datetime.now(timezone.utc),
341
+ )
342
+
343
+ # Save and retrieve
344
+ await specification_repo.save(specification)
345
+ retrieved = await specification_repo.get("complex-spec")
346
+
347
+ assert retrieved is not None
348
+ assert retrieved.jsonschema == complex_schema
349
+ assert retrieved.knowledge_service_queries == complex_queries
350
+ assert len(retrieved.knowledge_service_queries) == 4
351
+
352
+ @pytest.mark.asyncio
353
+ async def test_specification_roundtrip_with_unicode(
354
+ self, specification_repo: MinioAssemblySpecificationRepository
355
+ ) -> None:
356
+ """Test specification with unicode content survives roundtrip."""
357
+ unicode_specification = AssemblySpecification(
358
+ assembly_specification_id="unicode-spec",
359
+ name="Spécification avec caractères spéciaux",
360
+ applicability="Документы с unicode содержанием и émojis 🚀📝",
361
+ jsonschema={
362
+ "type": "object",
363
+ "properties": {
364
+ "título": {"type": "string"},
365
+ "descripción": {"type": "string"},
366
+ "метаданные": {
367
+ "type": "object",
368
+ "properties": {"автор": {"type": "string"}},
369
+ },
370
+ },
371
+ },
372
+ status=AssemblySpecificationStatus.ACTIVE,
373
+ knowledge_service_queries={
374
+ "/properties/título": "query-título",
375
+ "/properties/метаданные": "query-metadata",
376
+ },
377
+ version="1.0.0",
378
+ created_at=datetime.now(timezone.utc),
379
+ updated_at=datetime.now(timezone.utc),
380
+ )
381
+
382
+ # Save and retrieve
383
+ await specification_repo.save(unicode_specification)
384
+ retrieved = await specification_repo.get("unicode-spec")
385
+
386
+ assert retrieved is not None
387
+ assert retrieved.name == "Spécification avec caractères spéciaux"
388
+ assert "unicode содержанием и émojis 🚀📝" in retrieved.applicability
389
+ assert "título" in retrieved.jsonschema["properties"]
390
+ assert "метаданные" in retrieved.jsonschema["properties"]
391
+ assert "/properties/título" in retrieved.knowledge_service_queries
@@ -0,0 +1,57 @@
1
+ """
2
+ Tests to verify protocol compatibility between real Minio client and protocol.
3
+
4
+ This module tests that the real minio.Minio client properly implements our
5
+ MinioClient protocol, ensuring that our protocol definition matches the
6
+ actual interface.
7
+ """
8
+
9
+ from minio import Minio
10
+
11
+ from ..client import MinioClient
12
+
13
+
14
+ class TestMinioClientProtocol:
15
+ """Test that the real Minio client implements our protocol."""
16
+
17
+ def test_real_minio_client_implements_protocol(self) -> None:
18
+ """Test that minio.Minio implements MinioClient protocol."""
19
+ # Create a real Minio client (doesn't need to connect)
20
+ real_client = Minio("localhost:9000")
21
+
22
+ # This should pass if the protocol is correctly defined
23
+ assert isinstance(real_client, MinioClient)
24
+
25
+ def test_protocol_method_signatures_match_real_client(self) -> None:
26
+ """Test that protocol method signatures match the real client."""
27
+ real_client = Minio("localhost:9000")
28
+
29
+ # Test that all protocol methods exist on the real client
30
+ assert hasattr(real_client, "bucket_exists")
31
+ assert hasattr(real_client, "make_bucket")
32
+ assert hasattr(real_client, "put_object")
33
+ assert hasattr(real_client, "get_object")
34
+ assert hasattr(real_client, "stat_object")
35
+
36
+ # Test that methods are callable
37
+ assert callable(getattr(real_client, "bucket_exists"))
38
+ assert callable(getattr(real_client, "make_bucket"))
39
+ assert callable(getattr(real_client, "put_object"))
40
+ assert callable(getattr(real_client, "get_object"))
41
+ assert callable(getattr(real_client, "stat_object"))
42
+
43
+ def test_protocol_accepts_real_minio_client(self) -> None:
44
+ """Test that our protocol accepts a real Minio client instance."""
45
+ from ..document import MinioDocumentRepository
46
+
47
+ # Create a real Minio client (no connection attempted in constructor)
48
+ real_client = Minio("localhost:9000")
49
+
50
+ # This should work without type errors if protocol is correct
51
+ # We don't call any methods that would trigger network calls
52
+ repository = MinioDocumentRepository.__new__(MinioDocumentRepository)
53
+ repository.client = real_client
54
+
55
+ # Verify the client was stored correctly
56
+ assert repository.client is real_client
57
+ assert isinstance(repository.client, MinioClient)