Skip to content

Commit 818a948

Browse files
committed
Add cre_apps system tests
1 parent 6f0af2d commit 818a948

File tree

6 files changed

+155
-1
lines changed

6 files changed

+155
-1
lines changed

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ services:
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"
2525
- "./tests/system/test_apps/modularinput_app:/opt/splunk/etc/apps/modularinput_app"
26+
- "./tests/system/test_apps/cre_app:/opt/splunk/etc/apps/cre_app"
2627
- "./splunklib:/opt/splunk/etc/apps/eventing_app/bin/splunklib"
2728
- "./splunklib:/opt/splunk/etc/apps/generating_app/bin/splunklib"
2829
- "./splunklib:/opt/splunk/etc/apps/reporting_app/bin/splunklib"

splunklib/binding.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ class Context:
511511
:param headers: List of extra HTTP headers to send (optional).
512512
:type headers: ``list`` of 2-tuples.
513513
:param retries: Number of retries for each HTTP connection (optional, the default is 0).
514-
NOTE: THIS MAY INCREASE THE NUMBER OF ROUNDTRIP CONNECTIONS
514+
NOTE: THIS MAY INCREASE THE NUMBER OF ROUNDTRIP CONNECTIONS
515515
TO THE SPLUNK SERVER AND BLOCK THE CURRENT THREAD WHILE RETRYING.
516516
:type retries: ``int``
517517
:param retryDelay: How long to wait between connection attempts if `retries` > 0 (optional, defaults to 10s).
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import splunk.rest
2+
import json
3+
4+
5+
class Handler(splunk.rest.BaseRestHandler):
6+
def handle_GET(self):
7+
self.response.setHeader("Content-Type", "application/json")
8+
self.response.setHeader("x-foo", "bar")
9+
self.response.status = 200
10+
self.response.write(
11+
json.dumps(
12+
{
13+
"headers": self.headers(),
14+
"method": "GET",
15+
}
16+
)
17+
)
18+
19+
def handle_DELETE(self):
20+
self.handle_with_payload("DELETE")
21+
22+
def handle_POST(self):
23+
self.handle_with_payload("POST")
24+
25+
def handle_PUT(self):
26+
self.handle_with_payload("PUT")
27+
28+
def handle_PATCH(self):
29+
self.handle_with_payload("PATCH")
30+
31+
def handle_with_payload(self, method):
32+
self.response.setHeader("Content-Type", "application/json")
33+
self.response.setHeader("x-foo", "bar")
34+
self.response.status = 200
35+
self.response.write(
36+
json.dumps(
37+
{
38+
"payload": self.request.get("payload"),
39+
"headers": self.headers(),
40+
"method": method,
41+
}
42+
)
43+
)
44+
45+
def headers(self):
46+
return {
47+
k: v
48+
for k, v in self.request.get("headers", {}).items()
49+
if k.lower().startswith("x")
50+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[id]
2+
name = cre_app
3+
version = 0.1.0
4+
5+
[package]
6+
id = cre_app
7+
check_for_updates = False
8+
9+
[install]
10+
is_configured = 0
11+
state = enabled
12+
13+
[ui]
14+
is_visible = 1
15+
label = [EXAMPLE] CRE app
16+
17+
[launcher]
18+
description = Example app that exposes custom rest endpoints
19+
version = 0.0.1
20+
author = Splunk
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[script:execute]
2+
match = /execute
3+
scripttype = python
4+
handler = execute.Handler
5+

tests/system/test_cre_apps.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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 json
18+
import pytest
19+
20+
from tests import testlib
21+
from splunklib import results
22+
23+
24+
@pytest.mark.smoke
25+
class TestJSONCustomRestEndpointsApp(testlib.SDKTestCase):
26+
app_name = "cre_app"
27+
28+
def test_GET(self):
29+
resp = self.service.get(
30+
app=self.app_name,
31+
path_segment="execute",
32+
headers=[("x-bar", "baz")],
33+
)
34+
self.assertIn(("x-foo", "bar"), resp.headers)
35+
self.assertEqual(resp.status, 200)
36+
self.assertEqual(
37+
json.loads(str(resp.body)),
38+
{
39+
"headers": {"x-bar": "baz"},
40+
"method": "GET",
41+
},
42+
)
43+
44+
def test_POST(self):
45+
body = json.dumps({"foo": "bar"})
46+
resp = self.service.post(
47+
app=self.app_name,
48+
path_segment="execute",
49+
body=body,
50+
headers=[("x-bar", "baz")],
51+
)
52+
self.assertIn(("x-foo", "bar"), resp.headers)
53+
self.assertEqual(resp.status, 200)
54+
self.assertEqual(
55+
json.loads(str(resp.body)),
56+
{
57+
"payload": '{"foo": "bar"}',
58+
"headers": {"x-bar": "baz"},
59+
"method": "POST",
60+
},
61+
)
62+
63+
def test_DELETE(self):
64+
# delete does allow specifying body and custom headers.
65+
resp = self.service.delete(
66+
app=self.app_name,
67+
path_segment="execute",
68+
)
69+
self.assertIn(("x-foo", "bar"), resp.headers)
70+
self.assertEqual(resp.status, 200)
71+
self.assertEqual(
72+
json.loads(str(resp.body)),
73+
{
74+
"payload": "",
75+
"headers": {},
76+
"method": "DELETE",
77+
},
78+
)

0 commit comments

Comments
 (0)