Skip to content

Commit f82c32b

Browse files
authored
Merge pull request #636 from splunk/dev/MP/modularinput-e2e-test
DVPL-12515: Add modular input E2E test
2 parents de7e883 + dc066cc commit f82c32b

File tree

6 files changed

+169
-0
lines changed

6 files changed

+169
-0
lines changed

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ services:
2222
- "./tests/system/test_apps/generating_app:/opt/splunk/etc/apps/generating_app"
2323
- "./tests/system/test_apps/reporting_app:/opt/splunk/etc/apps/reporting_app"
2424
- "./tests/system/test_apps/streaming_app:/opt/splunk/etc/apps/streaming_app"
25+
- "./tests/system/test_apps/modularinput_app:/opt/splunk/etc/apps/modularinput_app"
2526
- "./splunklib:/opt/splunk/etc/apps/eventing_app/lib/splunklib"
2627
- "./splunklib:/opt/splunk/etc/apps/generating_app/lib/splunklib"
2728
- "./splunklib:/opt/splunk/etc/apps/reporting_app/lib/splunklib"
2829
- "./splunklib:/opt/splunk/etc/apps/streaming_app/lib/splunklib"
30+
- "./splunklib:/opt/splunk/etc/apps/modularinput_app/lib/splunklib"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[modularinput://<name>]
2+
3+
endpoint = <value>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright © 2011-2025 Splunk, Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"): you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
import sys
18+
import os
19+
from urllib import parse
20+
21+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
22+
from splunklib.modularinput import Scheme, Argument, Script, Event
23+
24+
25+
class ModularInput(Script):
26+
endpoint_arg = "endpoint"
27+
28+
def get_scheme(self):
29+
scheme = Scheme("modularinput")
30+
31+
scheme.use_external_validation = True
32+
scheme.use_single_instance = True
33+
34+
endpoint = Argument(self.endpoint_arg)
35+
endpoint.title = "URL"
36+
endpoint.data_type = Argument.data_type_string
37+
endpoint.description = "URL"
38+
endpoint.required_on_create = True
39+
scheme.add_argument(endpoint)
40+
41+
return scheme
42+
43+
def validate_input(self, definition):
44+
url = definition.parameters[self.endpoint_arg]
45+
parsed = parse.urlparse(url)
46+
if parsed.scheme != "https":
47+
raise ValueError(f"non-supported scheme {parsed.scheme}")
48+
49+
def stream_events(self, inputs, ew):
50+
for input_name, input_item in list(inputs.inputs.items()):
51+
event = Event()
52+
event.stanza = input_name
53+
event.data = "example message"
54+
ew.write_event(event)
55+
56+
57+
if __name__ == "__main__":
58+
sys.exit(ModularInput().run(sys.argv))
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[install]
2+
is_configured = 0
3+
4+
[ui]
5+
is_visible = 1
6+
label = Modular Input test app
7+
8+
[launcher]
9+
author=Splunk
10+
description=Modular input test app
11+
version = 1.0
12+
13+
[package]
14+
check_for_updates = false
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[modularinput]
2+
python.version = python3

tests/system/test_modularinput_app.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright © 2011-2025 Splunk, Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"): you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
from splunklib import results
18+
from tests import testlib
19+
from splunklib.binding import HTTPError
20+
21+
22+
class ModularInput(testlib.SDKTestCase):
23+
index_name = "test_modular_input"
24+
input_name = "test_modular_input"
25+
input_kind = "modularinput"
26+
27+
def setUp(self):
28+
super().setUp()
29+
30+
app_found = False
31+
for kind in self.service.modular_input_kinds:
32+
if kind.name == self.input_kind:
33+
app_found = True
34+
35+
self.assertTrue(app_found, f"{self.input_kind} modular input not installed")
36+
self.clean()
37+
38+
def tearDown(self):
39+
super().tearDown()
40+
self.clean()
41+
42+
def clean(self):
43+
for input in self.service.inputs:
44+
if input.name == self.input_name and input.kind == self.input_kind:
45+
self.service.inputs.delete(self.input_name, self.input_kind)
46+
47+
for index in self.service.indexes:
48+
if index.name == self.input_name:
49+
self.service.indexes.delete(self.input_name)
50+
51+
def test_modular_input(self):
52+
self.service.indexes.create(self.index_name)
53+
54+
self.service.inputs.create(
55+
self.input_name,
56+
self.input_kind,
57+
endpoint="https://example.com/api/endpoint",
58+
index=self.index_name,
59+
)
60+
61+
def query():
62+
stream = self.service.jobs.oneshot(
63+
f'search index="{self.index_name}"', output_mode="json"
64+
)
65+
reader = results.JSONResultsReader(stream)
66+
return list(reader)
67+
68+
# Wait until the modular input is executed by splunk.
69+
self.assertEventuallyTrue(lambda: len(query()) != 0, timeout=10)
70+
71+
items = query()
72+
self.assertTrue(len(items) == 1)
73+
self.assertEqual(items[0]["_raw"], "example message")
74+
75+
def test_external_validator(self):
76+
def create():
77+
self.service.inputs.create(
78+
self.input_name,
79+
self.input_kind,
80+
endpoint="http://example.com/api/endpoint",
81+
index=self.index_name,
82+
)
83+
84+
self.assertRaisesRegex(HTTPError, "non-supported scheme http", create)
85+
86+
87+
if __name__ == "__main__":
88+
import unittest
89+
90+
unittest.main()

0 commit comments

Comments
 (0)