Skip to content

Commit a856b1c

Browse files
committed
Add support for collection paging - mostly a matter of passing through the kwargs in a few places plus writing a bunch of new units for the feature.
1 parent aededac commit a856b1c

File tree

3 files changed

+122
-11
lines changed

3 files changed

+122
-11
lines changed

splunklib/client.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ def __init__(self, service, path, item=None, ctor=None, dtor=None):
221221
self.ctor = ctor # Item constructor
222222
self.dtor = dtor # Item desteructor
223223

224-
def __call__(self):
225-
return self.list()
224+
def __call__(self, **kwargs):
225+
return self.list(**kwargs)
226226

227227
def __contains__(self, name):
228228
return self.contains(name)
@@ -277,10 +277,9 @@ def itemmeta(self):
277277
'eai:attributes': content['eai:attributes']
278278
}
279279

280-
def list(self, **kwargs):
281-
"""Returns a list of collection members."""
282-
count = kwargs.get('count', -1)
283-
response = self.get(count=count)
280+
# kwargs: count, offset, search, sort_dir, sort_key, sort_mode
281+
def list(self, count=0, **kwargs):
282+
response = self.get(count=count, **kwargs)
284283
return self._load_list(response)
285284

286285
# kwargs: path, app, owner, sharing, state
@@ -535,7 +534,7 @@ def list(self, *args):
535534
for kind in kinds:
536535
response = None
537536
try:
538-
response = self.service.get(self.kindpath(kind), count=-1)
537+
response = self.service.get(self.kindpath(kind), count=0)
539538
except HTTPError as e:
540539
if e.status == 404:
541540
continue # No inputs of this kind
@@ -643,17 +642,16 @@ class Jobs(Collection):
643642
def __init__(self, service):
644643
Collection.__init__(self, service, PATH_JOBS, item=Job)
645644

645+
def __iter__(self):
646+
for item in self.list(): yield item
647+
646648
def create(self, query, **kwargs):
647649
response = self.post(search=query, **kwargs)
648650
if kwargs.get("exec_mode", None) == "oneshot":
649651
return response.body
650652
sid = _load_atom(response).response.sid
651653
return Job(self.service, PATH_JOBS + sid)
652654

653-
def list(self, **kwargs):
654-
"""Returns a list of search Job entities."""
655-
return self._load_list(self.get()) # No count argument allowed
656-
657655
class Message(Entity):
658656
def __init__(self, service, name, **kwargs):
659657
Entity.__init__(self, service, _path(PATH_MESSAGES, name), **kwargs)

tests/runtests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
files = [
2525
"test_data.py",
2626
"test_binding.py",
27+
"test_collection.py",
2728
"test_client.py",
2829
"test_examples.py",
2930
]

tests/test_collection.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright 2011-2012 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 unittest
19+
20+
import splunklib.client as client
21+
from utils import parse
22+
23+
opts = None # Command line options
24+
25+
class TestCase(unittest.TestCase):
26+
def setUp(self):
27+
self.service = client.connect(**opts.kwargs)
28+
29+
# Verify that the given collections interface behaves as expected
30+
def check_collection(self, collection):
31+
# Check various collection options
32+
collection.list() # Default
33+
collection.list(search="title=*")
34+
collection.list(sort_dir="asc")
35+
collection.list(sort_dir="desc")
36+
collection.list(sort_mode="auto")
37+
collection.list(sort_mode="alpha")
38+
collection.list(sort_mode="alpha_case")
39+
collection.list(sort_mode="num")
40+
41+
# Retrieve the entire list
42+
items = collection.list()
43+
total = len(items)
44+
45+
# Make sure the default list method returns all items
46+
items0 = collection.list(count=0)
47+
total0 = len(items0)
48+
self.assertEqual(total, total0)
49+
50+
self.check_iterable(collection, total)
51+
52+
# Page through contents one-at-a-time and check count
53+
count = 0
54+
for i in xrange(total):
55+
item = collection.list(offset=i, count=1)
56+
count += 1
57+
self.assertEqual(count, total)
58+
59+
# Page through the collection using various page sizes and make sure
60+
# the expected paging invariants hold.
61+
page_size = int(total/2)
62+
while page_size > 0:
63+
offset = 0
64+
while offset < total:
65+
page = collection.list(offset=offset, count=page_size)
66+
count = len(page)
67+
offset += count
68+
self.assertTrue(count == page_size or offset == total)
69+
self.assertEqual(offset, total)
70+
page_size = int(page_size/2) # Try half the page size
71+
72+
# Verify that the given collection's iterator works as expected.
73+
def check_iterable(self, collection, count):
74+
# Iterate contents and make sure we see the expected count.
75+
seen = 0
76+
for item in collection:
77+
seen += 1
78+
self.assertEqual(seen, count)
79+
80+
def test_apps(self):
81+
self.check_collection(self.service.apps)
82+
83+
def test_indexes(self):
84+
self.check_collection(self.service.indexes)
85+
86+
def test_inputs(self):
87+
# The Inputs collection is an aggregated view of the various REST API
88+
# input endpoints, and does not support the paging interface.
89+
count = len(self.service.inputs.list())
90+
self.check_iterable(self.service.inputs, count)
91+
92+
def test_jobs(self):
93+
# The Jobs REST API endpoint does not support the paging interface.
94+
count = len(self.service.jobs.list())
95+
self.check_iterable(self.service.jobs, count)
96+
97+
def test_loggers(self):
98+
self.check_collection(self.service.loggers)
99+
100+
def test_messages(self):
101+
self.check_collection(self.service.messages)
102+
103+
def test_roles(self):
104+
self.check_collection(self.service.roles)
105+
106+
def test_users(self):
107+
self.check_collection(self.service.users)
108+
109+
if __name__ == "__main__":
110+
opts = parse(sys.argv[1:], {}, ".splunkrc")
111+
unittest.main(argv=sys.argv[:1])
112+

0 commit comments

Comments
 (0)