karrio-server-core 2025.5rc31__py3-none-any.whl → 2026.1.1__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.
- karrio/server/core/authentication.py +38 -20
- karrio/server/core/config.py +31 -0
- karrio/server/core/datatypes.py +30 -4
- karrio/server/core/dataunits.py +26 -7
- karrio/server/core/exceptions.py +287 -17
- karrio/server/core/filters.py +14 -0
- karrio/server/core/gateway.py +284 -11
- karrio/server/core/logging.py +403 -0
- karrio/server/core/middleware.py +104 -2
- karrio/server/core/models/base.py +34 -1
- karrio/server/core/oauth_validators.py +2 -3
- karrio/server/core/permissions.py +1 -2
- karrio/server/core/serializers.py +154 -7
- karrio/server/core/signals.py +22 -28
- karrio/server/core/telemetry.py +573 -0
- karrio/server/core/tests/__init__.py +27 -0
- karrio/server/core/{tests.py → tests/base.py} +6 -7
- karrio/server/core/tests/test_exception_level.py +159 -0
- karrio/server/core/tests/test_resource_token.py +593 -0
- karrio/server/core/utils.py +688 -38
- karrio/server/core/validators.py +144 -222
- karrio/server/core/views/oauth.py +13 -12
- karrio/server/core/views/references.py +2 -2
- karrio/server/iam/apps.py +1 -4
- karrio/server/iam/migrations/0002_setup_carrier_permission_groups.py +103 -0
- karrio/server/iam/migrations/0003_remove_permission_groups.py +91 -0
- karrio/server/iam/permissions.py +7 -134
- karrio/server/iam/serializers.py +9 -3
- karrio/server/iam/signals.py +2 -4
- karrio/server/providers/admin.py +1 -1
- karrio/server/providers/migrations/0085_populate_dhl_parcel_de_oauth_credentials.py +82 -0
- karrio/server/providers/migrations/0086_rename_dhl_parcel_de_customer_number_to_billing_number.py +71 -0
- karrio/server/providers/migrations/0087_alter_carrier_capabilities.py +38 -0
- karrio/server/providers/migrations/0088_servicelevel_surcharges.py +24 -0
- karrio/server/providers/migrations/0089_servicelevel_cost_max_volume.py +31 -0
- karrio/server/providers/migrations/0090_ratesheet_surcharges_servicelevel_zone_surcharge_ids.py +47 -0
- karrio/server/providers/migrations/0091_migrate_legacy_zones_surcharges.py +154 -0
- karrio/server/providers/models/carrier.py +101 -29
- karrio/server/providers/models/service.py +182 -125
- karrio/server/providers/models/sheet.py +342 -198
- karrio/server/providers/serializers/base.py +263 -2
- karrio/server/providers/signals.py +2 -4
- karrio/server/providers/templates/providers/oauth_callback.html +105 -0
- karrio/server/providers/tests/__init__.py +5 -0
- karrio/server/providers/tests/test_connections.py +895 -0
- karrio/server/providers/views/carriers.py +1 -3
- karrio/server/providers/views/connections.py +322 -2
- karrio/server/serializers/abstract.py +112 -21
- karrio/server/tracing/utils.py +5 -8
- karrio/server/user/models.py +36 -34
- karrio/server/user/serializers.py +1 -0
- {karrio_server_core-2025.5rc31.dist-info → karrio_server_core-2026.1.1.dist-info}/METADATA +2 -2
- {karrio_server_core-2025.5rc31.dist-info → karrio_server_core-2026.1.1.dist-info}/RECORD +55 -38
- karrio/server/providers/tests.py +0 -3
- {karrio_server_core-2025.5rc31.dist-info → karrio_server_core-2026.1.1.dist-info}/WHEEL +0 -0
- {karrio_server_core-2025.5rc31.dist-info → karrio_server_core-2026.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Tests for exception handler level classification.
|
|
2
|
+
|
|
3
|
+
These tests verify the level classification logic in isolation,
|
|
4
|
+
without requiring the full Django setup.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest
|
|
8
|
+
from unittest.mock import MagicMock
|
|
9
|
+
from rest_framework import status
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestGetDefaultLevel(unittest.TestCase):
|
|
13
|
+
"""Tests for get_default_level function."""
|
|
14
|
+
|
|
15
|
+
def setUp(self):
|
|
16
|
+
# Import here to avoid Django setup issues
|
|
17
|
+
from karrio.server.core.exceptions import get_default_level, ERROR_LEVEL_DEFAULTS
|
|
18
|
+
self.get_default_level = get_default_level
|
|
19
|
+
self.ERROR_LEVEL_DEFAULTS = ERROR_LEVEL_DEFAULTS
|
|
20
|
+
|
|
21
|
+
def test_returns_exception_level_when_set(self):
|
|
22
|
+
exc = MagicMock()
|
|
23
|
+
exc.level = "warning"
|
|
24
|
+
result = self.get_default_level(400, exc)
|
|
25
|
+
self.assertEqual(result, "warning")
|
|
26
|
+
|
|
27
|
+
def test_returns_status_code_mapping_for_400(self):
|
|
28
|
+
result = self.get_default_level(400)
|
|
29
|
+
self.assertEqual(result, "error")
|
|
30
|
+
|
|
31
|
+
def test_returns_status_code_mapping_for_404(self):
|
|
32
|
+
result = self.get_default_level(404)
|
|
33
|
+
self.assertEqual(result, "warning")
|
|
34
|
+
|
|
35
|
+
def test_returns_status_code_mapping_for_429(self):
|
|
36
|
+
result = self.get_default_level(429)
|
|
37
|
+
self.assertEqual(result, "warning")
|
|
38
|
+
|
|
39
|
+
def test_returns_status_code_mapping_for_500(self):
|
|
40
|
+
result = self.get_default_level(500)
|
|
41
|
+
self.assertEqual(result, "error")
|
|
42
|
+
|
|
43
|
+
def test_returns_status_code_mapping_for_503(self):
|
|
44
|
+
result = self.get_default_level(503)
|
|
45
|
+
self.assertEqual(result, "warning")
|
|
46
|
+
|
|
47
|
+
def test_returns_error_for_unmapped_4xx(self):
|
|
48
|
+
result = self.get_default_level(418) # I'm a teapot
|
|
49
|
+
self.assertEqual(result, "error")
|
|
50
|
+
|
|
51
|
+
def test_returns_error_for_unmapped_5xx(self):
|
|
52
|
+
result = self.get_default_level(599)
|
|
53
|
+
self.assertEqual(result, "error")
|
|
54
|
+
|
|
55
|
+
def test_returns_info_for_2xx(self):
|
|
56
|
+
result = self.get_default_level(200)
|
|
57
|
+
self.assertEqual(result, "info")
|
|
58
|
+
|
|
59
|
+
def test_exception_level_overrides_status_code_default(self):
|
|
60
|
+
exc = MagicMock()
|
|
61
|
+
exc.level = "info"
|
|
62
|
+
result = self.get_default_level(500, exc) # 500 defaults to "error"
|
|
63
|
+
self.assertEqual(result, "info")
|
|
64
|
+
|
|
65
|
+
def test_ignores_none_level_on_exception(self):
|
|
66
|
+
exc = MagicMock()
|
|
67
|
+
exc.level = None
|
|
68
|
+
result = self.get_default_level(404)
|
|
69
|
+
self.assertEqual(result, "warning")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TestAPIException(unittest.TestCase):
|
|
73
|
+
"""Tests for APIException class with level support."""
|
|
74
|
+
|
|
75
|
+
def setUp(self):
|
|
76
|
+
from karrio.server.core.exceptions import APIException, IndexedAPIException
|
|
77
|
+
self.APIException = APIException
|
|
78
|
+
self.IndexedAPIException = IndexedAPIException
|
|
79
|
+
|
|
80
|
+
def test_default_level_is_none(self):
|
|
81
|
+
exc = self.APIException(detail="Test error")
|
|
82
|
+
self.assertIsNone(exc.level)
|
|
83
|
+
|
|
84
|
+
def test_level_can_be_set_in_constructor(self):
|
|
85
|
+
exc = self.APIException(detail="Test error", level="warning")
|
|
86
|
+
self.assertEqual(exc.level, "warning")
|
|
87
|
+
|
|
88
|
+
def test_status_code_default(self):
|
|
89
|
+
exc = self.APIException(detail="Test error")
|
|
90
|
+
self.assertEqual(exc.status_code, status.HTTP_400_BAD_REQUEST)
|
|
91
|
+
|
|
92
|
+
def test_custom_status_code(self):
|
|
93
|
+
exc = self.APIException(detail="Test error", status_code=500)
|
|
94
|
+
self.assertEqual(exc.status_code, 500)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestIndexedAPIException(unittest.TestCase):
|
|
98
|
+
"""Tests for IndexedAPIException class."""
|
|
99
|
+
|
|
100
|
+
def setUp(self):
|
|
101
|
+
from karrio.server.core.exceptions import IndexedAPIException
|
|
102
|
+
self.IndexedAPIException = IndexedAPIException
|
|
103
|
+
|
|
104
|
+
def test_index_is_set(self):
|
|
105
|
+
exc = self.IndexedAPIException(index=5, detail="Test error")
|
|
106
|
+
self.assertEqual(exc.index, 5)
|
|
107
|
+
|
|
108
|
+
def test_level_can_be_set(self):
|
|
109
|
+
exc = self.IndexedAPIException(index=0, detail="Test error", level="warning")
|
|
110
|
+
self.assertEqual(exc.level, "warning")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class TestErrorLevelDefaults(unittest.TestCase):
|
|
114
|
+
"""Tests for ERROR_LEVEL_DEFAULTS mapping."""
|
|
115
|
+
|
|
116
|
+
def setUp(self):
|
|
117
|
+
from karrio.server.core.exceptions import ERROR_LEVEL_DEFAULTS
|
|
118
|
+
self.ERROR_LEVEL_DEFAULTS = ERROR_LEVEL_DEFAULTS
|
|
119
|
+
|
|
120
|
+
def test_client_errors_mapped(self):
|
|
121
|
+
self.assertIn(400, self.ERROR_LEVEL_DEFAULTS)
|
|
122
|
+
self.assertIn(401, self.ERROR_LEVEL_DEFAULTS)
|
|
123
|
+
self.assertIn(403, self.ERROR_LEVEL_DEFAULTS)
|
|
124
|
+
self.assertIn(404, self.ERROR_LEVEL_DEFAULTS)
|
|
125
|
+
self.assertIn(422, self.ERROR_LEVEL_DEFAULTS)
|
|
126
|
+
|
|
127
|
+
def test_server_errors_mapped(self):
|
|
128
|
+
self.assertIn(500, self.ERROR_LEVEL_DEFAULTS)
|
|
129
|
+
self.assertIn(502, self.ERROR_LEVEL_DEFAULTS)
|
|
130
|
+
self.assertIn(503, self.ERROR_LEVEL_DEFAULTS)
|
|
131
|
+
self.assertIn(504, self.ERROR_LEVEL_DEFAULTS)
|
|
132
|
+
|
|
133
|
+
def test_404_is_warning(self):
|
|
134
|
+
self.assertEqual(self.ERROR_LEVEL_DEFAULTS[404], "warning")
|
|
135
|
+
|
|
136
|
+
def test_429_is_warning(self):
|
|
137
|
+
self.assertEqual(self.ERROR_LEVEL_DEFAULTS[429], "warning")
|
|
138
|
+
|
|
139
|
+
def test_503_is_warning(self):
|
|
140
|
+
self.assertEqual(self.ERROR_LEVEL_DEFAULTS[503], "warning")
|
|
141
|
+
|
|
142
|
+
def test_500_is_error(self):
|
|
143
|
+
self.assertEqual(self.ERROR_LEVEL_DEFAULTS[500], "error")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class TestErrorDatatype(unittest.TestCase):
|
|
147
|
+
"""Tests for Error datatype with level field."""
|
|
148
|
+
|
|
149
|
+
def setUp(self):
|
|
150
|
+
from karrio.server.core.datatypes import Error
|
|
151
|
+
self.Error = Error
|
|
152
|
+
|
|
153
|
+
def test_error_has_level_field(self):
|
|
154
|
+
error = self.Error(code="test", message="Test error", level="warning")
|
|
155
|
+
self.assertEqual(error.level, "warning")
|
|
156
|
+
|
|
157
|
+
def test_error_level_defaults_to_none(self):
|
|
158
|
+
error = self.Error(code="test", message="Test error")
|
|
159
|
+
self.assertIsNone(error.level)
|