orionis 0.287.0__py3-none-any.whl → 0.288.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/metadata/framework.py +1 -1
- orionis/services/environment/contracts/types.py +70 -0
- orionis/services/environment/dot_env.py +11 -13
- orionis/services/environment/{type_hint.py → types.py} +64 -45
- orionis/services/paths/exceptions/not_found_exceptions.py +15 -12
- orionis/services/paths/exceptions/path_value_exceptions.py +13 -10
- orionis/services/standard/contracts/std.py +1 -1
- orionis/services/standard/exceptions/std_value_exception.py +23 -0
- orionis/services/standard/std.py +2 -2
- orionis/services/system/contracts/imports.py +27 -7
- orionis/services/system/contracts/workers.py +8 -3
- orionis/services/system/imports.py +31 -12
- orionis/services/system/runtime_imports.py +33 -23
- orionis/services/system/workers.py +6 -8
- orionis/services/wrapper/dicts/dot_dict.py +82 -41
- orionis/unittesting.py +12 -12
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/METADATA +1 -1
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/RECORD +70 -66
- tests/foundation/config/app/{test_app.py → test_foundation_config_app.py} +1 -1
- tests/foundation/config/auth/{test_auth.py → test_foundation_config_auth.py} +1 -1
- tests/foundation/config/cache/{test_cache.py → test_foundation_config_cache.py} +1 -1
- tests/foundation/config/cache/{test_cache_file.py → test_foundation_config_cache_file.py} +1 -1
- tests/foundation/config/cache/{test_cache_stores.py → test_foundation_config_cache_stores.py} +1 -1
- tests/foundation/config/cors/{test_cors.py → test_foundation_config_cors.py} +1 -1
- tests/foundation/config/database/{test_database.py → test_foundation_config_database.py} +1 -1
- tests/foundation/config/database/{test_database_connections.py → test_foundation_config_database_connections.py} +1 -1
- tests/foundation/config/database/{test_database_mysql.py → test_foundation_config_database_mysql.py} +1 -1
- tests/foundation/config/database/{test_database_oracle.py → test_foundation_config_database_oracle.py} +1 -1
- tests/foundation/config/database/{test_database_pgsql.py → test_foundation_config_database_pgsql.py} +1 -1
- tests/foundation/config/database/{test_database_sqlite.py → test_foundation_config_database_sqlite.py} +1 -1
- tests/foundation/config/exceptions/{test_exceptions_integrity.py → test_foundation_config_exceptions.py} +1 -1
- tests/foundation/config/filesystems/{test_filesystems.py → test_foundation_config_filesystems.py} +1 -1
- tests/foundation/config/filesystems/{test_filesystems_aws.py → test_foundation_config_filesystems_aws.py} +1 -1
- tests/foundation/config/filesystems/{test_filesystems_disks.py → test_foundation_config_filesystems_disks.py} +1 -1
- tests/foundation/config/filesystems/{test_filesystems_local.py → test_foundation_config_filesystems_local.py} +1 -1
- tests/foundation/config/filesystems/{test_filesystems_public.py → test_foundation_config_filesystems_public.py} +1 -1
- tests/foundation/config/logging/{test_logging.py → test_foundation_config_logging.py} +1 -1
- tests/foundation/config/logging/{test_logging_channels.py → test_foundation_config_logging_channels.py} +1 -1
- tests/foundation/config/logging/{test_logging_chunked.py → test_foundation_config_logging_chunked.py} +1 -1
- tests/foundation/config/logging/{test_logging_daily.py → test_foundation_config_logging_daily.py} +1 -1
- tests/foundation/config/logging/{test_logging_hourly.py → test_foundation_config_logging_hourly.py} +1 -1
- tests/foundation/config/logging/{test_logging_monthly.py → test_foundation_config_logging_monthly.py} +1 -1
- tests/foundation/config/logging/{test_logging_stack.py → test_foundation_config_logging_stack.py} +1 -1
- tests/foundation/config/logging/{test_logging_weekly.py → test_foundation_config_logging_weekly.py} +1 -1
- tests/foundation/config/mail/{test_mail.py → test_foundation_config_mail.py} +1 -1
- tests/foundation/config/mail/{test_mail_file.py → test_foundation_config_mail_file.py} +1 -1
- tests/foundation/config/mail/{test_mail_mailers.py → test_foundation_config_mail_mailers.py} +1 -1
- tests/foundation/config/mail/{test_mail_smtp.py → test_foundation_config_mail_smtp.py} +1 -1
- tests/foundation/config/queue/{test_queue.py → test_foundation_config_queue.py} +1 -1
- tests/foundation/config/queue/{test_queue_brokers.py → test_foundation_config_queue_brokers.py} +1 -1
- tests/foundation/config/queue/{test_queue_database.py → test_foundation_config_queue_database.py} +1 -1
- tests/foundation/config/root/{test_root_paths.py → test_foundation_config_root_paths.py} +1 -1
- tests/foundation/config/session/{test_session.py → test_foundation_config_session.py} +1 -1
- tests/foundation/config/startup/{test_config_startup.py → test_foundation_config_startup.py} +14 -14
- tests/foundation/config/testing/{test_testing.py → test_foundation_config_testing.py} +1 -1
- tests/patterns/singleton/{test_singleton.py → test_patterns_singleton.py} +1 -1
- tests/services/asynchrony/{test_async_io.py → test_services_asynchrony_coroutine.py} +1 -1
- tests/services/environment/test_services_environment.py +93 -0
- tests/services/path/{test_resolver.py → test_services_resolver.py} +51 -12
- tests/services/standard/{test_std.py → test_services_std.py} +45 -22
- tests/services/system/__init__.py +0 -0
- tests/services/system/test_services_system_imports.py +101 -0
- tests/services/system/test_services_system_workers.py +89 -0
- tests/services/wrapper/{test_wrapper_doc_dict.py → test_services_wrapper_docdict.py} +28 -16
- tests/testing/test_testing_result.py +1 -1
- tests/testing/test_testing_unit.py +16 -16
- orionis/services/standard/exceptions/path_value_exceptions.py +0 -28
- tests/services/environment/test_env.py +0 -154
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/WHEEL +0 -0
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/top_level.txt +0 -0
- {orionis-0.287.0.dist-info → orionis-0.288.0.dist-info}/zip-safe +0 -0
tests/foundation/config/startup/{test_config_startup.py → test_foundation_config_startup.py}
RENAMED
@@ -1,9 +1,9 @@
|
|
1
1
|
from dataclasses import is_dataclass
|
2
2
|
from orionis.foundation.config.exceptions.integrity import OrionisIntegrityException
|
3
3
|
from orionis.foundation.config.startup import Configuration
|
4
|
-
from orionis.unittesting import TestCase,
|
4
|
+
from orionis.unittesting import TestCase, Mock
|
5
5
|
|
6
|
-
class
|
6
|
+
class TestFoundationConfigStartup(TestCase):
|
7
7
|
"""
|
8
8
|
Test suite for the Configuration dataclass.
|
9
9
|
|
@@ -98,18 +98,18 @@ class TestConfiguration(TestCase):
|
|
98
98
|
|
99
99
|
# Test each section with wrong type
|
100
100
|
sections = [
|
101
|
-
('paths',
|
102
|
-
('app',
|
103
|
-
('auth',
|
104
|
-
('cache',
|
105
|
-
('cors',
|
106
|
-
('database',
|
107
|
-
('filesystems',
|
108
|
-
('logging',
|
109
|
-
('mail',
|
110
|
-
('queue',
|
111
|
-
('session',
|
112
|
-
('testing',
|
101
|
+
('paths', Mock()),
|
102
|
+
('app', Mock()),
|
103
|
+
('auth', Mock()),
|
104
|
+
('cache', Mock()),
|
105
|
+
('cors', Mock()),
|
106
|
+
('database', Mock()),
|
107
|
+
('filesystems', Mock()),
|
108
|
+
('logging', Mock()),
|
109
|
+
('mail', Mock()),
|
110
|
+
('queue', Mock()),
|
111
|
+
('session', Mock()),
|
112
|
+
('testing', Mock())
|
113
113
|
]
|
114
114
|
|
115
115
|
for section_name, wrong_value in sections:
|
@@ -3,7 +3,7 @@ from orionis.foundation.config.exceptions.integrity import OrionisIntegrityExcep
|
|
3
3
|
from orionis.test.enums.test_mode import ExecutionMode
|
4
4
|
from orionis.unittesting import TestCase
|
5
5
|
|
6
|
-
class
|
6
|
+
class TestFoundationConfigTesting(TestCase):
|
7
7
|
"""
|
8
8
|
Test suite for the Testing configuration entity.
|
9
9
|
|
@@ -3,7 +3,7 @@ from orionis.services.asynchrony.coroutines import Coroutine
|
|
3
3
|
from orionis.services.asynchrony.exceptions.coroutine_exception import OrionisCoroutineException
|
4
4
|
from orionis.unittesting import TestCase
|
5
5
|
|
6
|
-
class
|
6
|
+
class TestServicesAsynchronyCoroutine(TestCase):
|
7
7
|
|
8
8
|
async def testExecuteWithActiveEventLoop(self):
|
9
9
|
"""
|
@@ -0,0 +1,93 @@
|
|
1
|
+
from orionis.services.environment.env import Env
|
2
|
+
from orionis.unittesting import TestCase
|
3
|
+
|
4
|
+
class TestServicesEnvironment(TestCase):
|
5
|
+
|
6
|
+
async def testSetAndGetConstants(self):
|
7
|
+
"""
|
8
|
+
Test storing and retrieving framework metadata constants using Env.set and Env.get.
|
9
|
+
|
10
|
+
Imports several metadata constants from the `orionis.metadata.framework` module, sets each constant
|
11
|
+
in the Env storage using `Env.set`, and verifies that the operation succeeds. Then retrieves each
|
12
|
+
constant using `Env.get` and asserts that the retrieved value matches the original constant.
|
13
|
+
|
14
|
+
Ensures
|
15
|
+
-------
|
16
|
+
- `Env.set` returns True for each constant.
|
17
|
+
- `Env.get` returns the correct value for each constant.
|
18
|
+
"""
|
19
|
+
from orionis.metadata.framework import (
|
20
|
+
NAME, VERSION, AUTHOR, AUTHOR_EMAIL, DESCRIPTION,
|
21
|
+
SKELETON, FRAMEWORK, DOCS, API, PYTHON_REQUIRES
|
22
|
+
)
|
23
|
+
constants = {
|
24
|
+
"NAME": NAME,
|
25
|
+
"VERSION": VERSION,
|
26
|
+
"AUTHOR": AUTHOR,
|
27
|
+
"AUTHOR_EMAIL": AUTHOR_EMAIL,
|
28
|
+
"DESCRIPTION": DESCRIPTION,
|
29
|
+
"SKELETON": SKELETON,
|
30
|
+
"FRAMEWORK": FRAMEWORK,
|
31
|
+
"DOCS": DOCS,
|
32
|
+
"API": API,
|
33
|
+
"PYTHON_REQUIRES": PYTHON_REQUIRES
|
34
|
+
}
|
35
|
+
for key, value in constants.items():
|
36
|
+
result = Env.set(key, value)
|
37
|
+
self.assertTrue(result)
|
38
|
+
for key, value in constants.items():
|
39
|
+
retrieved = Env.get(key)
|
40
|
+
self.assertEqual(retrieved, value)
|
41
|
+
|
42
|
+
async def testGetNonExistentKey(self):
|
43
|
+
"""
|
44
|
+
Test that Env.get returns None for a non-existent environment key.
|
45
|
+
|
46
|
+
Ensures
|
47
|
+
-------
|
48
|
+
- `Env.get` returns None when the key does not exist.
|
49
|
+
"""
|
50
|
+
self.assertIsNone(Env.get("NON_EXISTENT_KEY"))
|
51
|
+
|
52
|
+
async def testTypeHints(self):
|
53
|
+
"""
|
54
|
+
Test that Env.set and Env.get correctly handle and preserve Python type hints.
|
55
|
+
|
56
|
+
Sets environment variables with various data types (int, float, bool, str, list, dict, tuple, set)
|
57
|
+
using the `Env.set` method, specifying the type as a string. Then retrieves each variable using
|
58
|
+
`Env.get` and asserts that the returned value is of the expected Python type.
|
59
|
+
|
60
|
+
Ensures
|
61
|
+
-------
|
62
|
+
- The returned value from `Env.get` matches the expected Python type for each variable.
|
63
|
+
"""
|
64
|
+
|
65
|
+
# Set environment variables with type hints
|
66
|
+
Env.set("TEST_INT", 42, 'int')
|
67
|
+
Env.set("TEST_FLOAT", 3.14, 'float')
|
68
|
+
Env.set("TEST_BOOL", True, 'bool')
|
69
|
+
Env.set("TEST_STR", "Hello, World!", 'str')
|
70
|
+
Env.set("TEST_LIST", [1, 2, 3], 'list')
|
71
|
+
Env.set("TEST_DICT", {"key": "value"}, 'dict')
|
72
|
+
Env.set("TEST_TUPLE", (1,2,3), 'tuple')
|
73
|
+
Env.set("TEST_SET", {1, 2, 3}, 'set')
|
74
|
+
|
75
|
+
# Retrieve and check types
|
76
|
+
self.assertIsInstance(Env.get("TEST_INT"), int)
|
77
|
+
self.assertIsInstance(Env.get("TEST_FLOAT"), float)
|
78
|
+
self.assertIsInstance(Env.get("TEST_BOOL"), bool)
|
79
|
+
self.assertIsInstance(Env.get("TEST_STR"), str)
|
80
|
+
self.assertIsInstance(Env.get("TEST_LIST"), list)
|
81
|
+
self.assertIsInstance(Env.get("TEST_DICT"), dict)
|
82
|
+
self.assertIsInstance(Env.get("TEST_TUPLE"), tuple)
|
83
|
+
self.assertIsInstance(Env.get("TEST_SET"), set)
|
84
|
+
|
85
|
+
# Clean up environment variables after test
|
86
|
+
Env.unset("TEST_INT")
|
87
|
+
Env.unset("TEST_FLOAT")
|
88
|
+
Env.unset("TEST_BOOL")
|
89
|
+
Env.unset("TEST_STR")
|
90
|
+
Env.unset("TEST_LIST")
|
91
|
+
Env.unset("TEST_DICT")
|
92
|
+
Env.unset("TEST_TUPLE")
|
93
|
+
Env.unset("TEST_SET")
|
@@ -1,27 +1,42 @@
|
|
1
|
-
import tempfile
|
2
1
|
import os
|
2
|
+
import tempfile
|
3
3
|
from pathlib import Path
|
4
|
+
from orionis.services.paths.exceptions.not_found_exceptions import OrionisFileNotFoundException
|
4
5
|
from orionis.services.paths.resolver import Resolver
|
5
6
|
from orionis.unittesting import TestCase
|
6
7
|
|
7
|
-
class
|
8
|
-
"""
|
9
|
-
Unit tests for the Resolver class, which resolves file and directory paths relative to a base directory.
|
10
|
-
"""
|
8
|
+
class TestServicesResolver(TestCase):
|
11
9
|
|
12
|
-
async def
|
10
|
+
async def testFileNotFound(self):
|
13
11
|
"""
|
14
|
-
Test that resolving a non-existent file path raises
|
12
|
+
Test that resolving a non-existent file path raises OrionisFileNotFoundException.
|
13
|
+
|
14
|
+
Returns
|
15
|
+
-------
|
16
|
+
None
|
17
|
+
|
18
|
+
Raises
|
19
|
+
------
|
20
|
+
OrionisFileNotFoundException
|
21
|
+
If the file does not exist.
|
15
22
|
"""
|
16
23
|
with tempfile.TemporaryDirectory() as tmpdir:
|
17
24
|
resolver = Resolver(tmpdir)
|
18
25
|
non_existent = "does_not_exist.txt"
|
19
|
-
with self.assertRaises(
|
26
|
+
with self.assertRaises(OrionisFileNotFoundException):
|
20
27
|
resolver.relativePath(non_existent)
|
21
28
|
|
22
|
-
async def
|
29
|
+
async def testValidFilePath(self):
|
23
30
|
"""
|
24
31
|
Test that resolving a valid file path returns the correct absolute path.
|
32
|
+
|
33
|
+
Returns
|
34
|
+
-------
|
35
|
+
None
|
36
|
+
|
37
|
+
Asserts
|
38
|
+
-------
|
39
|
+
The resolved path ends with the file name and is absolute.
|
25
40
|
"""
|
26
41
|
with tempfile.TemporaryDirectory() as tmpdir:
|
27
42
|
# Create a temporary file inside the temp directory
|
@@ -34,9 +49,17 @@ class TestsResolver(TestCase):
|
|
34
49
|
# The resolved path should be absolute
|
35
50
|
self.assertTrue(os.path.isabs(resolved))
|
36
51
|
|
37
|
-
async def
|
52
|
+
async def testValidDirectoryPath(self):
|
38
53
|
"""
|
39
54
|
Test that resolving a valid directory path returns the correct absolute path.
|
55
|
+
|
56
|
+
Returns
|
57
|
+
-------
|
58
|
+
None
|
59
|
+
|
60
|
+
Asserts
|
61
|
+
-------
|
62
|
+
The resolved path ends with the directory name and is absolute.
|
40
63
|
"""
|
41
64
|
with tempfile.TemporaryDirectory() as tmpdir:
|
42
65
|
# Create a subdirectory inside the temp directory
|
@@ -47,9 +70,17 @@ class TestsResolver(TestCase):
|
|
47
70
|
self.assertTrue(resolved.endswith("subdir"))
|
48
71
|
self.assertTrue(os.path.isabs(resolved))
|
49
72
|
|
50
|
-
async def
|
73
|
+
async def testOtherBasePath(self):
|
51
74
|
"""
|
52
75
|
Test that providing a different base path to Resolver works as expected.
|
76
|
+
|
77
|
+
Returns
|
78
|
+
-------
|
79
|
+
None
|
80
|
+
|
81
|
+
Asserts
|
82
|
+
-------
|
83
|
+
The resolved path ends with the file name and is absolute.
|
53
84
|
"""
|
54
85
|
with tempfile.TemporaryDirectory() as tmpdir:
|
55
86
|
# Create a file in a subdirectory
|
@@ -62,9 +93,17 @@ class TestsResolver(TestCase):
|
|
62
93
|
self.assertTrue(resolved.endswith("file.txt"))
|
63
94
|
self.assertTrue(os.path.isabs(resolved))
|
64
95
|
|
65
|
-
async def
|
96
|
+
async def testEqualOutputString(self):
|
66
97
|
"""
|
67
98
|
Test that the string representation of the resolved path matches the output of toString().
|
99
|
+
|
100
|
+
Returns
|
101
|
+
-------
|
102
|
+
None
|
103
|
+
|
104
|
+
Asserts
|
105
|
+
-------
|
106
|
+
The string representation of the resolved path matches the output of toString().
|
68
107
|
"""
|
69
108
|
with tempfile.TemporaryDirectory() as tmpdir:
|
70
109
|
file_path = Path(tmpdir) / "file.txt"
|
@@ -1,14 +1,16 @@
|
|
1
|
-
|
1
|
+
from orionis.services.standard.exceptions.std_value_exception import OrionisStdValueException
|
2
2
|
from orionis.services.standard.std import StdClass
|
3
3
|
from orionis.unittesting import TestCase
|
4
4
|
|
5
|
-
class
|
5
|
+
class TestServicesStd(TestCase):
|
6
6
|
|
7
7
|
async def testInitializationAndAccess(self):
|
8
8
|
"""
|
9
9
|
Test the initialization of StdClass and access to its attributes.
|
10
10
|
|
11
|
-
|
11
|
+
Notes
|
12
|
+
-----
|
13
|
+
Verifies that an instance of StdClass can be created with the given
|
12
14
|
first name, last name, and age, and that these attributes can be accessed
|
13
15
|
correctly after initialization.
|
14
16
|
"""
|
@@ -24,7 +26,9 @@ class TestStdClass(TestCase):
|
|
24
26
|
"""
|
25
27
|
Test that the toDict method of StdClass returns a dictionary with the correct data.
|
26
28
|
|
27
|
-
|
29
|
+
Notes
|
30
|
+
-----
|
31
|
+
Creates an instance of StdClass with specific attributes and verifies
|
28
32
|
that calling toDict() returns a dictionary containing those attributes and their values.
|
29
33
|
"""
|
30
34
|
obj = StdClass(a=1, b=2)
|
@@ -35,7 +39,9 @@ class TestStdClass(TestCase):
|
|
35
39
|
"""
|
36
40
|
Test that the `update` method of `StdClass` correctly sets multiple attributes.
|
37
41
|
|
38
|
-
|
42
|
+
Notes
|
43
|
+
-----
|
44
|
+
Creates an instance of `StdClass`, updates its attributes using the `update` method,
|
39
45
|
and asserts that the attributes `foo` and `number` are set to the expected values.
|
40
46
|
"""
|
41
47
|
obj = StdClass()
|
@@ -47,27 +53,36 @@ class TestStdClass(TestCase):
|
|
47
53
|
"""
|
48
54
|
Test that updating a reserved attribute (such as '__init__') on a StdClass instance
|
49
55
|
raises a ValueError exception.
|
56
|
+
|
57
|
+
Notes
|
58
|
+
-----
|
59
|
+
Ensures that updating a reserved attribute raises an OrionisStdValueException.
|
50
60
|
"""
|
51
61
|
obj = StdClass()
|
52
|
-
with self.assertRaises(
|
62
|
+
with self.assertRaises(OrionisStdValueException):
|
53
63
|
obj.update(__init__='bad')
|
54
64
|
|
55
65
|
async def testUpdateConflictingAttributeRaisesError(self):
|
56
66
|
"""
|
57
67
|
Test that updating an object with a conflicting attribute name ('toDict') raises a ValueError.
|
58
68
|
|
59
|
-
|
69
|
+
Notes
|
70
|
+
-----
|
71
|
+
Ensures that attempting to update the StdClass instance with a keyword argument
|
60
72
|
that conflicts with an existing method or reserved attribute ('toDict') correctly triggers
|
61
|
-
|
73
|
+
an OrionisStdValueException, enforcing attribute safety.
|
62
74
|
"""
|
63
75
|
obj = StdClass()
|
64
|
-
with self.assertRaises(
|
76
|
+
with self.assertRaises(OrionisStdValueException):
|
65
77
|
obj.update(toDict='oops')
|
66
78
|
|
67
79
|
async def testRemoveExistingAttributes(self):
|
68
80
|
"""
|
69
|
-
|
70
|
-
|
81
|
+
Test that the `remove` method of `StdClass` successfully removes an existing attribute.
|
82
|
+
|
83
|
+
Notes
|
84
|
+
-----
|
85
|
+
Removes attribute 'x' from the object and checks that 'y' remains.
|
71
86
|
"""
|
72
87
|
obj = StdClass(x=1, y=2)
|
73
88
|
obj.remove('x')
|
@@ -78,7 +93,9 @@ class TestStdClass(TestCase):
|
|
78
93
|
"""
|
79
94
|
Test that attempting to remove a non-existing attribute from a StdClass instance raises an AttributeError.
|
80
95
|
|
81
|
-
|
96
|
+
Notes
|
97
|
+
-----
|
98
|
+
Verifies that the `remove` method of `StdClass` raises an AttributeError
|
82
99
|
when called with the name of an attribute that does not exist on the object.
|
83
100
|
"""
|
84
101
|
obj = StdClass()
|
@@ -89,20 +106,23 @@ class TestStdClass(TestCase):
|
|
89
106
|
"""
|
90
107
|
Test that StdClass.from_dict creates an instance equivalent to the original data.
|
91
108
|
|
92
|
-
|
109
|
+
Notes
|
110
|
+
-----
|
111
|
+
Verifies that when a dictionary is passed to StdClass.from_dict,
|
93
112
|
the resulting object's toDict() method returns a dictionary equal to the original input.
|
94
113
|
"""
|
95
114
|
data = {'a': 10, 'b': 20}
|
96
|
-
obj = StdClass.
|
115
|
+
obj = StdClass.fromDict(data)
|
97
116
|
self.assertEqual(obj.toDict(), data)
|
98
117
|
|
99
118
|
async def testReprAndStr(self):
|
100
119
|
"""
|
101
120
|
Test that the __repr__ and __str__ methods of StdClass include the class name and the value of 'x' respectively.
|
102
121
|
|
103
|
-
|
104
|
-
|
105
|
-
-
|
122
|
+
Notes
|
123
|
+
-----
|
124
|
+
- Checks that repr(obj) contains the class name 'StdClass'.
|
125
|
+
- Checks that str(obj) contains the key-value pair "'x': 5".
|
106
126
|
"""
|
107
127
|
obj = StdClass(x=5)
|
108
128
|
self.assertIn("StdClass", repr(obj))
|
@@ -110,15 +130,18 @@ class TestStdClass(TestCase):
|
|
110
130
|
|
111
131
|
async def testEquality(self):
|
112
132
|
"""
|
113
|
-
|
133
|
+
Test the equality and inequality operations for StdClass instances.
|
114
134
|
|
115
|
-
|
135
|
+
Notes
|
136
|
+
-----
|
137
|
+
Creates three instances of StdClass:
|
116
138
|
- 'a' and 'b' with identical attributes (x=1, y=2), which should be considered equal.
|
117
139
|
- 'c' with a different attribute (x=3), which should not be equal to 'a'.
|
118
140
|
|
119
|
-
|
120
|
-
|
121
|
-
-
|
141
|
+
Asserts
|
142
|
+
-------
|
143
|
+
- 'a' and 'b' are equal.
|
144
|
+
- 'a' and 'c' are not equal.
|
122
145
|
"""
|
123
146
|
a = StdClass(x=1, y=2)
|
124
147
|
b = StdClass(x=1, y=2)
|
File without changes
|
@@ -0,0 +1,101 @@
|
|
1
|
+
from orionis.services.system.imports import Imports
|
2
|
+
from orionis.unittesting import TestCase
|
3
|
+
import sys
|
4
|
+
import types
|
5
|
+
|
6
|
+
class TestServicesSystemImports(TestCase):
|
7
|
+
|
8
|
+
def testImportModule(self) -> None:
|
9
|
+
"""
|
10
|
+
Test that Imports can be instantiated and collected.
|
11
|
+
|
12
|
+
Returns
|
13
|
+
-------
|
14
|
+
None
|
15
|
+
"""
|
16
|
+
imports = Imports()
|
17
|
+
imports.collect()
|
18
|
+
self.assertIsInstance(imports, Imports)
|
19
|
+
|
20
|
+
def testCollectPopulatesImports(self):
|
21
|
+
"""
|
22
|
+
Test that collect() populates the imports list with modules.
|
23
|
+
|
24
|
+
Returns
|
25
|
+
-------
|
26
|
+
None
|
27
|
+
"""
|
28
|
+
dummy_mod = types.ModuleType("dummy_mod")
|
29
|
+
dummy_mod.__file__ = __file__
|
30
|
+
def dummy_func(): pass
|
31
|
+
dummy_mod.dummy_func = dummy_func
|
32
|
+
dummy_func.__module__ = "dummy_mod"
|
33
|
+
sys.modules["dummy_mod"] = dummy_mod
|
34
|
+
|
35
|
+
imports = Imports()
|
36
|
+
imports.collect()
|
37
|
+
found = any(imp["name"] == "dummy_mod" for imp in imports.imports)
|
38
|
+
self.assertTrue(found)
|
39
|
+
|
40
|
+
# Cleanup
|
41
|
+
del sys.modules["dummy_mod"]
|
42
|
+
|
43
|
+
def testCollectExcludesStdlibAndSpecialModules(self):
|
44
|
+
"""
|
45
|
+
Test that collect() excludes standard library and special modules.
|
46
|
+
|
47
|
+
Returns
|
48
|
+
-------
|
49
|
+
None
|
50
|
+
"""
|
51
|
+
imports = Imports()
|
52
|
+
imports.collect()
|
53
|
+
names = [imp["name"] for imp in imports.imports]
|
54
|
+
self.assertNotIn("__main__", names)
|
55
|
+
self.assertFalse(any(n.startswith("_distutils") for n in names))
|
56
|
+
|
57
|
+
def testClearEmptiesImports(self):
|
58
|
+
"""
|
59
|
+
Test that clear() empties the imports list.
|
60
|
+
|
61
|
+
Returns
|
62
|
+
-------
|
63
|
+
None
|
64
|
+
"""
|
65
|
+
imports = Imports()
|
66
|
+
imports.imports = [{"name": "test", "file": "test.py", "symbols": ["a"]}]
|
67
|
+
imports.clear()
|
68
|
+
self.assertEqual(imports.imports, [])
|
69
|
+
|
70
|
+
def testCollectHandlesModulesWithoutFile(self):
|
71
|
+
"""
|
72
|
+
Test that collect() handles modules without a __file__ attribute.
|
73
|
+
|
74
|
+
Returns
|
75
|
+
-------
|
76
|
+
None
|
77
|
+
"""
|
78
|
+
mod = types.ModuleType("mod_without_file")
|
79
|
+
sys.modules["mod_without_file"] = mod
|
80
|
+
imports = Imports()
|
81
|
+
imports.collect()
|
82
|
+
names = [imp["name"] for imp in imports.imports]
|
83
|
+
self.assertNotIn("mod_without_file", names)
|
84
|
+
del sys.modules["mod_without_file"]
|
85
|
+
|
86
|
+
def testCollectSkipsBinaryExtensions(self):
|
87
|
+
"""
|
88
|
+
Test that collect() skips binary extension modules.
|
89
|
+
|
90
|
+
Returns
|
91
|
+
-------
|
92
|
+
None
|
93
|
+
"""
|
94
|
+
mod = types.ModuleType("bin_mod")
|
95
|
+
mod.__file__ = "bin_mod.pyd"
|
96
|
+
sys.modules["bin_mod"] = mod
|
97
|
+
imports = Imports()
|
98
|
+
imports.collect()
|
99
|
+
names = [imp["name"] for imp in imports.imports]
|
100
|
+
self.assertNotIn("bin_mod", names)
|
101
|
+
del sys.modules["bin_mod"]
|
@@ -0,0 +1,89 @@
|
|
1
|
+
from orionis.services.system.workers import Workers
|
2
|
+
from orionis.unittesting import TestCase, patch
|
3
|
+
|
4
|
+
class TestServicesSystemWorkers(TestCase):
|
5
|
+
"""
|
6
|
+
Unit tests for the Workers class.
|
7
|
+
|
8
|
+
This test suite verifies the correct calculation of the number of workers
|
9
|
+
based on available CPU and RAM resources.
|
10
|
+
|
11
|
+
Methods
|
12
|
+
-------
|
13
|
+
testCalculateCpuLimited()
|
14
|
+
Test when the number of workers is limited by CPU count.
|
15
|
+
testCalculateRamLimited()
|
16
|
+
Test when the number of workers is limited by available RAM.
|
17
|
+
testCalculateExactFit()
|
18
|
+
Test when CPU and RAM allow for the same number of workers.
|
19
|
+
testCalculateLowRam()
|
20
|
+
Test when low RAM restricts the number of workers to less than CPU count.
|
21
|
+
"""
|
22
|
+
|
23
|
+
@patch('multiprocessing.cpu_count', return_value=8)
|
24
|
+
@patch('psutil.virtual_memory')
|
25
|
+
def testCalculateCpuLimited(self, mockVm, mockCpuCount):
|
26
|
+
"""
|
27
|
+
Test when the number of workers is limited by CPU count.
|
28
|
+
|
29
|
+
Simulates 8 CPUs and 16 GB RAM, with ram_per_worker=1.
|
30
|
+
RAM allows 16 workers, but CPU only allows 8.
|
31
|
+
|
32
|
+
Returns
|
33
|
+
-------
|
34
|
+
None
|
35
|
+
"""
|
36
|
+
mockVm.return_value.total = 16 * 1024 ** 3
|
37
|
+
workers = Workers(ram_per_worker=1)
|
38
|
+
self.assertEqual(workers.calculate(), 8)
|
39
|
+
|
40
|
+
@patch('multiprocessing.cpu_count', return_value=32)
|
41
|
+
@patch('psutil.virtual_memory')
|
42
|
+
def testCalculateRamLimited(self, mockVm, mockCpuCount):
|
43
|
+
"""
|
44
|
+
Test when the number of workers is limited by available RAM.
|
45
|
+
|
46
|
+
Simulates 32 CPUs and 4 GB RAM, with ram_per_worker=1.
|
47
|
+
RAM allows only 4 workers.
|
48
|
+
|
49
|
+
Returns
|
50
|
+
-------
|
51
|
+
None
|
52
|
+
"""
|
53
|
+
mockVm.return_value.total = 4 * 1024 ** 3
|
54
|
+
workers = Workers(ram_per_worker=1)
|
55
|
+
self.assertEqual(workers.calculate(), 4)
|
56
|
+
|
57
|
+
@patch('multiprocessing.cpu_count', return_value=4)
|
58
|
+
@patch('psutil.virtual_memory')
|
59
|
+
def testCalculateExactFit(self, mockVm, mockCpuCount):
|
60
|
+
"""
|
61
|
+
Test when CPU and RAM allow for the same number of workers.
|
62
|
+
|
63
|
+
Simulates 4 CPUs and 2 GB RAM, with ram_per_worker=0.5.
|
64
|
+
RAM allows 4 workers.
|
65
|
+
|
66
|
+
Returns
|
67
|
+
-------
|
68
|
+
None
|
69
|
+
"""
|
70
|
+
mockVm.return_value.total = 2 * 1024 ** 3
|
71
|
+
workers = Workers(ram_per_worker=0.5)
|
72
|
+
self.assertEqual(workers.calculate(), 4)
|
73
|
+
|
74
|
+
@patch('multiprocessing.cpu_count', return_value=2)
|
75
|
+
@patch('psutil.virtual_memory')
|
76
|
+
def testCalculateLowRam(self, mockVm, mockCpuCount):
|
77
|
+
"""
|
78
|
+
Test when low RAM restricts the number of workers to less than CPU count.
|
79
|
+
|
80
|
+
Simulates 2 CPUs and 0.7 GB RAM, with ram_per_worker=0.5.
|
81
|
+
RAM allows only 1 worker.
|
82
|
+
|
83
|
+
Returns
|
84
|
+
-------
|
85
|
+
None
|
86
|
+
"""
|
87
|
+
mockVm.return_value.total = 0.7 * 1024 ** 3
|
88
|
+
workers = Workers(ram_per_worker=0.5)
|
89
|
+
self.assertEqual(workers.calculate(), 1)
|