orionis 0.286.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/env.py +45 -50
- orionis/services/environment/contracts/types.py +70 -0
- orionis/services/environment/dot_env.py +204 -182
- orionis/services/environment/env.py +68 -85
- orionis/services/{standard/exceptions/path_value_exceptions.py → environment/exceptions/environment_value_error.py} +2 -12
- orionis/services/environment/exceptions/environment_value_exception.py +23 -0
- orionis/services/environment/types.py +578 -0
- 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/test/logs/history.py +3 -5
- orionis/unittesting.py +12 -12
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/METADATA +1 -1
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/RECORD +76 -70
- tests/example/test_example.py +5 -2
- tests/foundation/config/app/{test_app.py → test_foundation_config_app.py} +14 -4
- tests/foundation/config/auth/{test_auth.py → test_foundation_config_auth.py} +10 -5
- tests/foundation/config/cache/{test_cache.py → test_foundation_config_cache.py} +61 -16
- tests/foundation/config/cache/test_foundation_config_cache_file.py +126 -0
- tests/foundation/config/cache/test_foundation_config_cache_stores.py +148 -0
- tests/foundation/config/cors/test_foundation_config_cors.py +190 -0
- tests/foundation/config/database/{test_database.py → test_foundation_config_database.py} +39 -15
- tests/foundation/config/database/{test_database_connections.py → test_foundation_config_database_connections.py} +80 -6
- tests/foundation/config/database/{test_database_mysql.py → test_foundation_config_database_mysql.py} +139 -16
- tests/foundation/config/database/{test_database_oracle.py → test_foundation_config_database_oracle.py} +111 -27
- tests/foundation/config/database/{test_database_pgsql.py → test_foundation_config_database_pgsql.py} +97 -27
- tests/foundation/config/database/{test_database_sqlite.py → test_foundation_config_database_sqlite.py} +57 -3
- tests/foundation/config/exceptions/{test_exceptions_integrity.py → test_foundation_config_exceptions.py} +45 -11
- tests/foundation/config/filesystems/{test_filesystems.py → test_foundation_config_filesystems.py} +65 -15
- tests/foundation/config/filesystems/{test_filesystems_aws.py → test_foundation_config_filesystems_aws.py} +46 -8
- tests/foundation/config/filesystems/{test_filesystems_disks.py → test_foundation_config_filesystems_disks.py} +79 -9
- tests/foundation/config/filesystems/{test_filesystems_local.py → test_foundation_config_filesystems_local.py} +67 -19
- tests/foundation/config/filesystems/{test_filesystems_public.py → test_foundation_config_filesystems_public.py} +38 -1
- tests/foundation/config/logging/test_foundation_config_logging.py +112 -0
- tests/foundation/config/logging/{test_logging_channels.py → test_foundation_config_logging_channels.py} +80 -3
- tests/foundation/config/logging/{test_logging_chunked.py → test_foundation_config_logging_chunked.py} +86 -13
- tests/foundation/config/logging/{test_logging_daily.py → test_foundation_config_logging_daily.py} +80 -13
- tests/foundation/config/logging/{test_logging_hourly.py → test_foundation_config_logging_hourly.py} +69 -3
- tests/foundation/config/logging/{test_logging_monthly.py → test_foundation_config_logging_monthly.py} +49 -3
- tests/foundation/config/logging/{test_logging_stack.py → test_foundation_config_logging_stack.py} +50 -15
- tests/foundation/config/logging/{test_logging_weekly.py → test_foundation_config_logging_weekly.py} +93 -3
- tests/foundation/config/mail/test_foundation_config_mail.py +145 -0
- tests/foundation/config/mail/{test_mail_file.py → test_foundation_config_mail_file.py} +41 -5
- tests/foundation/config/mail/test_foundation_config_mail_mailers.py +106 -0
- tests/foundation/config/mail/{test_mail_smtp.py → test_foundation_config_mail_smtp.py} +59 -15
- tests/foundation/config/queue/test_foundation_config_queue.py +111 -0
- tests/foundation/config/queue/{test_queue_brokers.py → test_foundation_config_queue_brokers.py} +28 -11
- tests/foundation/config/queue/{test_queue_database.py → test_foundation_config_queue_database.py} +54 -16
- tests/foundation/config/root/{test_root_paths.py → test_foundation_config_root_paths.py} +70 -3
- tests/foundation/config/session/{test_session.py → test_foundation_config_session.py} +31 -2
- tests/foundation/config/startup/{test_config_startup.py → test_foundation_config_startup.py} +91 -21
- tests/foundation/config/testing/{test_testing.py → test_foundation_config_testing.py} +69 -1
- tests/patterns/singleton/test_patterns_singleton.py +27 -0
- 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 +57 -20
- tests/testing/test_testing_unit.py +110 -41
- orionis/services/environment/exceptions/value_exception.py +0 -27
- tests/foundation/config/cache/test_cache_file.py +0 -78
- tests/foundation/config/cache/test_cache_stores.py +0 -88
- tests/foundation/config/cors/test_cors.py +0 -121
- tests/foundation/config/logging/test_logging.py +0 -48
- tests/foundation/config/mail/test_mail.py +0 -73
- tests/foundation/config/mail/test_mail_mailers.py +0 -58
- tests/foundation/config/queue/test_queue.py +0 -58
- tests/patterns/singleton/test_singleton.py +0 -18
- tests/services/environment/test_env.py +0 -155
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/WHEEL +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/top_level.txt +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/zip-safe +0 -0
@@ -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)
|
@@ -1,16 +1,23 @@
|
|
1
1
|
from orionis.services.wrapper.dicts.dot_dict import DotDict
|
2
2
|
from orionis.unittesting import TestCase
|
3
3
|
|
4
|
-
class
|
4
|
+
class TestServicesWrapperDocDict(TestCase):
|
5
5
|
"""
|
6
6
|
Test cases for the DotDict class which provides dictionary with dot notation access.
|
7
|
+
|
8
|
+
Notes
|
9
|
+
-----
|
10
|
+
These tests cover dot notation access, assignment, deletion, and utility methods
|
11
|
+
for the DotDict class, ensuring correct behavior and compatibility with nested
|
12
|
+
dictionaries.
|
7
13
|
"""
|
8
14
|
|
9
15
|
async def testDotNotationAccess(self):
|
10
16
|
"""
|
11
|
-
Test
|
17
|
+
Test dot notation access for dictionary values.
|
18
|
+
|
12
19
|
Verifies that both existing and non-existing keys can be accessed via dot notation,
|
13
|
-
with None returned for missing keys.
|
20
|
+
with `None` returned for missing keys.
|
14
21
|
"""
|
15
22
|
dd = DotDict({'key1': 'value1', 'nested': {'inner': 42}})
|
16
23
|
self.assertEqual(dd.key1, 'value1')
|
@@ -19,7 +26,8 @@ class TestDotDict(TestCase):
|
|
19
26
|
|
20
27
|
async def testDotNotationAssignment(self):
|
21
28
|
"""
|
22
|
-
Test
|
29
|
+
Test assignment of dictionary values using dot notation.
|
30
|
+
|
23
31
|
Verifies that new keys can be added and existing keys can be updated using dot notation,
|
24
32
|
with automatic conversion of nested dictionaries to DotDict.
|
25
33
|
"""
|
@@ -33,8 +41,9 @@ class TestDotDict(TestCase):
|
|
33
41
|
|
34
42
|
async def testDotNotationDeletion(self):
|
35
43
|
"""
|
36
|
-
Test
|
37
|
-
|
44
|
+
Test deletion of dictionary keys using dot notation.
|
45
|
+
|
46
|
+
Verifies that existing keys can be deleted and an AttributeError is raised
|
38
47
|
when trying to delete non-existent keys.
|
39
48
|
"""
|
40
49
|
dd = DotDict({'key1': 'value1', 'key2': 'value2'})
|
@@ -46,8 +55,9 @@ class TestDotDict(TestCase):
|
|
46
55
|
|
47
56
|
async def testGetMethod(self):
|
48
57
|
"""
|
49
|
-
Test
|
50
|
-
|
58
|
+
Test the `get` method with automatic DotDict conversion.
|
59
|
+
|
60
|
+
Verifies that the `get` method returns the correct value or default,
|
51
61
|
and converts nested dictionaries to DotDict instances.
|
52
62
|
"""
|
53
63
|
dd = DotDict({'key1': 'value1', 'nested': {'inner': 42}})
|
@@ -59,7 +69,8 @@ class TestDotDict(TestCase):
|
|
59
69
|
|
60
70
|
async def testExportMethod(self):
|
61
71
|
"""
|
62
|
-
Test
|
72
|
+
Test the `export` method for recursive conversion to regular dict.
|
73
|
+
|
63
74
|
Verifies that all nested DotDict instances are converted back to regular dicts.
|
64
75
|
"""
|
65
76
|
dd = DotDict({
|
@@ -78,7 +89,8 @@ class TestDotDict(TestCase):
|
|
78
89
|
|
79
90
|
async def testCopyMethod(self):
|
80
91
|
"""
|
81
|
-
Test
|
92
|
+
Test the `copy` method for deep copy with DotDict conversion.
|
93
|
+
|
82
94
|
Verifies that the copy is independent of the original and maintains DotDict structure.
|
83
95
|
"""
|
84
96
|
original = DotDict({
|
@@ -98,7 +110,8 @@ class TestDotDict(TestCase):
|
|
98
110
|
|
99
111
|
async def testNestedDictConversion(self):
|
100
112
|
"""
|
101
|
-
Test
|
113
|
+
Test automatic conversion of nested dictionaries to DotDict.
|
114
|
+
|
102
115
|
Verifies that nested dicts are converted both during initialization and assignment.
|
103
116
|
"""
|
104
117
|
dd = DotDict({
|
@@ -120,10 +133,9 @@ class TestDotDict(TestCase):
|
|
120
133
|
|
121
134
|
async def testReprMethod(self):
|
122
135
|
"""
|
123
|
-
Test
|
124
|
-
|
136
|
+
Test the string representation of DotDict.
|
137
|
+
|
138
|
+
Verifies that the `__repr__` method includes the DotDict prefix.
|
125
139
|
"""
|
126
140
|
dd = DotDict({'key': 'value'})
|
127
|
-
self.
|
128
|
-
self.assertTrue(repr(dd).endswith('})'))
|
129
|
-
self.assertIn("'key': 'value'", repr(dd))
|
141
|
+
self.assertEqual(repr(dd), "{'key': 'value'}")
|
@@ -1,16 +1,25 @@
|
|
1
|
-
|
2
1
|
from orionis.unittesting import TestCase, TestResult, TestStatus
|
3
2
|
|
4
|
-
class
|
5
|
-
"""
|
6
|
-
Test cases for the TestResult dataclass.
|
7
|
-
"""
|
3
|
+
class TestTestingResult(TestCase):
|
8
4
|
|
9
|
-
async def testDefaultValues(self):
|
5
|
+
async def testDefaultValues(self) -> None:
|
10
6
|
"""
|
11
|
-
|
7
|
+
Ensures that when optional fields are not provided during initialization of a TestResult
|
8
|
+
instance, they are set to None.
|
9
|
+
|
10
|
+
Notes
|
11
|
+
-----
|
12
|
+
This test verifies the default behavior of the following optional fields:
|
13
|
+
- error_message
|
14
|
+
- traceback
|
15
|
+
- class_name
|
16
|
+
- method
|
17
|
+
- module
|
18
|
+
- file_path
|
12
19
|
|
13
|
-
|
20
|
+
Assertions
|
21
|
+
----------
|
22
|
+
Each optional field is checked to confirm it is None after initialization.
|
14
23
|
"""
|
15
24
|
result = TestResult(
|
16
25
|
id=1,
|
@@ -25,11 +34,16 @@ class TestTestResult(TestCase):
|
|
25
34
|
self.assertIsNone(result.module)
|
26
35
|
self.assertIsNone(result.file_path)
|
27
36
|
|
28
|
-
async def testRequiredFields(self):
|
37
|
+
async def testRequiredFields(self) -> None:
|
29
38
|
"""
|
30
|
-
Test that TestResult
|
39
|
+
Test that TestResult enforces the presence of all required (non-optional) fields during initialization.
|
40
|
+
This test verifies that omitting any required field when creating a TestResult instance raises a TypeError.
|
31
41
|
|
32
|
-
|
42
|
+
Notes
|
43
|
+
-----
|
44
|
+
- Attempts to instantiate TestResult with no arguments.
|
45
|
+
- Attempts to instantiate TestResult missing the 'id' field.
|
46
|
+
- Expects a TypeError to be raised in both cases.
|
33
47
|
"""
|
34
48
|
with self.assertRaises(TypeError):
|
35
49
|
TestResult() # Missing all required fields
|
@@ -42,11 +56,21 @@ class TestTestResult(TestCase):
|
|
42
56
|
execution_time=0.5
|
43
57
|
)
|
44
58
|
|
45
|
-
async def testImmutable(self):
|
59
|
+
async def testImmutable(self) -> None:
|
46
60
|
"""
|
47
|
-
Test
|
61
|
+
Test the immutability of TestResult instances.
|
62
|
+
This test ensures that TestResult, implemented as a frozen dataclass, does not allow
|
63
|
+
modification of its attributes after instantiation.
|
64
|
+
|
65
|
+
Parameters
|
66
|
+
----------
|
67
|
+
self : TestCase
|
68
|
+
The test case instance.
|
48
69
|
|
49
|
-
|
70
|
+
Raises
|
71
|
+
------
|
72
|
+
FrozenInstanceError
|
73
|
+
If an attempt is made to modify an attribute of a frozen TestResult instance.
|
50
74
|
"""
|
51
75
|
result = TestResult(
|
52
76
|
id=1,
|
@@ -57,11 +81,18 @@ class TestTestResult(TestCase):
|
|
57
81
|
with self.assertRaises(Exception):
|
58
82
|
result.name = "Modified Name"
|
59
83
|
|
60
|
-
async def testStatusValues(self):
|
84
|
+
async def testStatusValues(self) -> None:
|
61
85
|
"""
|
62
|
-
|
86
|
+
Parameters
|
87
|
+
----------
|
88
|
+
self : TestCase
|
89
|
+
The test case instance.
|
63
90
|
|
64
|
-
|
91
|
+
Notes
|
92
|
+
-----
|
93
|
+
This test iterates over all possible values of the `TestStatus` enum and verifies
|
94
|
+
that each value can be assigned to the `status` field of a `TestResult` instance.
|
95
|
+
It asserts that the assigned status matches the expected value.
|
65
96
|
"""
|
66
97
|
for status in TestStatus:
|
67
98
|
result = TestResult(
|
@@ -72,11 +103,17 @@ class TestTestResult(TestCase):
|
|
72
103
|
)
|
73
104
|
self.assertEqual(result.status, status)
|
74
105
|
|
75
|
-
async def testErrorFields(self):
|
106
|
+
async def testErrorFields(self) -> None:
|
76
107
|
"""
|
77
|
-
|
108
|
+
Parameters
|
109
|
+
----------
|
110
|
+
self : TestCase
|
111
|
+
The test case instance.
|
78
112
|
|
79
|
-
|
113
|
+
Notes
|
114
|
+
-----
|
115
|
+
Verifies that the `error_message` and `traceback` fields are correctly stored in the `TestResult`
|
116
|
+
object when provided during initialization.
|
80
117
|
"""
|
81
118
|
error_msg = "Test failed"
|
82
119
|
traceback = "Traceback info"
|