deltafi 2.28.0__tar.gz → 2.29.0__tar.gz
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.
Potentially problematic release.
This version of deltafi might be problematic. Click here for more details.
- {deltafi-2.28.0 → deltafi-2.29.0}/PKG-INFO +1 -1
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/plugin.py +1 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/result.py +17 -3
- deltafi-2.29.0/deltafi/resultmessage.py +56 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/egress.py +1 -1
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/framework.py +25 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/timed_ingress.py +4 -1
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/transform.py +2 -1
- {deltafi-2.28.0 → deltafi-2.29.0}/pyproject.toml +1 -1
- {deltafi-2.28.0 → deltafi-2.29.0}/README.md +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/__init__.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/action.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/actioneventqueue.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/actiontype.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/domain.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/exception.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/genericmodel.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/input.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/logger.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/metric.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/storage.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/__init__.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/assertions.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/compare_helpers.py +0 -0
- {deltafi-2.28.0 → deltafi-2.29.0}/deltafi/test_kit/constants.py +0 -0
|
@@ -392,6 +392,7 @@ class Plugin(object):
|
|
|
392
392
|
'start': start_time,
|
|
393
393
|
'stop': stop_time,
|
|
394
394
|
'type': result.result_type,
|
|
395
|
+
'messages': [message.json() for message in result.messages],
|
|
395
396
|
'metrics': [metric.json() for metric in result.metrics]
|
|
396
397
|
}
|
|
397
398
|
if result.result_key is not None:
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
import abc
|
|
20
20
|
import uuid
|
|
21
21
|
from enum import Enum
|
|
22
|
-
from typing import NamedTuple
|
|
23
22
|
|
|
24
23
|
from deltafi.domain import Content, Context
|
|
25
24
|
from deltafi.metric import Metric
|
|
25
|
+
from deltafi.resultmessage import LogMessage
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class Result:
|
|
@@ -31,6 +31,7 @@ class Result:
|
|
|
31
31
|
def __init__(self, result_key, result_type, context):
|
|
32
32
|
self.result_key = result_key
|
|
33
33
|
self.result_type = result_type
|
|
34
|
+
self.messages = []
|
|
34
35
|
self.metrics = []
|
|
35
36
|
self.context = context
|
|
36
37
|
|
|
@@ -42,6 +43,18 @@ class Result:
|
|
|
42
43
|
self.metrics.append(metric)
|
|
43
44
|
return self
|
|
44
45
|
|
|
46
|
+
def log_info(self, message: str):
|
|
47
|
+
self.messages.append(LogMessage.info(self.context.action_name, message))
|
|
48
|
+
return self
|
|
49
|
+
|
|
50
|
+
def log_warning(self, message: str):
|
|
51
|
+
self.messages.append(LogMessage.warning(self.context.action_name, message))
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def log_error(self, message: str):
|
|
55
|
+
self.messages.append(LogMessage.error(self.context.action_name, message))
|
|
56
|
+
return self
|
|
57
|
+
|
|
45
58
|
|
|
46
59
|
class EgressResult(Result):
|
|
47
60
|
def __init__(self, context: Context):
|
|
@@ -63,6 +76,7 @@ class ErrorResult(Result):
|
|
|
63
76
|
return self
|
|
64
77
|
|
|
65
78
|
def response(self):
|
|
79
|
+
self.log_error(self.error_cause + '\n' + self.error_context)
|
|
66
80
|
return {
|
|
67
81
|
'cause': self.error_cause,
|
|
68
82
|
'context': self.error_context,
|
|
@@ -145,8 +159,8 @@ class IngressResultItem:
|
|
|
145
159
|
return segment_names
|
|
146
160
|
|
|
147
161
|
def annotate(self, key: str, value: str):
|
|
148
|
-
|
|
149
|
-
|
|
162
|
+
self.annotations[key] = value
|
|
163
|
+
return self
|
|
150
164
|
|
|
151
165
|
def response(self):
|
|
152
166
|
return {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DeltaFi - Data transformation and enrichment platform
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2021-2025 DeltaFi Contributors <deltafi@deltafi.org>
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
import time
|
|
20
|
+
from enum import Enum
|
|
21
|
+
from typing import NamedTuple
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LogSeverity(Enum):
|
|
25
|
+
TRACE = "TRACE"
|
|
26
|
+
INFO = "INFO"
|
|
27
|
+
WARNING = "WARNING"
|
|
28
|
+
ERROR = "ERROR"
|
|
29
|
+
USER = "USER"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LogMessage(NamedTuple):
|
|
33
|
+
severity: LogSeverity
|
|
34
|
+
created: int
|
|
35
|
+
source: str
|
|
36
|
+
message: str
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def info(cls, source: str, message: str):
|
|
40
|
+
return LogMessage(severity=LogSeverity.INFO, created=time.time(), source=source, message=message)
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def warning(cls, source: str, message: str):
|
|
44
|
+
return LogMessage(severity=LogSeverity.WARNING, created=time.time(), source=source,
|
|
45
|
+
message=message)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def error(cls, source: str, message: str):
|
|
49
|
+
return LogMessage(severity=LogSeverity.ERROR, created=time.time(), source=source,
|
|
50
|
+
message=message)
|
|
51
|
+
|
|
52
|
+
def json(self):
|
|
53
|
+
return {'severity': self.severity.value,
|
|
54
|
+
'created': self.created,
|
|
55
|
+
'source': self.source,
|
|
56
|
+
'message': self.message}
|
|
@@ -50,5 +50,5 @@ class EgressActionTest(ActionTest):
|
|
|
50
50
|
self.assert_egress_result(test_case, result)
|
|
51
51
|
|
|
52
52
|
def assert_egress_result(self, test_case: EgressTestCase, result: EgressResult):
|
|
53
|
-
# Check metrics
|
|
54
53
|
self.compare_metrics(test_case.expected_metrics, result.metrics)
|
|
54
|
+
self.compare_log_messages(test_case.expected_messages, result.messages)
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
#
|
|
18
18
|
|
|
19
|
+
import re
|
|
19
20
|
import uuid
|
|
20
21
|
from abc import ABC
|
|
21
22
|
from importlib.resources import files
|
|
@@ -25,7 +26,9 @@ from deltafi.domain import DeltaFileMessage, Event, Content, Context
|
|
|
25
26
|
from deltafi.logger import get_logger
|
|
26
27
|
from deltafi.metric import Metric
|
|
27
28
|
from deltafi.result import ErrorResult, FilterResult
|
|
29
|
+
from deltafi.resultmessage import LogMessage
|
|
28
30
|
from deltafi.storage import Segment
|
|
31
|
+
|
|
29
32
|
from .assertions import *
|
|
30
33
|
from .compare_helpers import GenericCompareHelper, CompareHelper
|
|
31
34
|
from .constants import *
|
|
@@ -170,10 +173,14 @@ class TestCaseBase(ABC):
|
|
|
170
173
|
self.err_or_filt_annotations = None
|
|
171
174
|
self.join_meta = data["join_meta"] if "join_meta" in data else None
|
|
172
175
|
self.expected_metrics = []
|
|
176
|
+
self.expected_messages = []
|
|
173
177
|
|
|
174
178
|
def add_metric(self, metric: Metric):
|
|
175
179
|
self.expected_metrics.append(metric)
|
|
176
180
|
|
|
181
|
+
def add_message(self, message: LogMessage):
|
|
182
|
+
self.expected_messages.append(message)
|
|
183
|
+
|
|
177
184
|
def expect_error_result(self, cause: str, context: str, annotations: Dict = None):
|
|
178
185
|
"""
|
|
179
186
|
A Sets the expected output of the action to an Error Result
|
|
@@ -360,6 +367,24 @@ class ActionTest(ABC):
|
|
|
360
367
|
for index, expected in enumerate(expected_metrics):
|
|
361
368
|
self.compare_one_metric(expected, results[index])
|
|
362
369
|
|
|
370
|
+
@staticmethod
|
|
371
|
+
def compare_one_message(expected: LogMessage, result: LogMessage):
|
|
372
|
+
assert_equal_short(expected.severity, result.severity, "message severity does not match")
|
|
373
|
+
# Look for regex characters:
|
|
374
|
+
if '*' in expected.message or '{' in expected.message or '^' in expected.message \
|
|
375
|
+
or '$' in expected.message:
|
|
376
|
+
match = re.search(expected.message, result.message)
|
|
377
|
+
assert match is not None, "message does not match regex"
|
|
378
|
+
|
|
379
|
+
else:
|
|
380
|
+
assert_equal_short(expected.message, result.message, "message value does not match")
|
|
381
|
+
|
|
382
|
+
def compare_log_messages(self, expected_messages: List[LogMessage], results: List[LogMessage]):
|
|
383
|
+
if len(expected_messages) > 0:
|
|
384
|
+
assert_equal_len_with_label(expected_messages, results, "invalid messages count")
|
|
385
|
+
for index, expected in enumerate(expected_messages):
|
|
386
|
+
self.compare_one_message(expected, results[index])
|
|
387
|
+
|
|
363
388
|
def has_saved_content__size(self, count: int):
|
|
364
389
|
assert_equal_with_label(
|
|
365
390
|
count, len(self.context.saved_content), "savedContent")
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
from typing import List
|
|
20
20
|
|
|
21
21
|
from deltafi.result import IngressResult, IngressResultItem, IngressStatusEnum
|
|
22
|
+
|
|
22
23
|
from .assertions import *
|
|
23
24
|
from .framework import TestCaseBase, ActionTest, IOContent
|
|
24
25
|
|
|
@@ -43,7 +44,8 @@ class TimedIngressTestCase(TestCaseBase):
|
|
|
43
44
|
self.status = status
|
|
44
45
|
self.status_message = status_message
|
|
45
46
|
|
|
46
|
-
def add_ingress_result_item(self, content: List[IOContent], metadata: Dict, name: str = None,
|
|
47
|
+
def add_ingress_result_item(self, content: List[IOContent], metadata: Dict, name: str = None,
|
|
48
|
+
annotations: Dict = None):
|
|
47
49
|
if annotations is None:
|
|
48
50
|
annotations = {}
|
|
49
51
|
self.results.append(
|
|
@@ -80,6 +82,7 @@ class TimedIngressActionTest(ActionTest):
|
|
|
80
82
|
assert_equal_short(test_case.execute_immediate, result.execute_immediate, "invalid execute_immediate")
|
|
81
83
|
assert_equal_short(test_case.status, result.status, "invalid status")
|
|
82
84
|
assert_equal_with_label(test_case.status_message, result.status_message, "invalid status_message")
|
|
85
|
+
self.compare_log_messages(test_case.expected_messages, result.messages)
|
|
83
86
|
|
|
84
87
|
assert_equal_len_with_label(test_case.results, result.ingress_result_items, "item count mismatch")
|
|
85
88
|
for index, ingress_item in enumerate(result.ingress_result_items):
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
from typing import List
|
|
20
20
|
|
|
21
21
|
from deltafi.result import TransformResult, TransformResults
|
|
22
|
+
|
|
22
23
|
from .assertions import *
|
|
23
24
|
from .framework import TestCaseBase, ActionTest, IOContent
|
|
24
25
|
|
|
@@ -81,8 +82,8 @@ class TransformActionTest(ActionTest):
|
|
|
81
82
|
assert_equal_with_label(expected["name"], child_result.delta_file_name, f"name[{index}]")
|
|
82
83
|
|
|
83
84
|
def assert_transform_result(self, test_case: TransformTestCase, result: TransformResult):
|
|
84
|
-
# Check metrics
|
|
85
85
|
self.compare_metrics(test_case.expected_metrics, result.metrics)
|
|
86
|
+
self.compare_log_messages(test_case.expected_messages, result.messages)
|
|
86
87
|
self.compare_one_transform_result(test_case, result, 0)
|
|
87
88
|
|
|
88
89
|
def compare_one_transform_result(self, test_case: TransformTestCase, result: TransformResult, index: int):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|