orionis 0.546.0__py3-none-any.whl → 0.547.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.
- orionis/console/base/scheduler_event_listener.py +0 -17
- orionis/console/contracts/schedule_event_listener.py +0 -18
- orionis/foundation/config/app/entities/app.py +3 -2
- orionis/foundation/config/app/enums/ciphers.py +5 -19
- orionis/foundation/config/session/entities/session.py +2 -2
- orionis/metadata/framework.py +1 -1
- orionis/services/encrypter/encrypter.py +115 -0
- orionis/services/environment/dynamic/caster.py +35 -27
- orionis/services/environment/key/key_generator.py +32 -11
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/METADATA +1 -1
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/RECORD +15 -159
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/top_level.txt +0 -1
- tests/container/__init__.py +0 -0
- tests/container/context/__init__.py +0 -0
- tests/container/context/test_manager.py +0 -38
- tests/container/context/test_scope.py +0 -32
- tests/container/core/__init__.py +0 -0
- tests/container/core/test_advanced_async.py +0 -234
- tests/container/core/test_async_optimizations.py +0 -268
- tests/container/core/test_container.py +0 -453
- tests/container/core/test_singleton.py +0 -122
- tests/container/core/test_thread_safety.py +0 -90
- tests/container/entities/__init__.py +0 -0
- tests/container/entities/test_binding.py +0 -242
- tests/container/enums/__init__.py +0 -0
- tests/container/enums/test_lifetimes.py +0 -97
- tests/container/facades/__init__.py +0 -0
- tests/container/facades/test_facade.py +0 -78
- tests/container/mocks/__init__.py +0 -0
- tests/container/mocks/mock_advanced_async.py +0 -332
- tests/container/mocks/mock_async_optimizations.py +0 -407
- tests/container/mocks/mock_auto_resolution.py +0 -192
- tests/container/mocks/mock_complex_classes.py +0 -792
- tests/container/mocks/mock_simple_classes.py +0 -98
- tests/container/providers/__init__.py +0 -0
- tests/container/providers/test_providers.py +0 -55
- tests/container/validators/__init__.py +0 -0
- tests/container/validators/test_implements.py +0 -186
- tests/container/validators/test_is_abstract_class.py +0 -147
- tests/container/validators/test_is_callable.py +0 -102
- tests/container/validators/test_is_concrete_class.py +0 -160
- tests/container/validators/test_is_instance.py +0 -150
- tests/container/validators/test_is_not_subclass.py +0 -49
- tests/container/validators/test_is_subclass.py +0 -178
- tests/container/validators/test_is_valid_alias.py +0 -147
- tests/container/validators/test_lifetime.py +0 -106
- tests/example/__init__.py +0 -0
- tests/example/test_example.py +0 -725
- tests/foundation/__init__.py +0 -0
- tests/foundation/config/__init__.py +0 -0
- tests/foundation/config/app/__init__.py +0 -0
- tests/foundation/config/app/test_foundation_config_app.py +0 -262
- tests/foundation/config/auth/__init__.py +0 -0
- tests/foundation/config/auth/test_foundation_config_auth.py +0 -29
- tests/foundation/config/cache/__init__.py +0 -0
- tests/foundation/config/cache/test_foundation_config_cache.py +0 -143
- tests/foundation/config/cache/test_foundation_config_cache_file.py +0 -126
- tests/foundation/config/cache/test_foundation_config_cache_stores.py +0 -156
- tests/foundation/config/cors/__init__.py +0 -0
- tests/foundation/config/cors/test_foundation_config_cors.py +0 -190
- tests/foundation/config/database/__init__.py +0 -0
- tests/foundation/config/database/test_foundation_config_database.py +0 -158
- tests/foundation/config/database/test_foundation_config_database_connections.py +0 -203
- tests/foundation/config/database/test_foundation_config_database_mysql.py +0 -354
- tests/foundation/config/database/test_foundation_config_database_oracle.py +0 -288
- tests/foundation/config/database/test_foundation_config_database_pgsql.py +0 -257
- tests/foundation/config/database/test_foundation_config_database_sqlite.py +0 -207
- tests/foundation/config/filesystems/__init__.py +0 -0
- tests/foundation/config/filesystems/test_foundation_config_filesystems.py +0 -160
- tests/foundation/config/filesystems/test_foundation_config_filesystems_aws.py +0 -189
- tests/foundation/config/filesystems/test_foundation_config_filesystems_disks.py +0 -184
- tests/foundation/config/filesystems/test_foundation_config_filesystems_local.py +0 -143
- tests/foundation/config/filesystems/test_foundation_config_filesystems_public.py +0 -184
- tests/foundation/config/logging/__init__.py +0 -0
- tests/foundation/config/logging/test_foundation_config_logging.py +0 -112
- tests/foundation/config/logging/test_foundation_config_logging_channels.py +0 -246
- tests/foundation/config/logging/test_foundation_config_logging_chunked.py +0 -217
- tests/foundation/config/logging/test_foundation_config_logging_daily.py +0 -220
- tests/foundation/config/logging/test_foundation_config_logging_hourly.py +0 -196
- tests/foundation/config/logging/test_foundation_config_logging_monthly.py +0 -214
- tests/foundation/config/logging/test_foundation_config_logging_stack.py +0 -178
- tests/foundation/config/logging/test_foundation_config_logging_weekly.py +0 -224
- tests/foundation/config/mail/__init__.py +0 -0
- tests/foundation/config/mail/test_foundation_config_mail.py +0 -145
- tests/foundation/config/mail/test_foundation_config_mail_file.py +0 -97
- tests/foundation/config/mail/test_foundation_config_mail_mailers.py +0 -106
- tests/foundation/config/mail/test_foundation_config_mail_smtp.py +0 -146
- tests/foundation/config/queue/__init__.py +0 -0
- tests/foundation/config/queue/test_foundation_config_queue.py +0 -88
- tests/foundation/config/queue/test_foundation_config_queue_brokers.py +0 -72
- tests/foundation/config/queue/test_foundation_config_queue_database.py +0 -134
- tests/foundation/config/root/__init__.py +0 -0
- tests/foundation/config/root/test_foundation_config_root_paths.py +0 -112
- tests/foundation/config/session/__init__.py +0 -0
- tests/foundation/config/session/test_foundation_config_session.py +0 -213
- tests/foundation/config/startup/__init__.py +0 -0
- tests/foundation/config/startup/test_foundation_config_startup.py +0 -202
- tests/foundation/config/testing/__init__.py +0 -0
- tests/foundation/config/testing/test_foundation_config_testing.py +0 -235
- tests/metadata/__init__.py +0 -0
- tests/metadata/test_metadata_framework.py +0 -140
- tests/metadata/test_metadata_package.py +0 -139
- tests/services/__init__.py +0 -0
- tests/services/asynchrony/__init__.py +0 -0
- tests/services/asynchrony/test_services_asynchrony_coroutine.py +0 -85
- tests/services/environment/__init__.py +0 -0
- tests/services/environment/test_services_environment.py +0 -226
- tests/services/introspection/__init__.py +0 -0
- tests/services/introspection/dependencies/__init__.py +0 -0
- tests/services/introspection/dependencies/mocks/__init__.py +0 -0
- tests/services/introspection/dependencies/mocks/mock_user.py +0 -30
- tests/services/introspection/dependencies/mocks/mock_user_controller.py +0 -27
- tests/services/introspection/dependencies/mocks/mock_users_permissions.py +0 -41
- tests/services/introspection/dependencies/test_reflect_dependencies.py +0 -261
- tests/services/introspection/reflection/__init__.py +0 -0
- tests/services/introspection/reflection/mock/__init__.py +0 -0
- tests/services/introspection/reflection/mock/fake_reflect_instance.py +0 -1115
- tests/services/introspection/reflection/test_reflection_abstract.py +0 -1011
- tests/services/introspection/reflection/test_reflection_callable.py +0 -206
- tests/services/introspection/reflection/test_reflection_concrete.py +0 -952
- tests/services/introspection/reflection/test_reflection_instance.py +0 -1233
- tests/services/introspection/reflection/test_reflection_module.py +0 -567
- tests/services/introspection/test_reflection.py +0 -462
- tests/services/log/__init__.py +0 -0
- tests/services/log/test_log.py +0 -97
- tests/services/system/__init__.py +0 -0
- tests/services/system/test_services_system_imports.py +0 -204
- tests/services/system/test_services_system_workers.py +0 -131
- tests/support/__init__.py +0 -0
- tests/support/entities/__init__.py +0 -0
- tests/support/entities/mock_dataclass.py +0 -40
- tests/support/entities/test_base.py +0 -64
- tests/support/patterns/__init__.py +0 -0
- tests/support/patterns/singleton/__init__.py +0 -0
- tests/support/patterns/singleton/test_patterns_singleton.py +0 -39
- tests/support/standard/__init__.py +0 -0
- tests/support/standard/test_services_std.py +0 -226
- tests/support/wrapper/__init__.py +0 -0
- tests/support/wrapper/test_services_wrapper_docdict.py +0 -202
- tests/testing/__init__.py +0 -0
- tests/testing/cases/__init__.py +0 -0
- tests/testing/cases/test_testing_asynchronous.py +0 -63
- tests/testing/cases/test_testing_synchronous.py +0 -57
- tests/testing/entities/__init__.py +0 -0
- tests/testing/entities/test_testing_result.py +0 -146
- tests/testing/enums/__init__.py +0 -0
- tests/testing/enums/test_testing_status.py +0 -63
- tests/testing/output/__init__.py +0 -0
- tests/testing/output/test_testing_dumper.py +0 -29
- tests/testing/output/test_testing_printer.py +0 -42
- tests/testing/records/__init__.py +0 -0
- tests/testing/records/test_testing_records.py +0 -171
- tests/testing/test_testing_unit.py +0 -164
- tests/testing/validators/__init__.py +0 -0
- tests/testing/validators/test_testing_validators.py +0 -392
- tests/testing/view/__init__.py +0 -0
- tests/testing/view/test_render.py +0 -30
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/WHEEL +0 -0
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/zip-safe +0 -0
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
from orionis.container.container import Container
|
|
2
|
-
from orionis.container.facades.facade import Facade
|
|
3
|
-
from orionis.foundation.application import Application
|
|
4
|
-
from orionis.test.cases.asynchronous import AsyncTestCase
|
|
5
|
-
from tests.container.mocks.mock_simple_classes import Car, ICar
|
|
6
|
-
|
|
7
|
-
class TestContainer(AsyncTestCase):
|
|
8
|
-
|
|
9
|
-
async def testTransientRegistration(self) -> None:
|
|
10
|
-
"""
|
|
11
|
-
Tests the transient registration of a service in the container.
|
|
12
|
-
|
|
13
|
-
This method verifies the following behaviors:
|
|
14
|
-
- The `container.transient()` method correctly registers a transient binding from an abstract type (`ICar`) to a concrete implementation (`Car`).
|
|
15
|
-
- Each call to `container.make(ICar)` returns a new instance of `Car`, confirming transient behavior.
|
|
16
|
-
- The resolved instances are of the correct type (`Car`), and each instance is a distinct object.
|
|
17
|
-
|
|
18
|
-
Parameters
|
|
19
|
-
----------
|
|
20
|
-
self : TestContainer
|
|
21
|
-
The test case instance.
|
|
22
|
-
|
|
23
|
-
Returns
|
|
24
|
-
-------
|
|
25
|
-
None
|
|
26
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
27
|
-
|
|
28
|
-
Notes
|
|
29
|
-
-----
|
|
30
|
-
After the test, the registration for `ICar` is dropped from the container to clean up.
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
# Create a new container instance
|
|
34
|
-
container = Container()
|
|
35
|
-
|
|
36
|
-
# Register ICar as a transient binding to Car
|
|
37
|
-
container.transient(ICar, Car)
|
|
38
|
-
|
|
39
|
-
# Resolve two instances of ICar (should be different objects)
|
|
40
|
-
instance1 = container.make(ICar)
|
|
41
|
-
instance2 = container.make(ICar)
|
|
42
|
-
|
|
43
|
-
# Assert both instances are of type Car
|
|
44
|
-
self.assertIsInstance(instance1, Car)
|
|
45
|
-
self.assertIsInstance(instance2, Car)
|
|
46
|
-
|
|
47
|
-
# Assert that the instances are not the same object (transient behavior)
|
|
48
|
-
self.assertIsNot(instance1, instance2)
|
|
49
|
-
|
|
50
|
-
# Clean up registration
|
|
51
|
-
container.drop(abstract=ICar)
|
|
52
|
-
|
|
53
|
-
async def testSingletonRegistration(self) -> None:
|
|
54
|
-
"""
|
|
55
|
-
Tests singleton registration and resolution from the container.
|
|
56
|
-
|
|
57
|
-
This method ensures:
|
|
58
|
-
- A class (`Car`) can be registered as a singleton implementation of an interface (`ICar`).
|
|
59
|
-
- The container returns an instance of the registered implementation.
|
|
60
|
-
- Multiple requests for the same interface return the same instance, confirming singleton behavior.
|
|
61
|
-
|
|
62
|
-
Parameters
|
|
63
|
-
----------
|
|
64
|
-
self : TestContainer
|
|
65
|
-
The test case instance.
|
|
66
|
-
|
|
67
|
-
Returns
|
|
68
|
-
-------
|
|
69
|
-
None
|
|
70
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
71
|
-
|
|
72
|
-
Notes
|
|
73
|
-
-----
|
|
74
|
-
The registration for `ICar` is dropped after the test.
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
# Create a new container instance
|
|
78
|
-
container = Container()
|
|
79
|
-
|
|
80
|
-
# Register ICar as a singleton binding to Car
|
|
81
|
-
container.singleton(ICar, Car)
|
|
82
|
-
|
|
83
|
-
# Resolve two instances of ICar (should be the same object)
|
|
84
|
-
instance1 = container.make(ICar)
|
|
85
|
-
instance2 = container.make(ICar)
|
|
86
|
-
|
|
87
|
-
# Assert both instances are of type Car
|
|
88
|
-
self.assertIsInstance(instance1, Car)
|
|
89
|
-
self.assertIsInstance(instance2, Car)
|
|
90
|
-
|
|
91
|
-
# Assert that both instances are the same object (singleton behavior)
|
|
92
|
-
self.assertIs(instance1, instance2)
|
|
93
|
-
|
|
94
|
-
# Clean up registration
|
|
95
|
-
container.drop(abstract=ICar)
|
|
96
|
-
|
|
97
|
-
async def testScopedRegistration(self) -> None:
|
|
98
|
-
"""
|
|
99
|
-
Tests the scoped registration functionality of the container.
|
|
100
|
-
|
|
101
|
-
This method verifies:
|
|
102
|
-
- Within a single context, scoped registrations return the same instance when the same interface is requested multiple times.
|
|
103
|
-
- Different contexts produce different instances of the same registration.
|
|
104
|
-
|
|
105
|
-
Parameters
|
|
106
|
-
----------
|
|
107
|
-
self : TestContainer
|
|
108
|
-
The test case instance.
|
|
109
|
-
|
|
110
|
-
Returns
|
|
111
|
-
-------
|
|
112
|
-
None
|
|
113
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
114
|
-
|
|
115
|
-
Notes
|
|
116
|
-
-----
|
|
117
|
-
The registration for `ICar` is dropped after the test.
|
|
118
|
-
"""
|
|
119
|
-
|
|
120
|
-
# Create a new container instance
|
|
121
|
-
container = Container()
|
|
122
|
-
|
|
123
|
-
# First context: instances should be the same
|
|
124
|
-
with container.createContext():
|
|
125
|
-
container.scoped(ICar, Car)
|
|
126
|
-
instance1 = container.make(ICar)
|
|
127
|
-
instance2 = container.make(ICar)
|
|
128
|
-
|
|
129
|
-
self.assertIsInstance(instance1, Car)
|
|
130
|
-
self.assertIsInstance(instance2, Car)
|
|
131
|
-
self.assertIs(instance1, instance2)
|
|
132
|
-
|
|
133
|
-
# Second context: instance should be different from previous context
|
|
134
|
-
with container.createContext():
|
|
135
|
-
container.scoped(ICar, Car)
|
|
136
|
-
instance3 = container.make(ICar)
|
|
137
|
-
self.assertIsNot(instance1, instance3)
|
|
138
|
-
|
|
139
|
-
# Clean up registration
|
|
140
|
-
container.drop(abstract=ICar)
|
|
141
|
-
|
|
142
|
-
async def testInstanceRegistration(self) -> None:
|
|
143
|
-
"""
|
|
144
|
-
Tests instance registration in the container.
|
|
145
|
-
|
|
146
|
-
This method ensures:
|
|
147
|
-
- When an instance is registered to a service in the container, the container returns exactly the same instance when resolving that service.
|
|
148
|
-
|
|
149
|
-
Parameters
|
|
150
|
-
----------
|
|
151
|
-
self : TestContainer
|
|
152
|
-
The test case instance.
|
|
153
|
-
|
|
154
|
-
Returns
|
|
155
|
-
-------
|
|
156
|
-
None
|
|
157
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
158
|
-
|
|
159
|
-
Notes
|
|
160
|
-
-----
|
|
161
|
-
The registration for `ICar` is dropped after the test.
|
|
162
|
-
"""
|
|
163
|
-
|
|
164
|
-
# Create a specific instance of Car
|
|
165
|
-
car_instance = Car()
|
|
166
|
-
container = Container()
|
|
167
|
-
|
|
168
|
-
# Register a specific instance of Car to ICar
|
|
169
|
-
container.instance(ICar, car_instance)
|
|
170
|
-
|
|
171
|
-
# Resolve ICar and check that it returns the same instance
|
|
172
|
-
resolved = container.make(ICar)
|
|
173
|
-
self.assertIs(resolved, car_instance)
|
|
174
|
-
|
|
175
|
-
# Clean up registration
|
|
176
|
-
container.drop(abstract=ICar)
|
|
177
|
-
|
|
178
|
-
async def testCallableRegistration(self) -> None:
|
|
179
|
-
"""
|
|
180
|
-
Tests that callables can be registered and resolved from the container.
|
|
181
|
-
|
|
182
|
-
This method verifies:
|
|
183
|
-
- Functions can be registered in the container using the `callable()` method.
|
|
184
|
-
- Registered functions can be resolved and executed using the `make()` method.
|
|
185
|
-
- Arguments can be passed to the resolved functions as positional and keyword arguments.
|
|
186
|
-
|
|
187
|
-
Parameters
|
|
188
|
-
----------
|
|
189
|
-
self : TestContainer
|
|
190
|
-
The test case instance.
|
|
191
|
-
|
|
192
|
-
Returns
|
|
193
|
-
-------
|
|
194
|
-
None
|
|
195
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
196
|
-
|
|
197
|
-
Notes
|
|
198
|
-
-----
|
|
199
|
-
The registrations for 'add' and 'multiply' are dropped after the test.
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
# Define some simple functions to register
|
|
203
|
-
def add(a: int, b: int) -> int:
|
|
204
|
-
return a + b
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
# Define another function to register
|
|
208
|
-
def multiply(a: int, b: int) -> int:
|
|
209
|
-
return a * b
|
|
210
|
-
|
|
211
|
-
# Create a new container instance
|
|
212
|
-
container = Container()
|
|
213
|
-
|
|
214
|
-
# Register callables
|
|
215
|
-
container.callable('add', add)
|
|
216
|
-
container.callable('multiply', multiply)
|
|
217
|
-
|
|
218
|
-
# Test resolution and execution with positional and keyword arguments
|
|
219
|
-
self.assertEqual(container.make('add', 1, 2), 3)
|
|
220
|
-
self.assertEqual(container.make('multiply', 3, 4), 12)
|
|
221
|
-
self.assertEqual(container.make('add', a=5, b=7), 12)
|
|
222
|
-
|
|
223
|
-
# Clean up registrations
|
|
224
|
-
container.drop(alias='add')
|
|
225
|
-
container.drop(alias='multiply')
|
|
226
|
-
|
|
227
|
-
async def testTransientFacade(self) -> None:
|
|
228
|
-
"""
|
|
229
|
-
Tests transient instance resolution using the Facade pattern.
|
|
230
|
-
|
|
231
|
-
This method validates:
|
|
232
|
-
- The container can register a transient binding between an interface and a class.
|
|
233
|
-
- The Facade pattern correctly resolves instances of the registered interface.
|
|
234
|
-
- Multiple calls to the Facade's `resolve()` method return different instances, confirming transient behavior.
|
|
235
|
-
|
|
236
|
-
Parameters
|
|
237
|
-
----------
|
|
238
|
-
self : TestContainer
|
|
239
|
-
The test case instance.
|
|
240
|
-
|
|
241
|
-
Returns
|
|
242
|
-
-------
|
|
243
|
-
None
|
|
244
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
245
|
-
|
|
246
|
-
Notes
|
|
247
|
-
-----
|
|
248
|
-
The registration for `ICar` is dropped after the test.
|
|
249
|
-
"""
|
|
250
|
-
|
|
251
|
-
# Create a new container instance
|
|
252
|
-
container = Application()
|
|
253
|
-
|
|
254
|
-
# Register ICar as a transient binding to Car
|
|
255
|
-
container.transient(ICar, Car)
|
|
256
|
-
|
|
257
|
-
# Define a Facade class to access the ICar binding
|
|
258
|
-
class CarFacade(Facade):
|
|
259
|
-
@classmethod
|
|
260
|
-
def getFacadeAccessor(cls):
|
|
261
|
-
return ICar
|
|
262
|
-
|
|
263
|
-
# Resolve two instances via Facade (should be different objects)
|
|
264
|
-
instance1 = CarFacade.resolve()
|
|
265
|
-
instance2 = CarFacade.resolve()
|
|
266
|
-
|
|
267
|
-
self.assertIsInstance(instance1, Car)
|
|
268
|
-
self.assertIsInstance(instance2, Car)
|
|
269
|
-
self.assertIsNot(instance1, instance2)
|
|
270
|
-
|
|
271
|
-
# Clean up registration
|
|
272
|
-
container.drop(abstract=ICar)
|
|
273
|
-
|
|
274
|
-
async def testSingletonFacade(self) -> None:
|
|
275
|
-
"""
|
|
276
|
-
Tests singleton instance resolution using the Facade pattern.
|
|
277
|
-
|
|
278
|
-
This method verifies:
|
|
279
|
-
- A singleton binding can be registered in the container.
|
|
280
|
-
- A Facade class can be created to access this binding.
|
|
281
|
-
- Multiple resolutions through the Facade return the same instance, confirming singleton behavior.
|
|
282
|
-
- The resolved instances are of the correct type (`Car`).
|
|
283
|
-
|
|
284
|
-
Parameters
|
|
285
|
-
----------
|
|
286
|
-
self : TestContainer
|
|
287
|
-
The test case instance.
|
|
288
|
-
|
|
289
|
-
Returns
|
|
290
|
-
-------
|
|
291
|
-
None
|
|
292
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
293
|
-
|
|
294
|
-
Notes
|
|
295
|
-
-----
|
|
296
|
-
The registration for `ICar` is dropped after the test.
|
|
297
|
-
"""
|
|
298
|
-
|
|
299
|
-
# Create a new container instance
|
|
300
|
-
container = Application()
|
|
301
|
-
|
|
302
|
-
# Register ICar as a singleton binding to Car
|
|
303
|
-
container.singleton(ICar, Car)
|
|
304
|
-
|
|
305
|
-
# Define a Facade class to access the ICar binding
|
|
306
|
-
class CarFacade(Facade):
|
|
307
|
-
@classmethod
|
|
308
|
-
def getFacadeAccessor(cls):
|
|
309
|
-
return ICar
|
|
310
|
-
|
|
311
|
-
# Resolve two instances via Facade (should be the same object)
|
|
312
|
-
instance1 = CarFacade.resolve()
|
|
313
|
-
instance2 = CarFacade.resolve()
|
|
314
|
-
|
|
315
|
-
# Assert both instances are of type Car and are the same object
|
|
316
|
-
self.assertIsInstance(instance1, Car)
|
|
317
|
-
self.assertIsInstance(instance2, Car)
|
|
318
|
-
self.assertIs(instance1, instance2)
|
|
319
|
-
|
|
320
|
-
# Clean up registration
|
|
321
|
-
container.drop(abstract=ICar)
|
|
322
|
-
|
|
323
|
-
async def testScopedFacade(self) -> None:
|
|
324
|
-
"""
|
|
325
|
-
Tests the functionality of a Facade accessing a scoped service within a container context.
|
|
326
|
-
|
|
327
|
-
This method verifies:
|
|
328
|
-
- The Facade can properly resolve a scoped service.
|
|
329
|
-
- Multiple resolves within the same scope return the same instance, confirming scoped behavior.
|
|
330
|
-
- The resolved instance is of the correct type (`Car`).
|
|
331
|
-
|
|
332
|
-
Parameters
|
|
333
|
-
----------
|
|
334
|
-
self : TestContainer
|
|
335
|
-
The test case instance.
|
|
336
|
-
|
|
337
|
-
Returns
|
|
338
|
-
-------
|
|
339
|
-
None
|
|
340
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
341
|
-
|
|
342
|
-
Notes
|
|
343
|
-
-----
|
|
344
|
-
The registration for `ICar` is dropped after the test.
|
|
345
|
-
"""
|
|
346
|
-
|
|
347
|
-
# Create a new container instance
|
|
348
|
-
container = Application()
|
|
349
|
-
|
|
350
|
-
# Create a new scope/context
|
|
351
|
-
with container.createContext():
|
|
352
|
-
|
|
353
|
-
# Register ICar as a scoped binding to Car
|
|
354
|
-
container.scoped(ICar, Car)
|
|
355
|
-
|
|
356
|
-
# Define a Facade class to access the ICar binding
|
|
357
|
-
class CarFacade(Facade):
|
|
358
|
-
@classmethod
|
|
359
|
-
def getFacadeAccessor(cls):
|
|
360
|
-
return ICar
|
|
361
|
-
|
|
362
|
-
# Resolve two instances via Facade (should be the same object within the scope)
|
|
363
|
-
instance1 = CarFacade.resolve()
|
|
364
|
-
instance2 = CarFacade.resolve()
|
|
365
|
-
|
|
366
|
-
# Assert both instances are of type Car and are the same object
|
|
367
|
-
self.assertIsInstance(instance1, Car)
|
|
368
|
-
self.assertIsInstance(instance2, Car)
|
|
369
|
-
self.assertIs(instance1, instance2)
|
|
370
|
-
|
|
371
|
-
# Clean up registration
|
|
372
|
-
container.drop(abstract=ICar)
|
|
373
|
-
|
|
374
|
-
async def testResolvingUnregisteredType(self) -> None:
|
|
375
|
-
"""
|
|
376
|
-
Tests that attempting to resolve an unregistered type from the container raises an exception.
|
|
377
|
-
|
|
378
|
-
This method ensures:
|
|
379
|
-
- The container correctly validates that a type is registered before attempting to resolve it.
|
|
380
|
-
- An exception is raised when attempting to resolve an unregistered type.
|
|
381
|
-
|
|
382
|
-
Parameters
|
|
383
|
-
----------
|
|
384
|
-
self : TestContainer
|
|
385
|
-
The test case instance.
|
|
386
|
-
|
|
387
|
-
Returns
|
|
388
|
-
-------
|
|
389
|
-
None
|
|
390
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
391
|
-
|
|
392
|
-
Raises
|
|
393
|
-
------
|
|
394
|
-
Exception
|
|
395
|
-
Raised when attempting to resolve an unregistered type.
|
|
396
|
-
"""
|
|
397
|
-
|
|
398
|
-
# Create a new container instance
|
|
399
|
-
container = Container()
|
|
400
|
-
|
|
401
|
-
# Attempt to resolve an unregistered type; should raise Exception
|
|
402
|
-
with self.assertRaises(Exception):
|
|
403
|
-
container.make('ICar')
|
|
404
|
-
|
|
405
|
-
async def testOverridingRegistration(self) -> None:
|
|
406
|
-
"""
|
|
407
|
-
Tests the ability of the container to override existing registrations.
|
|
408
|
-
|
|
409
|
-
This method verifies:
|
|
410
|
-
- When a class is registered as a singleton for an interface.
|
|
411
|
-
- A different class can later be registered for the same interface.
|
|
412
|
-
- The container returns the new class when resolving the interface.
|
|
413
|
-
- The new instance is different from the previous instance, confirming the override.
|
|
414
|
-
|
|
415
|
-
Parameters
|
|
416
|
-
----------
|
|
417
|
-
self : TestContainer
|
|
418
|
-
The test case instance.
|
|
419
|
-
|
|
420
|
-
Returns
|
|
421
|
-
-------
|
|
422
|
-
None
|
|
423
|
-
This method does not return any value. Assertions are used to validate expected behavior.
|
|
424
|
-
|
|
425
|
-
Notes
|
|
426
|
-
-----
|
|
427
|
-
The registration for `ICar` is dropped after the test.
|
|
428
|
-
"""
|
|
429
|
-
|
|
430
|
-
# Create a new container instance
|
|
431
|
-
class SportsCar(Car):
|
|
432
|
-
def start(self):
|
|
433
|
-
return f"{self.brand} {self.model} is starting."
|
|
434
|
-
def stop(self):
|
|
435
|
-
return f"{self.brand} {self.model} is stopping."
|
|
436
|
-
|
|
437
|
-
# Create a new container instance
|
|
438
|
-
container = Container()
|
|
439
|
-
|
|
440
|
-
# Register ICar as a singleton binding to Car
|
|
441
|
-
container.singleton(ICar, Car)
|
|
442
|
-
first = container.make(ICar)
|
|
443
|
-
self.assertIsInstance(first, Car)
|
|
444
|
-
self.assertNotIsInstance(first, SportsCar)
|
|
445
|
-
|
|
446
|
-
# Override registration: register ICar as a singleton binding to SportsCar
|
|
447
|
-
container.singleton(ICar, SportsCar)
|
|
448
|
-
second = container.make(ICar)
|
|
449
|
-
self.assertIsInstance(second, SportsCar)
|
|
450
|
-
self.assertIsNot(first, second)
|
|
451
|
-
|
|
452
|
-
# Clean up registration
|
|
453
|
-
container.drop(abstract=ICar)
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import time
|
|
3
|
-
from orionis.foundation.application import Application as Orionis
|
|
4
|
-
from orionis.container.container import Container
|
|
5
|
-
from orionis.test.cases.asynchronous import AsyncTestCase
|
|
6
|
-
|
|
7
|
-
class TestSingleton(AsyncTestCase):
|
|
8
|
-
|
|
9
|
-
async def testSingletonBasicFunctionality(self) -> None:
|
|
10
|
-
"""
|
|
11
|
-
Tests the fundamental behavior of the singleton pattern for `Container` and `Orionis` classes.
|
|
12
|
-
|
|
13
|
-
This method verifies the following:
|
|
14
|
-
- Multiple instances of `Container` refer to the same object.
|
|
15
|
-
- Multiple instances of `Orionis` refer to the same object.
|
|
16
|
-
- The singleton instances of `Container` and `Orionis` are distinct from each other.
|
|
17
|
-
|
|
18
|
-
Returns
|
|
19
|
-
-------
|
|
20
|
-
None
|
|
21
|
-
This method does not return any value. Assertions are used to validate singleton behavior.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
# Create multiple instances of Container and Orionis
|
|
25
|
-
container1 = Container()
|
|
26
|
-
container2 = Container()
|
|
27
|
-
orionis1 = Orionis()
|
|
28
|
-
orionis2 = Orionis()
|
|
29
|
-
|
|
30
|
-
# Assert that all Container instances are the same object
|
|
31
|
-
self.assertIs(container1, container2)
|
|
32
|
-
self.assertEqual(id(container1), id(container2))
|
|
33
|
-
|
|
34
|
-
# Assert that all Orionis instances are the same object
|
|
35
|
-
self.assertIs(orionis1, orionis2)
|
|
36
|
-
self.assertEqual(id(orionis1), id(orionis2))
|
|
37
|
-
|
|
38
|
-
# Assert that Container and Orionis are different singleton instances
|
|
39
|
-
self.assertIsNot(container1, orionis1)
|
|
40
|
-
|
|
41
|
-
async def testSingletonThreadingSafety(self) -> None:
|
|
42
|
-
"""
|
|
43
|
-
Validates the thread safety of the singleton pattern for `Container` and `Orionis` classes.
|
|
44
|
-
|
|
45
|
-
This method ensures that, even when multiple threads attempt to instantiate
|
|
46
|
-
`Container` and `Orionis` simultaneously, only one instance of each class is created.
|
|
47
|
-
|
|
48
|
-
Returns
|
|
49
|
-
-------
|
|
50
|
-
None
|
|
51
|
-
This method does not return any value. Assertions are used to validate thread-safe singleton behavior.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
# List to hold instances created in threads
|
|
55
|
-
container_instances = []
|
|
56
|
-
orionis_instances = []
|
|
57
|
-
|
|
58
|
-
def create_container():
|
|
59
|
-
"""Create and append a Container instance in a thread."""
|
|
60
|
-
time.sleep(0.01) # Increase chance of race condition
|
|
61
|
-
container_instances.append(Container())
|
|
62
|
-
|
|
63
|
-
def create_orionis():
|
|
64
|
-
"""Create and append an Orionis instance in a thread."""
|
|
65
|
-
time.sleep(0.01) # Increase chance of race condition
|
|
66
|
-
orionis_instances.append(Orionis())
|
|
67
|
-
|
|
68
|
-
# Create threads for concurrent instantiation
|
|
69
|
-
threads = []
|
|
70
|
-
for i in range(10):
|
|
71
|
-
t1 = threading.Thread(target=create_container)
|
|
72
|
-
t2 = threading.Thread(target=create_orionis)
|
|
73
|
-
threads.extend([t1, t2])
|
|
74
|
-
|
|
75
|
-
# Start all threads
|
|
76
|
-
for t in threads:
|
|
77
|
-
t.start()
|
|
78
|
-
|
|
79
|
-
# Wait for all threads to complete
|
|
80
|
-
for t in threads:
|
|
81
|
-
t.join()
|
|
82
|
-
|
|
83
|
-
# Collect instance IDs for verification
|
|
84
|
-
container_ids = [id(c) for c in container_instances]
|
|
85
|
-
orionis_ids = [id(o) for o in orionis_instances]
|
|
86
|
-
|
|
87
|
-
# Assert that only one unique instance exists for each class
|
|
88
|
-
self.assertEqual(len(set(container_ids)), 1)
|
|
89
|
-
self.assertEqual(len(set(orionis_ids)), 1)
|
|
90
|
-
self.assertEqual(len(container_instances), 10)
|
|
91
|
-
self.assertEqual(len(orionis_instances), 10)
|
|
92
|
-
|
|
93
|
-
async def testInheritanceSeparation(self) -> None:
|
|
94
|
-
"""
|
|
95
|
-
Ensures that singleton instances are maintained separately for `Container` and `Orionis` classes.
|
|
96
|
-
|
|
97
|
-
This method checks that:
|
|
98
|
-
- Each class maintains its own singleton instance.
|
|
99
|
-
- Data added to one singleton does not affect the other.
|
|
100
|
-
- Both classes correctly implement the singleton pattern independently.
|
|
101
|
-
|
|
102
|
-
Returns
|
|
103
|
-
-------
|
|
104
|
-
None
|
|
105
|
-
This method does not return any value. Assertions are used to validate singleton separation.
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
# Create instances of Container and Orionis
|
|
109
|
-
container = Container()
|
|
110
|
-
orionis = Orionis()
|
|
111
|
-
|
|
112
|
-
# Add a callable to the Container singleton
|
|
113
|
-
container.callable("test_container", lambda: "container_value")
|
|
114
|
-
|
|
115
|
-
# Verify that Container and Orionis are distinct singletons
|
|
116
|
-
self.assertEqual(type(container).__name__, "Container")
|
|
117
|
-
self.assertEqual(type(orionis).__name__, "Application")
|
|
118
|
-
self.assertIsNot(container, orionis)
|
|
119
|
-
|
|
120
|
-
# Check that the callable is bound only to Container
|
|
121
|
-
self.assertTrue(container.bound('test_container'))
|
|
122
|
-
self.assertFalse(orionis.bound('test_container'))
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import random
|
|
3
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
4
|
-
from orionis.foundation.application import Application as Orionis
|
|
5
|
-
from orionis.container.container import Container
|
|
6
|
-
from orionis.test.cases.asynchronous import AsyncTestCase
|
|
7
|
-
|
|
8
|
-
class TestThreadSafety(AsyncTestCase):
|
|
9
|
-
|
|
10
|
-
async def testStressSingleton(self) -> None:
|
|
11
|
-
"""
|
|
12
|
-
Stress test singleton behavior under extreme concurrent conditions.
|
|
13
|
-
|
|
14
|
-
This method creates a large number of threads that simultaneously attempt to
|
|
15
|
-
instantiate singleton objects (`Container` and `Orionis`). It verifies that
|
|
16
|
-
only one unique instance of each singleton exists, regardless of concurrent
|
|
17
|
-
access, and that the singleton instances are distinct from each other.
|
|
18
|
-
|
|
19
|
-
Parameters
|
|
20
|
-
----------
|
|
21
|
-
None
|
|
22
|
-
|
|
23
|
-
Returns
|
|
24
|
-
-------
|
|
25
|
-
None
|
|
26
|
-
This method does not return any value. Assertions are used to validate
|
|
27
|
-
singleton behavior under stress.
|
|
28
|
-
|
|
29
|
-
Notes
|
|
30
|
-
-----
|
|
31
|
-
- Random delays are introduced to increase the likelihood of race conditions.
|
|
32
|
-
- ThreadPoolExecutor is used to simulate high concurrency.
|
|
33
|
-
- The test ensures that singleton integrity is maintained even under heavy load.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
# Create lists to hold instances created in threads
|
|
37
|
-
container_instances = []
|
|
38
|
-
orionis_instances = []
|
|
39
|
-
|
|
40
|
-
def create_container_with_delay():
|
|
41
|
-
"""Create a Container instance after a random delay to simulate real-world concurrency."""
|
|
42
|
-
# Random delay to increase chance of race conditions
|
|
43
|
-
time.sleep(random.uniform(0.001, 0.01))
|
|
44
|
-
container = Container()
|
|
45
|
-
container_instances.append(container)
|
|
46
|
-
return id(container)
|
|
47
|
-
|
|
48
|
-
def create_orionis_with_delay():
|
|
49
|
-
"""Create an Orionis instance after a random delay to simulate real-world concurrency."""
|
|
50
|
-
# Random delay to increase chance of race conditions
|
|
51
|
-
time.sleep(random.uniform(0.001, 0.01))
|
|
52
|
-
orionis = Orionis()
|
|
53
|
-
orionis_instances.append(orionis)
|
|
54
|
-
return id(orionis)
|
|
55
|
-
|
|
56
|
-
# Number of concurrent threads to simulate
|
|
57
|
-
num_threads = 100
|
|
58
|
-
|
|
59
|
-
# Use ThreadPoolExecutor to run tasks concurrently
|
|
60
|
-
with ThreadPoolExecutor(max_workers=50) as executor:
|
|
61
|
-
# Submit container creation tasks
|
|
62
|
-
container_futures = [
|
|
63
|
-
executor.submit(create_container_with_delay)
|
|
64
|
-
for _ in range(num_threads)
|
|
65
|
-
]
|
|
66
|
-
|
|
67
|
-
# Submit orionis creation tasks
|
|
68
|
-
orionis_futures = [
|
|
69
|
-
executor.submit(create_orionis_with_delay)
|
|
70
|
-
for _ in range(num_threads)
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
# Wait for all tasks to complete and collect instance IDs
|
|
74
|
-
container_ids = [future.result() for future in as_completed(container_futures)]
|
|
75
|
-
orionis_ids = [future.result() for future in as_completed(orionis_futures)]
|
|
76
|
-
|
|
77
|
-
# Verify all instances are the same (singleton property)
|
|
78
|
-
unique_container_ids = set(container_ids)
|
|
79
|
-
unique_orionis_ids = set(orionis_ids)
|
|
80
|
-
|
|
81
|
-
self.assertEqual(len(container_instances), num_threads)
|
|
82
|
-
self.assertEqual(len(unique_container_ids), 1)
|
|
83
|
-
self.assertEqual(len(orionis_instances), num_threads)
|
|
84
|
-
self.assertEqual(len(unique_orionis_ids), 1)
|
|
85
|
-
|
|
86
|
-
# Verify that Container and Orionis are different singletons
|
|
87
|
-
container_id = list(unique_container_ids)[0] if unique_container_ids else None
|
|
88
|
-
orionis_id = list(unique_orionis_ids)[0] if unique_orionis_ids else None
|
|
89
|
-
|
|
90
|
-
self.assertNotEqual(container_id, orionis_id)
|
|
File without changes
|