deltafi 2.0rc1719271450675__py3-none-any.whl → 2.0rc1720728217472__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.
Potentially problematic release.
This version of deltafi might be problematic. Click here for more details.
- deltafi/action.py +119 -17
- deltafi/actiontype.py +6 -2
- deltafi/domain.py +52 -56
- deltafi/exception.py +10 -0
- deltafi/input.py +165 -1
- deltafi/plugin.py +17 -9
- deltafi/result.py +245 -32
- deltafi/test_kit/format.py +105 -0
- deltafi/test_kit/framework.py +50 -27
- deltafi/test_kit/load.py +128 -0
- deltafi/test_kit/transform.py +13 -41
- {deltafi-2.0rc1719271450675.dist-info → deltafi-2.0rc1720728217472.dist-info}/METADATA +5 -5
- {deltafi-2.0rc1719271450675.dist-info → deltafi-2.0rc1720728217472.dist-info}/RECORD +14 -12
- {deltafi-2.0rc1719271450675.dist-info → deltafi-2.0rc1720728217472.dist-info}/WHEEL +0 -0
deltafi/result.py
CHANGED
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
import abc
|
|
20
|
-
import uuid
|
|
21
20
|
from enum import Enum
|
|
22
|
-
|
|
21
|
+
import uuid
|
|
22
|
+
from typing import Dict, List
|
|
23
23
|
|
|
24
24
|
from deltafi.domain import Content, Context
|
|
25
25
|
from deltafi.metric import Metric
|
|
@@ -44,8 +44,22 @@ class Result:
|
|
|
44
44
|
|
|
45
45
|
def add_metric(self, metric: Metric):
|
|
46
46
|
self.metrics.append(metric)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DomainResult(Result):
|
|
50
|
+
def __init__(self, context: Context):
|
|
51
|
+
super().__init__('domain', 'DOMAIN', context)
|
|
52
|
+
self.annotations = {}
|
|
53
|
+
|
|
54
|
+
def annotate(self, key: str, value: str):
|
|
55
|
+
self.annotations[key] = value
|
|
47
56
|
return self
|
|
48
57
|
|
|
58
|
+
def response(self):
|
|
59
|
+
return {
|
|
60
|
+
'annotations': self.annotations
|
|
61
|
+
}
|
|
62
|
+
|
|
49
63
|
|
|
50
64
|
class EgressResult(Result):
|
|
51
65
|
def __init__(self, context: Context, destination: str, bytes_egressed: int):
|
|
@@ -57,6 +71,31 @@ class EgressResult(Result):
|
|
|
57
71
|
return None
|
|
58
72
|
|
|
59
73
|
|
|
74
|
+
class EnrichResult(Result):
|
|
75
|
+
def __init__(self, context: Context):
|
|
76
|
+
super().__init__('enrich', 'ENRICH', context)
|
|
77
|
+
self.enrichments = []
|
|
78
|
+
self.annotations = {}
|
|
79
|
+
|
|
80
|
+
def enrich(self, name: str, value: str, media_type: str):
|
|
81
|
+
self.enrichments.append({
|
|
82
|
+
'name': name,
|
|
83
|
+
'value': value,
|
|
84
|
+
'mediaType': media_type
|
|
85
|
+
})
|
|
86
|
+
return self
|
|
87
|
+
|
|
88
|
+
def annotate(self, key: str, value: str):
|
|
89
|
+
self.annotations[key] = value
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def response(self):
|
|
93
|
+
return {
|
|
94
|
+
'enrichments': self.enrichments,
|
|
95
|
+
'annotations': self.annotations
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
60
99
|
class ErrorResult(Result):
|
|
61
100
|
def __init__(self, context: Context, error_cause: str, error_context: str):
|
|
62
101
|
super().__init__('error', 'ERROR', context)
|
|
@@ -77,7 +116,7 @@ class ErrorResult(Result):
|
|
|
77
116
|
|
|
78
117
|
|
|
79
118
|
class FilterResult(Result):
|
|
80
|
-
def __init__(self, context: Context, filtered_cause: str, filtered_context: str
|
|
119
|
+
def __init__(self, context: Context, filtered_cause: str, filtered_context: str=None):
|
|
81
120
|
super().__init__('filter', 'FILTER', context)
|
|
82
121
|
self.filtered_cause = filtered_cause
|
|
83
122
|
self.filtered_context = filtered_context
|
|
@@ -95,13 +134,87 @@ class FilterResult(Result):
|
|
|
95
134
|
}
|
|
96
135
|
|
|
97
136
|
|
|
137
|
+
class FormatResult(Result):
|
|
138
|
+
def __init__(self, context: Context):
|
|
139
|
+
super().__init__('format', 'FORMAT', context)
|
|
140
|
+
self.content = None
|
|
141
|
+
self.delete_metadata_keys = []
|
|
142
|
+
self.metadata = {}
|
|
143
|
+
|
|
144
|
+
def set_metadata(self, metadata: dict):
|
|
145
|
+
self.metadata = metadata
|
|
146
|
+
return self
|
|
147
|
+
|
|
148
|
+
def add_metadata(self, key: str, value: str):
|
|
149
|
+
self.metadata[key] = value
|
|
150
|
+
return self
|
|
151
|
+
|
|
152
|
+
def delete_metadata_key(self, key: str):
|
|
153
|
+
self.delete_metadata_keys.append(key)
|
|
154
|
+
return self
|
|
155
|
+
|
|
156
|
+
def set_content(self, content: Content):
|
|
157
|
+
self.content = content
|
|
158
|
+
return self
|
|
159
|
+
|
|
160
|
+
def save_string_content(self, string_data: str, name: str, media_type: str):
|
|
161
|
+
segment = self.context.content_service.put_str(self.context.did, string_data)
|
|
162
|
+
self.content = Content(name=name, segments=[segment], media_type=media_type,
|
|
163
|
+
content_service=self.context.content_service)
|
|
164
|
+
return self
|
|
165
|
+
|
|
166
|
+
def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
|
|
167
|
+
segment = self.context.content_service.put_bytes(self.context.did, byte_data)
|
|
168
|
+
self.content = Content(name=name, segments=[segment], media_type=media_type,
|
|
169
|
+
content_service=self.context.content_service)
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
def response(self):
|
|
173
|
+
return {
|
|
174
|
+
'content': self.content.json(),
|
|
175
|
+
'metadata': self.metadata,
|
|
176
|
+
'deleteMetadataKeys': self.delete_metadata_keys
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class ChildFormatResult:
|
|
181
|
+
def __init__(self, format_result: FormatResult = None):
|
|
182
|
+
self._did = str(uuid.uuid4())
|
|
183
|
+
self.format_result = format_result
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def did(self):
|
|
187
|
+
return self._did
|
|
188
|
+
|
|
189
|
+
def response(self):
|
|
190
|
+
res = self.format_result.response()
|
|
191
|
+
res["did"] = self._did
|
|
192
|
+
return res
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class FormatManyResult(Result):
|
|
196
|
+
def __init__(self, context: Context):
|
|
197
|
+
super().__init__('formatMany', 'FORMAT_MANY', context)
|
|
198
|
+
self.format_results = []
|
|
199
|
+
|
|
200
|
+
def add_format_result(self, format_result):
|
|
201
|
+
if isinstance(format_result, ChildFormatResult):
|
|
202
|
+
self.format_results.append(format_result)
|
|
203
|
+
else:
|
|
204
|
+
self.format_results.append(ChildFormatResult(format_result))
|
|
205
|
+
return self
|
|
206
|
+
|
|
207
|
+
def response(self):
|
|
208
|
+
return [format_result.response() for format_result in self.format_results]
|
|
209
|
+
|
|
210
|
+
|
|
98
211
|
class IngressResultItem:
|
|
99
|
-
def __init__(self, context: Context,
|
|
212
|
+
def __init__(self, context: Context, filename: str):
|
|
100
213
|
self.context = context
|
|
214
|
+
self.filename = filename
|
|
101
215
|
self._did = str(uuid.uuid4())
|
|
102
216
|
self.content = []
|
|
103
217
|
self.metadata = {}
|
|
104
|
-
self.delta_file_name = delta_file_name
|
|
105
218
|
|
|
106
219
|
@property
|
|
107
220
|
def did(self):
|
|
@@ -140,7 +253,7 @@ class IngressResultItem:
|
|
|
140
253
|
def response(self):
|
|
141
254
|
return {
|
|
142
255
|
'did': self._did,
|
|
143
|
-
'
|
|
256
|
+
'filename': self.filename,
|
|
144
257
|
'metadata': self.metadata,
|
|
145
258
|
'content': [content.json() for content in self.content]
|
|
146
259
|
}
|
|
@@ -156,10 +269,10 @@ class IngressResult(Result):
|
|
|
156
269
|
def __init__(self, context: Context):
|
|
157
270
|
super().__init__('ingress', 'INGRESS', context)
|
|
158
271
|
self.memo = None
|
|
159
|
-
self.ingress_result_items = []
|
|
160
272
|
self.execute_immediate = False
|
|
273
|
+
self.ingress_result_items = []
|
|
161
274
|
self.status = IngressStatusEnum.HEALTHY
|
|
162
|
-
self.
|
|
275
|
+
self.statusMessage = None
|
|
163
276
|
|
|
164
277
|
def add_item(self, ingress_result_item: IngressResultItem):
|
|
165
278
|
self.ingress_result_items.append(ingress_result_item)
|
|
@@ -171,16 +284,17 @@ class IngressResult(Result):
|
|
|
171
284
|
'executeImmediate': self.execute_immediate,
|
|
172
285
|
'ingressItems': [ingress_result_item.response() for ingress_result_item in self.ingress_result_items],
|
|
173
286
|
'status': self.status.value,
|
|
174
|
-
'statusMessage': self.
|
|
287
|
+
'statusMessage': self.statusMessage
|
|
175
288
|
}
|
|
176
289
|
|
|
177
290
|
|
|
178
|
-
class
|
|
291
|
+
class LoadResult(Result):
|
|
179
292
|
def __init__(self, context: Context):
|
|
180
|
-
super().__init__('
|
|
293
|
+
super().__init__('load', 'LOAD', context)
|
|
181
294
|
self.content = []
|
|
182
|
-
self.annotations = {}
|
|
183
295
|
self.metadata = {}
|
|
296
|
+
self.domains = []
|
|
297
|
+
self.annotations = {}
|
|
184
298
|
self.delete_metadata_keys = []
|
|
185
299
|
|
|
186
300
|
# content can be a single Content or a List[Content]
|
|
@@ -213,6 +327,13 @@ class TransformResult(Result):
|
|
|
213
327
|
self.metadata[key] = value
|
|
214
328
|
return self
|
|
215
329
|
|
|
330
|
+
def add_domain(self, name: str, value: str, media_type: str):
|
|
331
|
+
self.domains.append({
|
|
332
|
+
'name': name,
|
|
333
|
+
'value': value,
|
|
334
|
+
'mediaType': media_type})
|
|
335
|
+
return self
|
|
336
|
+
|
|
216
337
|
def annotate(self, key: str, value: str):
|
|
217
338
|
self.annotations[key] = value
|
|
218
339
|
return self
|
|
@@ -221,41 +342,133 @@ class TransformResult(Result):
|
|
|
221
342
|
self.delete_metadata_keys.append(key)
|
|
222
343
|
return self
|
|
223
344
|
|
|
224
|
-
def
|
|
345
|
+
def response(self):
|
|
225
346
|
return {
|
|
347
|
+
'domains': self.domains,
|
|
226
348
|
'content': [content.json() for content in self.content],
|
|
227
|
-
'annotations': self.annotations,
|
|
228
349
|
'metadata': self.metadata,
|
|
350
|
+
'annotations': self.annotations,
|
|
229
351
|
'deleteMetadataKeys': self.delete_metadata_keys
|
|
230
352
|
}
|
|
231
353
|
|
|
354
|
+
|
|
355
|
+
class ChildLoadResult:
|
|
356
|
+
def __init__(self, load_result: LoadResult = None):
|
|
357
|
+
self._did = str(uuid.uuid4())
|
|
358
|
+
self.load_result = load_result
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
def did(self):
|
|
362
|
+
return self._did
|
|
363
|
+
|
|
364
|
+
def response(self):
|
|
365
|
+
res = self.load_result.response()
|
|
366
|
+
res["did"] = self._did
|
|
367
|
+
return res
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class LoadManyResult(Result):
|
|
371
|
+
def __init__(self, context: Context):
|
|
372
|
+
super().__init__('loadMany', 'LOAD_MANY', context)
|
|
373
|
+
self.load_results = []
|
|
374
|
+
|
|
375
|
+
def add_load_result(self, load_result):
|
|
376
|
+
if isinstance(load_result, ChildLoadResult):
|
|
377
|
+
self.load_results.append(load_result)
|
|
378
|
+
else:
|
|
379
|
+
self.load_results.append(ChildLoadResult(load_result))
|
|
380
|
+
return self
|
|
381
|
+
|
|
232
382
|
def response(self):
|
|
233
|
-
return [
|
|
383
|
+
return [load_result.response() for load_result in self.load_results]
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class ReinjectResult(Result):
|
|
387
|
+
class ReinjectChild:
|
|
388
|
+
def __init__(self, filename: str, flow: str, content: List[Content], metadata: Dict[str, str]):
|
|
389
|
+
self.filename = filename
|
|
390
|
+
self.flow = flow
|
|
391
|
+
self.content = content
|
|
392
|
+
self.metadata = metadata
|
|
234
393
|
|
|
394
|
+
def json(self):
|
|
395
|
+
return {
|
|
396
|
+
'filename': self.filename,
|
|
397
|
+
'flow': self.flow,
|
|
398
|
+
'metadata': self.metadata,
|
|
399
|
+
'content': [content.json() for content in self.content]
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
def __init__(self, context: Context):
|
|
403
|
+
super().__init__('reinject', 'REINJECT', context)
|
|
404
|
+
self.children = []
|
|
235
405
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
406
|
+
def add_child(self, filename: str, flow: str, content: List[Content], metadata: Dict[str, str]):
|
|
407
|
+
child = ReinjectResult.ReinjectChild(filename, flow, content, metadata)
|
|
408
|
+
self.children.append(child)
|
|
239
409
|
|
|
240
|
-
def
|
|
241
|
-
|
|
242
|
-
if self.name is not None:
|
|
243
|
-
j['name'] = self.name
|
|
244
|
-
return j
|
|
410
|
+
def response(self):
|
|
411
|
+
return [child.json() for child in self.children]
|
|
245
412
|
|
|
246
413
|
|
|
247
|
-
class
|
|
414
|
+
class TransformResult(Result):
|
|
248
415
|
def __init__(self, context: Context):
|
|
249
416
|
super().__init__('transform', 'TRANSFORM', context)
|
|
250
|
-
self.
|
|
417
|
+
self.content = []
|
|
418
|
+
self.metadata = {}
|
|
419
|
+
self.annotations = {}
|
|
420
|
+
self.delete_metadata_keys = []
|
|
421
|
+
|
|
422
|
+
# content can be a single Content or a List[Content]
|
|
423
|
+
def add_content(self, content):
|
|
424
|
+
if content:
|
|
425
|
+
if type(content) == list:
|
|
426
|
+
self.content.extend(content)
|
|
427
|
+
else:
|
|
428
|
+
self.content.append(content)
|
|
251
429
|
|
|
252
|
-
|
|
253
|
-
|
|
430
|
+
return self
|
|
431
|
+
|
|
432
|
+
def save_string_content(self, string_data: str, name: str, media_type: str):
|
|
433
|
+
segment = self.context.content_service.put_str(self.context.did, string_data)
|
|
434
|
+
self.content.append(
|
|
435
|
+
Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
|
|
436
|
+
return self
|
|
437
|
+
|
|
438
|
+
def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
|
|
439
|
+
segment = self.context.content_service.put_bytes(self.context.did, byte_data)
|
|
440
|
+
self.content.append(
|
|
441
|
+
Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
|
|
442
|
+
return self
|
|
443
|
+
|
|
444
|
+
def set_metadata(self, metadata: dict):
|
|
445
|
+
self.metadata = metadata
|
|
446
|
+
return self
|
|
447
|
+
|
|
448
|
+
def add_metadata(self, key: str, value: str):
|
|
449
|
+
self.metadata[key] = value
|
|
450
|
+
return self
|
|
451
|
+
|
|
452
|
+
def annotate(self, key: str, value: str):
|
|
453
|
+
self.annotations[key] = value
|
|
454
|
+
return self
|
|
455
|
+
|
|
456
|
+
def delete_metadata_key(self, key: str):
|
|
457
|
+
self.delete_metadata_keys.append(key)
|
|
254
458
|
return self
|
|
255
459
|
|
|
256
460
|
def response(self):
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
461
|
+
return {
|
|
462
|
+
'content': [content.json() for content in self.content],
|
|
463
|
+
'metadata': self.metadata,
|
|
464
|
+
'annotations': self.annotations,
|
|
465
|
+
'deleteMetadataKeys': self.delete_metadata_keys
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
class ValidateResult(Result):
|
|
470
|
+
def __init__(self, context: Context):
|
|
471
|
+
super().__init__(None, 'VALIDATE', context)
|
|
472
|
+
|
|
473
|
+
def response(self):
|
|
474
|
+
return None
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DeltaFi - Data transformation and enrichment platform
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2021-2023 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
|
+
from typing import List
|
|
20
|
+
|
|
21
|
+
from deltafi.result import FormatResult, FormatManyResult
|
|
22
|
+
|
|
23
|
+
from .assertions import *
|
|
24
|
+
from .framework import TestCaseBase, ActionTest
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FormatTestCase(TestCaseBase):
|
|
28
|
+
def __init__(self, fields: Dict):
|
|
29
|
+
super().__init__(fields)
|
|
30
|
+
self.metadata = {}
|
|
31
|
+
self.delete_metadata_keys = []
|
|
32
|
+
self.expected_format_many_result = []
|
|
33
|
+
|
|
34
|
+
def expect_format_result(self, metadata: Dict, delete_metadata_keys: List[str]):
|
|
35
|
+
self.expected_result_type = FormatResult
|
|
36
|
+
self.metadata = metadata
|
|
37
|
+
self.delete_metadata_keys = delete_metadata_keys
|
|
38
|
+
|
|
39
|
+
def add_format_many_result(self, metadata: Dict, delete_metadata_keys: List):
|
|
40
|
+
self.expected_result_type = FormatManyResult
|
|
41
|
+
self.expected_format_many_result.append(
|
|
42
|
+
{
|
|
43
|
+
"metadata": metadata,
|
|
44
|
+
"delete_metadata_keys": delete_metadata_keys
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FormatActionTest(ActionTest):
|
|
50
|
+
def __init__(self, package_name: str):
|
|
51
|
+
"""
|
|
52
|
+
Provides structure for testing DeltaFi Format action
|
|
53
|
+
Args:
|
|
54
|
+
package_name: name of the actions package for finding resources
|
|
55
|
+
"""
|
|
56
|
+
super().__init__(package_name)
|
|
57
|
+
|
|
58
|
+
def format(self, test_case: FormatTestCase):
|
|
59
|
+
if test_case.expected_result_type == FormatManyResult:
|
|
60
|
+
self.expect_format_many_result(test_case)
|
|
61
|
+
elif test_case.expected_result_type == FormatResult:
|
|
62
|
+
self.expect_format_result(test_case)
|
|
63
|
+
else:
|
|
64
|
+
super().execute(test_case)
|
|
65
|
+
|
|
66
|
+
def expect_format_result(self, test_case: FormatTestCase):
|
|
67
|
+
result = super().run_and_check_result_type(test_case, FormatResult)
|
|
68
|
+
self.assert_format_result(test_case, result)
|
|
69
|
+
|
|
70
|
+
def expect_format_many_result(self, test_case: FormatTestCase):
|
|
71
|
+
result = super().run_and_check_result_type(test_case, FormatManyResult)
|
|
72
|
+
self.assert_format_many_result(test_case, result)
|
|
73
|
+
|
|
74
|
+
def assert_format_result(self, test_case: FormatTestCase, result: FormatResult):
|
|
75
|
+
# Check metrics
|
|
76
|
+
self.compare_metrics(test_case.expected_metrics, result.metrics)
|
|
77
|
+
|
|
78
|
+
# Check output
|
|
79
|
+
if result.content is None:
|
|
80
|
+
self.compare_all_output(test_case.compare_tool, [])
|
|
81
|
+
else:
|
|
82
|
+
self.compare_all_output(test_case.compare_tool, [result.content])
|
|
83
|
+
|
|
84
|
+
# Check metadata
|
|
85
|
+
assert_keys_and_values(test_case.metadata, result.metadata)
|
|
86
|
+
|
|
87
|
+
# Check deleted metadata
|
|
88
|
+
for key in test_case.delete_metadata_keys:
|
|
89
|
+
assert_key_in(key, result.delete_metadata_keys)
|
|
90
|
+
|
|
91
|
+
def assert_format_many_result(self, test_case: FormatTestCase, actual: FormatManyResult):
|
|
92
|
+
# Check metrics
|
|
93
|
+
self.compare_metrics(test_case.expected_metrics, actual.metrics)
|
|
94
|
+
|
|
95
|
+
assert_equal_len(test_case.expected_format_many_result, actual.format_results)
|
|
96
|
+
for index, expected_child_result in enumerate(test_case.expected_format_many_result):
|
|
97
|
+
actual_child = actual.format_results[index]
|
|
98
|
+
self.compare_one_content(
|
|
99
|
+
test_case.compare_tool,
|
|
100
|
+
self.expected_outputs[index],
|
|
101
|
+
actual_child.format_result.content, index)
|
|
102
|
+
|
|
103
|
+
assert_keys_and_values(expected_child_result['metadata'], actual_child.format_result.metadata)
|
|
104
|
+
for key in expected_child_result['delete_metadata_keys']:
|
|
105
|
+
assert_key_in(key, actual_child.format_result.delete_metadata_keys)
|
deltafi/test_kit/framework.py
CHANGED
|
@@ -103,10 +103,6 @@ class InternalContentService:
|
|
|
103
103
|
seg_id = segments[0].uuid
|
|
104
104
|
return self.loaded_content[seg_id].data
|
|
105
105
|
|
|
106
|
-
def get_bytes(self, segments: List[Segment]):
|
|
107
|
-
seg_id = segments[0].uuid
|
|
108
|
-
return self.loaded_content[seg_id].data.encode('utf-8')
|
|
109
|
-
|
|
110
106
|
def get_output(self, seg_id: str):
|
|
111
107
|
if seg_id in self.outputs:
|
|
112
108
|
return self.outputs[seg_id]
|
|
@@ -127,6 +123,8 @@ class TestCaseBase(ABC):
|
|
|
127
123
|
- inputs: (optional) List[IOContent]: input content to action
|
|
128
124
|
- parameters: (optional) Dict: map of action input parameters
|
|
129
125
|
- in_meta: (optional) Dict: map of metadata as input to action
|
|
126
|
+
- in_domains: (optional) List[Domain]: list of domains as input to action
|
|
127
|
+
- in_enrichments: (optional) List[Domain]: list of enrichments as input to action
|
|
130
128
|
- did: (optional): str: overrides random DID
|
|
131
129
|
"""
|
|
132
130
|
if "action" in data:
|
|
@@ -146,8 +144,11 @@ class TestCaseBase(ABC):
|
|
|
146
144
|
|
|
147
145
|
self.inputs = data["inputs"] if "inputs" in data else []
|
|
148
146
|
self.file_name = data["file_name"] if "file_name" in data else "filename"
|
|
147
|
+
self.outputs = data["outputs"] if "outputs" in data else []
|
|
149
148
|
self.parameters = data["parameters"] if "parameters" in data else {}
|
|
150
149
|
self.in_meta = data["in_meta"] if "in_meta" in data else {}
|
|
150
|
+
self.in_domains = data["in_domains"] if "in_domains" in data else []
|
|
151
|
+
self.in_enrichments = data["in_enrichments"] if "in_enrichments" in data else []
|
|
151
152
|
self.use_did = data["did"] if "did" in data else None
|
|
152
153
|
self.expected_result_type = None
|
|
153
154
|
self.err_or_filt_cause = None
|
|
@@ -192,6 +193,7 @@ class ActionTest(ABC):
|
|
|
192
193
|
"""
|
|
193
194
|
self.content_service = InternalContentService()
|
|
194
195
|
self.did = ""
|
|
196
|
+
self.expected_outputs = []
|
|
195
197
|
self.loaded_inputs = []
|
|
196
198
|
self.package_name = package_name
|
|
197
199
|
self.res_path = ""
|
|
@@ -202,6 +204,7 @@ class ActionTest(ABC):
|
|
|
202
204
|
self.did = str(uuid.uuid4())
|
|
203
205
|
else:
|
|
204
206
|
self.did = did
|
|
207
|
+
self.expected_outputs = []
|
|
205
208
|
self.loaded_inputs = []
|
|
206
209
|
self.res_path = ""
|
|
207
210
|
|
|
@@ -222,6 +225,13 @@ class ActionTest(ABC):
|
|
|
222
225
|
else:
|
|
223
226
|
self.loaded_inputs.append(LoadedContent(self.did, input_ioc, None))
|
|
224
227
|
|
|
228
|
+
# Load expected outputs
|
|
229
|
+
for output_ioc in test_case.outputs:
|
|
230
|
+
if len(output_ioc.content_bytes) == 0:
|
|
231
|
+
self.expected_outputs.append(LoadedContent(self.did, output_ioc, self.load_file(output_ioc)))
|
|
232
|
+
else:
|
|
233
|
+
self.expected_outputs.append(LoadedContent(self.did, output_ioc, None))
|
|
234
|
+
|
|
225
235
|
def make_content_list(self, test_case: TestCaseBase):
|
|
226
236
|
content_list = []
|
|
227
237
|
for loaded_input in self.loaded_inputs:
|
|
@@ -236,23 +246,26 @@ class ActionTest(ABC):
|
|
|
236
246
|
content_list = self.make_content_list(test_case)
|
|
237
247
|
self.content_service.load(self.loaded_inputs)
|
|
238
248
|
|
|
239
|
-
return DeltaFileMessage(
|
|
240
|
-
|
|
249
|
+
return DeltaFileMessage(
|
|
250
|
+
metadata=test_case.in_meta,
|
|
251
|
+
content_list=content_list,
|
|
252
|
+
domains=test_case.in_domains,
|
|
253
|
+
enrichments=test_case.in_enrichments)
|
|
241
254
|
|
|
242
255
|
def make_context(self, test_case: TestCaseBase):
|
|
243
256
|
action_name = INGRESS_FLOW + "." + test_case.action.__class__.__name__
|
|
244
257
|
return Context(
|
|
245
258
|
did=self.did,
|
|
246
|
-
|
|
247
|
-
data_source="DATASRC",
|
|
248
|
-
flow_name=INGRESS_FLOW,
|
|
249
|
-
flow_id="FLOWID",
|
|
259
|
+
action_flow=INGRESS_FLOW,
|
|
250
260
|
action_name=action_name,
|
|
251
|
-
|
|
252
|
-
|
|
261
|
+
source_filename=test_case.file_name,
|
|
262
|
+
ingress_flow=INGRESS_FLOW,
|
|
263
|
+
egress_flow=EGRESS_FLOW,
|
|
264
|
+
system=SYSTEM,
|
|
253
265
|
hostname=HOSTNAME,
|
|
254
|
-
system_name=SYSTEM,
|
|
255
266
|
content_service=self.content_service,
|
|
267
|
+
collect=None,
|
|
268
|
+
collected_dids=None,
|
|
256
269
|
logger=get_logger())
|
|
257
270
|
|
|
258
271
|
def make_event(self, test_case: TestCaseBase):
|
|
@@ -298,27 +311,37 @@ class ActionTest(ABC):
|
|
|
298
311
|
else:
|
|
299
312
|
raise ValueError(f"unknown type: {test_case.expected_result_type}")
|
|
300
313
|
|
|
301
|
-
|
|
302
|
-
def compare_content_details(expected: LoadedContent, actual: Content):
|
|
314
|
+
def compare_content_details(self, expected: LoadedContent, actual: Content):
|
|
303
315
|
assert_equal(expected.content_type, actual.media_type)
|
|
304
316
|
assert_equal(expected.name, actual.name)
|
|
305
317
|
|
|
306
|
-
def compare_one_content(self,
|
|
318
|
+
def compare_one_content(self, comparitor: CompareHelper, expected: LoadedContent, actual, index):
|
|
307
319
|
self.compare_content_details(expected, actual)
|
|
308
320
|
seg_id = actual.segments[0].uuid
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def
|
|
312
|
-
assert_equal_len(expected_outputs, content)
|
|
313
|
-
for index,
|
|
314
|
-
|
|
315
|
-
|
|
321
|
+
comparitor.compare(expected.data, self.content_service.get_output(seg_id), f"Content[{index}]")
|
|
322
|
+
|
|
323
|
+
def compare_all_output(self, comparitor: CompareHelper, content: List):
|
|
324
|
+
assert_equal_len(self.expected_outputs, content)
|
|
325
|
+
for index, expected in enumerate(self.expected_outputs):
|
|
326
|
+
self.compare_one_content(comparitor, expected, content[index], index)
|
|
327
|
+
|
|
328
|
+
def compare_domains(self, comparitor: CompareHelper, expected_items: List[Dict], results: List[Dict]):
|
|
329
|
+
assert_equal_len(expected_items, results)
|
|
330
|
+
for index, expected in enumerate(expected_items):
|
|
331
|
+
actual = results[index]
|
|
332
|
+
assert_equal(expected['name'], actual['name'])
|
|
333
|
+
assert_equal(expected['mediaType'], actual['mediaType'])
|
|
334
|
+
|
|
335
|
+
expected_value = expected['value']
|
|
336
|
+
if type(expected_value) == str:
|
|
337
|
+
comparitor.compare(expected_value, actual['value'], f"Domain[{index}]")
|
|
338
|
+
elif type(expected_value) == IOContent:
|
|
339
|
+
expected_data = self.load_file(expected_value)
|
|
340
|
+
comparitor.compare(expected_data, actual['value'], f"Domain[{index}]")
|
|
316
341
|
else:
|
|
317
|
-
|
|
318
|
-
self.compare_one_content(comparator, expected, content[index], index)
|
|
342
|
+
raise ValueError(f"unknown expected_value type: {type(expected_value)}")
|
|
319
343
|
|
|
320
|
-
|
|
321
|
-
def compare_one_metric(expected: Metric, result: Metric):
|
|
344
|
+
def compare_one_metric(self, expected: Metric, result: Metric):
|
|
322
345
|
assert expected.name == result.name
|
|
323
346
|
assert_equal_with_label(expected.value, result.value, expected.name)
|
|
324
347
|
assert_keys_and_values(expected.tags, result.tags)
|