Skip to content

Commit 7f3787d

Browse files
feat: generate requirement test for other mappings (#883)
- Added support of generating requirement tests for other_mappings - Added/Updated e2e tests for requirement tests generation - Added/Updated unit tests
1 parent f44907c commit 7f3787d

File tree

8 files changed

+311
-5
lines changed

8 files changed

+311
-5
lines changed

pytest_splunk_addon/fields_tests/test_generator.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,19 @@ def generate_requirements_tests(self):
250250
}
251251

252252
cim_fields = event.requirement_test_data.get("cim_fields", {})
253+
other_fields = event.requirement_test_data.get("other_fields", {})
254+
requirement_fields = {**cim_fields, **other_fields}
253255

254-
if cim_fields:
255-
cim_fields = {
256+
if requirement_fields:
257+
requirement_fields = {
256258
field: value
257-
for field, value in cim_fields.items()
259+
for field, value in requirement_fields.items()
258260
if field not in exceptions
259261
}
260262
yield pytest.param(
261263
{
262264
"escaped_event": escaped_event,
263-
"fields": cim_fields,
265+
"fields": requirement_fields,
264266
"modinput_params": modinput_params,
265267
},
266268
id=f"sample_name::{event.sample_name}::host::{event.metadata.get('host')}",

pytest_splunk_addon/sample_generation/sample_stanza.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,16 @@ def populate_requirement_test_data(event):
398398
"""
399399
requirement_test_data = {}
400400
cim = event.get("cim")
401+
other_mappings = event.get("other_mappings")
402+
if other_mappings:
403+
other_fields = {}
404+
fields = other_mappings["field"]
405+
if type(fields) == list:
406+
for field in fields:
407+
other_fields[field["@name"]] = field["@value"]
408+
elif type(fields) == dict:
409+
other_fields[fields["@name"]] = fields["@value"]
410+
requirement_test_data["other_fields"] = other_fields
401411
if cim:
402412
requirement_test_data["cim_version"] = cim.get("@version", "latest")
403413
requirement_test_data["datamodels"] = cim.get("models") or {}

tests/e2e/addons/TA_req_broken/samples/sample_modinput.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,32 @@
102102
</missing_recommended_fields>
103103
</cim>
104104
</event>
105+
<event code="" name="WrongFieldValueOtherMappings" format="">
106+
<transport type="modinput" sourcetype="test:data:1" source="test_data.1" host="so1"/>
107+
<source>
108+
<jira id=""/>
109+
<comment>lab</comment>
110+
</source>
111+
<raw>
112+
<![CDATA[2021-12-31 15:15:30,340+0000 action=success app=psa user=admin status=success dest=10.0.0.1 src=10.0.0.2]]></raw>
113+
<cim>
114+
<models>
115+
<model>Authentication</model>
116+
</models>
117+
<cim_fields>
118+
<field name="action" value="success"/>
119+
<field name="status" value="success"/>
120+
<field name="app" value="psa"/>
121+
<field name="src" value="10.0.0.2"/>
122+
<field name="user" value="admin"/>
123+
<field name="dest" value="10.0.0.1"/>
124+
</cim_fields>
125+
<missing_recommended_fields>
126+
<field>src_user</field>
127+
</missing_recommended_fields>
128+
</cim>
129+
<other_mappings>
130+
<field name="vendor_product" value="PSA"/>
131+
</other_mappings>
132+
</event>
105133
</device>

tests/e2e/addons/TA_transition_from_req/default/props.conf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ FIELDALIAS-action = result AS action
1010
EVAL-app = "psa"
1111
FIELDALIAS-user = tester AS user
1212
FIELDALIAS-src = ip AS src
13-
EVAL-status = case(action=="success", "PASS", action=="failure", "FAIL", 0==0, "OTHER")
13+
EVAL-status = case(action=="success", "PASS", action=="failure", "FAIL", 0==0, "OTHER")
14+
EVAL-vendor_product = "Pytest Splunk Addon"

tests/e2e/addons/TA_transition_from_req/samples/sample_modinput.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,8 @@
2626
<field>src_user</field>
2727
</missing_recommended_fields>
2828
</cim>
29+
<other_mappings>
30+
<field name="vendor_product" value="Pytest Splunk Addon"/>
31+
</other_mappings>
2932
</event>
3033
</device>

tests/e2e/constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@
798798
"*test_splunk_app_req.py::Test_App::test_props_fields[test:data:1::field::status* PASSED*",
799799
"*test_splunk_app_req.py::Test_App::test_props_fields[test:data:1::field::tester* PASSED*",
800800
"*test_splunk_app_req.py::Test_App::test_props_fields[test:data:1::field::user* PASSED*",
801+
"*test_splunk_app_req.py::Test_App::test_props_fields[test:data:1::field::vendor_product* PASSED*",
801802
"*test_splunk_app_req.py::Test_App::test_requirements_fields[sample_name::sample_modinput.xml::host::so1-4* PASSED*",
802803
"*test_splunk_app_req.py::Test_App::test_requirements_fields[sample_name::sample_modinput.xml::host::so1-5* PASSED*",
803804
"*test_splunk_app_req.py::Test_App::test_requirements_fields[sample_name::sample_modinput.xml::host::so1-6* PASSED*",
@@ -811,6 +812,7 @@
811812
"*test_splunk_app_req.py::Test_App::test_props_fields_no_dash_not_empty[test:data:1::field::status* PASSED*",
812813
"*test_splunk_app_req.py::Test_App::test_props_fields_no_dash_not_empty[test:data:1::field::tester* PASSED*",
813814
"*test_splunk_app_req.py::Test_App::test_props_fields_no_dash_not_empty[test:data:1::field::user* PASSED*",
815+
"*test_splunk_app_req.py::Test_App::test_props_fields_no_dash_not_empty[test:data:1::field::vendor_product* PASSED*",
814816
"*test_splunk_app_req.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so1-4* PASSED*",
815817
"*test_splunk_app_req.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so1-5* PASSED*",
816818
"*test_splunk_app_req.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so1-6* PASSED*",
@@ -836,6 +838,7 @@
836838
"*test_splunk_app_req_broken.py::Test_App::test_indextime_time[req:test:broken::so11* PASSED*",
837839
"*test_splunk_app_req_broken.py::Test_App::test_indextime_time[req:test:broken::so12* PASSED*",
838840
"*test_splunk_app_req_broken.py::Test_App::test_indextime_time[req:test:broken::so13* PASSED*",
841+
"*test_splunk_app_req_broken.py::Test_App::test_indextime_time[req:test:broken::so14* PASSED*",
839842
"*test_splunk_app_req_broken.py::Test_App::test_indextime_line_breaker[juniper:junos:firewall::syslog.xml* PASSED*",
840843
"*test_splunk_app_req_broken.py::Test_App::test_indextime_line_breaker[req:test:broken::sample_modinput.xml* PASSED*",
841844
'*test_splunk_app_req_broken.py::Test_App::test_cim_required_fields[eventtype="net"::All_Traffic* PASSED*',
@@ -882,6 +885,7 @@
882885
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Authentication-::sample_name::sample_modinput.xml::host::so10* PASSED*",
883886
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Authentication-::sample_name::sample_modinput.xml::host::so12* PASSED*",
884887
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Authentication-::sample_name::sample_modinput.xml::host::so13* PASSED*",
888+
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Authentication-::sample_name::sample_modinput.xml::host::so14* PASSED*",
885889
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Network_Traffic-::sample_name::syslog.xml::host::10.0.0.30* PASSED*",
886890
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Network_Traffic-::sample_name::syslog.xml::host::10.0.0.31* PASSED*",
887891
"*test_splunk_app_req_broken.py::Test_App::test_splunk_internal_errors PASSED*",
@@ -897,6 +901,7 @@
897901
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so11* PASSED*",
898902
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so12* PASSED*",
899903
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so13* PASSED*",
904+
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Authentication::sample_name::sample_modinput.xml::host::so14* PASSED*",
900905
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Network_Traffic::sample_name::syslog.xml::host::10.0.0.30* PASSED*",
901906
"*test_splunk_app_req_broken.py::Test_App::test_eventtype[eventtype::net* PASSED*",
902907
"*test_splunk_app_req_broken.py::Test_App::test_eventtype[eventtype::test_auth* PASSED*",
@@ -913,6 +918,7 @@
913918
'*test_splunk_app_req_broken.py::Test_App::test_cim_required_fields[eventtype="net"::All_Traffic::src_zone* FAILED*',
914919
'*test_splunk_app_req_broken.py::Test_App::test_cim_required_fields[eventtype="net"::Blocked_Traffic* FAILED*',
915920
"*test_splunk_app_req_broken.py::Test_App::test_requirements_fields[sample_name::sample_modinput.xml::host::so13* FAILED*",
921+
"*test_splunk_app_req_broken.py::Test_App::test_requirements_fields[sample_name::sample_modinput.xml::host::so14* FAILED*",
916922
"*test_splunk_app_req_broken.py::Test_App::test_cim_fields_recommended[Authentication-::sample_name::sample_modinput.xml::host::so11* FAILED*",
917923
"*test_splunk_app_req_broken.py::Test_App::test_datamodels[Network_Traffic::sample_name::syslog.xml::host::10.0.0.31* FAILED*",
918924
]

tests/unit/tests_standard_lib/test_fields_tests/test_test_generator.py

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from pytest_splunk_addon.fields_tests.test_generator import (
44
FieldTestGenerator,
55
)
6+
from pytest_splunk_addon.sample_generation.sample_event import SampleEvent
7+
from pytest_splunk_addon.utilities import xml_event_parser
68

79

810
def field_1():
@@ -71,6 +73,14 @@ def test_field_test_generator_instantiation(addon_parser_mock):
7173
"splunk_searchtime_fields_savedsearches",
7274
"GENERATE_SAVEDSEARCHES_TESTS_RETURN_VALUE",
7375
),
76+
(
77+
"splunk_searchtime_fields_requirements",
78+
"GENERATE_REQUIREMENT_TESTS_RETURN_VALUE",
79+
),
80+
(
81+
"splunk_searchtime_fields_datamodels",
82+
"GENERATE_REQUIREMENT_DATAMODEL_TESTS_RETURN_VALUE",
83+
),
7484
],
7585
)
7686
def test_generate_tests(addon_parser_mock, fixture_name, expected_ouptput):
@@ -90,6 +100,14 @@ def test_generate_tests(addon_parser_mock, fixture_name, expected_ouptput):
90100
FieldTestGenerator,
91101
"generate_savedsearches_tests",
92102
return_value=(["GENERATE_SAVEDSEARCHES_TESTS_RETURN_VALUE"]),
103+
), patch.object(
104+
FieldTestGenerator,
105+
"generate_requirements_tests",
106+
return_value=(["GENERATE_REQUIREMENT_TESTS_RETURN_VALUE"]),
107+
), patch.object(
108+
FieldTestGenerator,
109+
"generate_requirements_datamodels_tests",
110+
return_value=(["GENERATE_REQUIREMENT_DATAMODEL_TESTS_RETURN_VALUE"]),
93111
):
94112
assert list(
95113
FieldTestGenerator(
@@ -391,3 +409,190 @@ def test_generate_field_tests(
391409
)
392410
assert out == expected_output
393411
assert param_mock.call_count == len(expected_output)
412+
413+
414+
@pytest.mark.parametrize(
415+
"tokenised_events, expected_output",
416+
[
417+
(
418+
[
419+
SampleEvent(
420+
event_string="escaped_event",
421+
metadata={
422+
"input_type": "modinput",
423+
"sourcetype_to_search": "dummy_sourcetype",
424+
"host": "dummy_host",
425+
},
426+
sample_name="file1.xml",
427+
requirement_test_data={
428+
"cim_fields": {
429+
"dest": "192.168.0.1",
430+
"severity": "low",
431+
"signature_id": "405001",
432+
"src": "192.168.0.1",
433+
"type": "event",
434+
},
435+
"exceptions": {"mane_1": "value_1", "dest": "192.168.0.1"},
436+
"other_fields": {
437+
"vendor_product": "Pytest Splunk Addon",
438+
"target_users": "[email protected]",
439+
},
440+
},
441+
),
442+
SampleEvent(
443+
event_string="escaped_event",
444+
metadata={
445+
"input_type": "syslog_tcp",
446+
"sourcetype_to_search": "dummy_sourcetype",
447+
"host": "dummy_host_syslog",
448+
},
449+
sample_name="file1.xml",
450+
requirement_test_data={},
451+
),
452+
SampleEvent(
453+
event_string="escaped_event",
454+
metadata={
455+
"input_type": "syslog_tcp",
456+
"sourcetype_to_search": "dummy_sourcetype",
457+
"host": "dummy_host_syslog",
458+
},
459+
sample_name="file1.xml",
460+
requirement_test_data={
461+
"cim_fields": {
462+
"src": "192.168.0.1",
463+
"type": "event",
464+
},
465+
"exceptions": {},
466+
"other_fields": {
467+
"vendor_product": "Pytest Splunk Addon",
468+
"target_users": "[email protected]",
469+
},
470+
},
471+
),
472+
],
473+
[
474+
(
475+
{
476+
"escaped_event": "escaped_event",
477+
"fields": {
478+
"severity": "low",
479+
"signature_id": "405001",
480+
"src": "192.168.0.1",
481+
"type": "event",
482+
"vendor_product": "Pytest Splunk Addon",
483+
"target_users": "[email protected]",
484+
},
485+
"modinput_params": {"sourcetype": "dummy_sourcetype"},
486+
},
487+
"sample_name::file1.xml::host::dummy_host",
488+
),
489+
(
490+
{
491+
"escaped_event": "escaped_event",
492+
"fields": {
493+
"src": "192.168.0.1",
494+
"type": "event",
495+
"vendor_product": "Pytest Splunk Addon",
496+
"target_users": "[email protected]",
497+
},
498+
"modinput_params": {"sourcetype": "dummy_sourcetype"},
499+
},
500+
"sample_name::file1.xml::host::dummy_host_syslog",
501+
),
502+
],
503+
),
504+
],
505+
)
506+
def test_generate_requirement_tests(tokenised_events, expected_output):
507+
with patch.object(
508+
xml_event_parser, "strip_syslog_header", return_value="escaped_event"
509+
), patch.object(
510+
xml_event_parser, "escape_char_event", return_value="escaped_event"
511+
), patch.object(
512+
pytest, "param", side_effect=lambda x, id: (x, id)
513+
) as param_mock:
514+
out = list(
515+
FieldTestGenerator(
516+
"app_path",
517+
tokenised_events,
518+
"field_bank",
519+
).generate_requirements_tests()
520+
)
521+
assert out == expected_output
522+
assert param_mock.call_count == len(expected_output)
523+
524+
525+
@pytest.mark.parametrize(
526+
"tokenised_events, expected_output",
527+
[
528+
(
529+
[
530+
SampleEvent(
531+
event_string="escaped_event",
532+
metadata={
533+
"input_type": "modinput",
534+
"sourcetype_to_search": "dummy_sourcetype",
535+
"host": "dummy_host",
536+
},
537+
sample_name="file1.xml",
538+
requirement_test_data={"datamodels": {"model": "Alerts"}},
539+
),
540+
SampleEvent(
541+
event_string="escaped_event",
542+
metadata={
543+
"input_type": "syslog_tcp",
544+
"sourcetype_to_search": "dummy_sourcetype",
545+
"host": "dummy_host_syslog",
546+
},
547+
sample_name="file1.xml",
548+
requirement_test_data={},
549+
),
550+
SampleEvent(
551+
event_string="escaped_event",
552+
metadata={
553+
"input_type": "syslog_tcp",
554+
"sourcetype_to_search": "dummy_sourcetype",
555+
"host": "dummy_host_syslog",
556+
},
557+
sample_name="file1.xml",
558+
requirement_test_data={
559+
"datamodels": {"model": ["Change", "Account Management"]}
560+
},
561+
),
562+
],
563+
[
564+
(
565+
{
566+
"datamodels": ["Alerts"],
567+
"stanza": "escaped_event",
568+
},
569+
"Alerts::sample_name::file1.xml::host::dummy_host",
570+
),
571+
(
572+
{
573+
"datamodels": ["Change", "Account_Management"],
574+
"stanza": "escaped_event",
575+
},
576+
"Change-Account_Management::sample_name::file1.xml::host::dummy_host_syslog",
577+
),
578+
],
579+
),
580+
],
581+
)
582+
def test_generate_requirement_datamodel_tests(tokenised_events, expected_output):
583+
with patch.object(
584+
xml_event_parser, "strip_syslog_header", return_value="escaped_event"
585+
), patch.object(
586+
xml_event_parser, "escape_char_event", return_value="escaped_event"
587+
), patch.object(
588+
pytest, "param", side_effect=lambda x, id: (x, id)
589+
) as param_mock:
590+
out = list(
591+
FieldTestGenerator(
592+
"app_path",
593+
tokenised_events,
594+
"field_bank",
595+
).generate_requirements_datamodels_tests()
596+
)
597+
assert out == expected_output
598+
assert param_mock.call_count == len(expected_output)

0 commit comments

Comments
 (0)