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.
- julee/__init__.py +3 -0
- julee/api/__init__.py +20 -0
- julee/api/app.py +180 -0
- julee/api/dependencies.py +257 -0
- julee/api/requests.py +175 -0
- julee/api/responses.py +43 -0
- julee/api/routers/__init__.py +43 -0
- julee/api/routers/assembly_specifications.py +212 -0
- julee/api/routers/documents.py +182 -0
- julee/api/routers/knowledge_service_configs.py +79 -0
- julee/api/routers/knowledge_service_queries.py +293 -0
- julee/api/routers/system.py +137 -0
- julee/api/routers/workflows.py +234 -0
- julee/api/services/__init__.py +20 -0
- julee/api/services/system_initialization.py +214 -0
- julee/api/tests/__init__.py +14 -0
- julee/api/tests/routers/__init__.py +17 -0
- julee/api/tests/routers/test_assembly_specifications.py +749 -0
- julee/api/tests/routers/test_documents.py +301 -0
- julee/api/tests/routers/test_knowledge_service_configs.py +234 -0
- julee/api/tests/routers/test_knowledge_service_queries.py +738 -0
- julee/api/tests/routers/test_system.py +179 -0
- julee/api/tests/routers/test_workflows.py +393 -0
- julee/api/tests/test_app.py +285 -0
- julee/api/tests/test_dependencies.py +245 -0
- julee/api/tests/test_requests.py +250 -0
- julee/domain/__init__.py +22 -0
- julee/domain/models/__init__.py +49 -0
- julee/domain/models/assembly/__init__.py +17 -0
- julee/domain/models/assembly/assembly.py +103 -0
- julee/domain/models/assembly/tests/__init__.py +0 -0
- julee/domain/models/assembly/tests/factories.py +37 -0
- julee/domain/models/assembly/tests/test_assembly.py +430 -0
- julee/domain/models/assembly_specification/__init__.py +24 -0
- julee/domain/models/assembly_specification/assembly_specification.py +172 -0
- julee/domain/models/assembly_specification/knowledge_service_query.py +123 -0
- julee/domain/models/assembly_specification/tests/__init__.py +0 -0
- julee/domain/models/assembly_specification/tests/factories.py +78 -0
- julee/domain/models/assembly_specification/tests/test_assembly_specification.py +490 -0
- julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +310 -0
- julee/domain/models/custom_fields/__init__.py +0 -0
- julee/domain/models/custom_fields/content_stream.py +68 -0
- julee/domain/models/custom_fields/tests/__init__.py +0 -0
- julee/domain/models/custom_fields/tests/test_custom_fields.py +53 -0
- julee/domain/models/document/__init__.py +17 -0
- julee/domain/models/document/document.py +150 -0
- julee/domain/models/document/tests/__init__.py +0 -0
- julee/domain/models/document/tests/factories.py +76 -0
- julee/domain/models/document/tests/test_document.py +297 -0
- julee/domain/models/knowledge_service_config/__init__.py +17 -0
- julee/domain/models/knowledge_service_config/knowledge_service_config.py +86 -0
- julee/domain/models/policy/__init__.py +15 -0
- julee/domain/models/policy/document_policy_validation.py +220 -0
- julee/domain/models/policy/policy.py +203 -0
- julee/domain/models/policy/tests/__init__.py +0 -0
- julee/domain/models/policy/tests/factories.py +47 -0
- julee/domain/models/policy/tests/test_document_policy_validation.py +420 -0
- julee/domain/models/policy/tests/test_policy.py +546 -0
- julee/domain/repositories/__init__.py +27 -0
- julee/domain/repositories/assembly.py +45 -0
- julee/domain/repositories/assembly_specification.py +52 -0
- julee/domain/repositories/base.py +146 -0
- julee/domain/repositories/document.py +49 -0
- julee/domain/repositories/document_policy_validation.py +52 -0
- julee/domain/repositories/knowledge_service_config.py +54 -0
- julee/domain/repositories/knowledge_service_query.py +44 -0
- julee/domain/repositories/policy.py +49 -0
- julee/domain/use_cases/__init__.py +17 -0
- julee/domain/use_cases/decorators.py +107 -0
- julee/domain/use_cases/extract_assemble_data.py +649 -0
- julee/domain/use_cases/initialize_system_data.py +842 -0
- julee/domain/use_cases/tests/__init__.py +7 -0
- julee/domain/use_cases/tests/test_extract_assemble_data.py +548 -0
- julee/domain/use_cases/tests/test_initialize_system_data.py +455 -0
- julee/domain/use_cases/tests/test_validate_document.py +1228 -0
- julee/domain/use_cases/validate_document.py +736 -0
- julee/fixtures/assembly_specifications.yaml +70 -0
- julee/fixtures/documents.yaml +178 -0
- julee/fixtures/knowledge_service_configs.yaml +37 -0
- julee/fixtures/knowledge_service_queries.yaml +27 -0
- julee/repositories/__init__.py +17 -0
- julee/repositories/memory/__init__.py +31 -0
- julee/repositories/memory/assembly.py +84 -0
- julee/repositories/memory/assembly_specification.py +125 -0
- julee/repositories/memory/base.py +227 -0
- julee/repositories/memory/document.py +149 -0
- julee/repositories/memory/document_policy_validation.py +104 -0
- julee/repositories/memory/knowledge_service_config.py +123 -0
- julee/repositories/memory/knowledge_service_query.py +120 -0
- julee/repositories/memory/policy.py +87 -0
- julee/repositories/memory/tests/__init__.py +0 -0
- julee/repositories/memory/tests/test_document.py +212 -0
- julee/repositories/memory/tests/test_document_policy_validation.py +161 -0
- julee/repositories/memory/tests/test_policy.py +443 -0
- julee/repositories/minio/__init__.py +31 -0
- julee/repositories/minio/assembly.py +103 -0
- julee/repositories/minio/assembly_specification.py +170 -0
- julee/repositories/minio/client.py +570 -0
- julee/repositories/minio/document.py +530 -0
- julee/repositories/minio/document_policy_validation.py +120 -0
- julee/repositories/minio/knowledge_service_config.py +187 -0
- julee/repositories/minio/knowledge_service_query.py +211 -0
- julee/repositories/minio/policy.py +106 -0
- julee/repositories/minio/tests/__init__.py +0 -0
- julee/repositories/minio/tests/fake_client.py +213 -0
- julee/repositories/minio/tests/test_assembly.py +374 -0
- julee/repositories/minio/tests/test_assembly_specification.py +391 -0
- julee/repositories/minio/tests/test_client_protocol.py +57 -0
- julee/repositories/minio/tests/test_document.py +591 -0
- julee/repositories/minio/tests/test_document_policy_validation.py +192 -0
- julee/repositories/minio/tests/test_knowledge_service_config.py +374 -0
- julee/repositories/minio/tests/test_knowledge_service_query.py +438 -0
- julee/repositories/minio/tests/test_policy.py +559 -0
- julee/repositories/temporal/__init__.py +38 -0
- julee/repositories/temporal/activities.py +114 -0
- julee/repositories/temporal/activity_names.py +34 -0
- julee/repositories/temporal/proxies.py +159 -0
- julee/services/__init__.py +18 -0
- julee/services/knowledge_service/__init__.py +48 -0
- julee/services/knowledge_service/anthropic/__init__.py +12 -0
- julee/services/knowledge_service/anthropic/knowledge_service.py +331 -0
- julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +318 -0
- julee/services/knowledge_service/factory.py +138 -0
- julee/services/knowledge_service/knowledge_service.py +160 -0
- julee/services/knowledge_service/memory/__init__.py +13 -0
- julee/services/knowledge_service/memory/knowledge_service.py +278 -0
- julee/services/knowledge_service/memory/test_knowledge_service.py +345 -0
- julee/services/knowledge_service/test_factory.py +112 -0
- julee/services/temporal/__init__.py +38 -0
- julee/services/temporal/activities.py +86 -0
- julee/services/temporal/activity_names.py +22 -0
- julee/services/temporal/proxies.py +41 -0
- julee/util/__init__.py +0 -0
- julee/util/domain.py +119 -0
- julee/util/repos/__init__.py +0 -0
- julee/util/repos/minio/__init__.py +0 -0
- julee/util/repos/minio/file_storage.py +213 -0
- julee/util/repos/temporal/__init__.py +11 -0
- julee/util/repos/temporal/client_proxies/file_storage.py +68 -0
- julee/util/repos/temporal/data_converter.py +123 -0
- julee/util/repos/temporal/minio_file_storage.py +12 -0
- julee/util/repos/temporal/proxies/__init__.py +0 -0
- julee/util/repos/temporal/proxies/file_storage.py +58 -0
- julee/util/repositories.py +55 -0
- julee/util/temporal/__init__.py +22 -0
- julee/util/temporal/activities.py +123 -0
- julee/util/temporal/decorators.py +473 -0
- julee/util/tests/__init__.py +1 -0
- julee/util/tests/test_decorators.py +770 -0
- julee/util/validation/__init__.py +29 -0
- julee/util/validation/repository.py +100 -0
- julee/util/validation/type_guards.py +369 -0
- julee/worker.py +211 -0
- julee/workflows/__init__.py +26 -0
- julee/workflows/extract_assemble.py +215 -0
- julee/workflows/validate_document.py +228 -0
- julee-0.1.0.dist-info/METADATA +195 -0
- julee-0.1.0.dist-info/RECORD +161 -0
- julee-0.1.0.dist-info/WHEEL +5 -0
- julee-0.1.0.dist-info/licenses/LICENSE +674 -0
- 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)
|