Skip to content

Commit 0d487fe

Browse files
author
Frederick Ross
committed
Fix set_priority tests on job. Refactor all tests to use assertEventuallyEqual and assertEventuallyTrue instead of previous forms.
Add better control of restarts in the suite and checking if restarts are required.
1 parent 9faf735 commit 0d487fe

File tree

11 files changed

+197
-147
lines changed

11 files changed

+197
-147
lines changed

splunklib/client.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,19 @@ def restart(self, timeout=None):
446446
sleep(2)
447447
raise Exception, "Operation timed out."
448448

449+
@property
450+
def restart_required(self):
451+
"""Is splunkd in a state that requires a restart?"""
452+
response = self.get("messages").body.read()
453+
messages = data.load(response)['feed']
454+
if 'entry' not in messages:
455+
titles = []
456+
elif isinstance(messages['entry'], dict):
457+
titles = [messages['entry']['title']]
458+
else:
459+
titles = [x['title'] for x in messages['entry']]
460+
return 'restart_required' in titles
461+
449462
@property
450463
def roles(self):
451464
"""Returns a collection of user roles."""
@@ -2040,7 +2053,7 @@ def refresh(self, state=None):
20402053
raw_state = self._load_state(response)
20412054
raw_state['links'] = dict([(k, urllib.unquote(v)) for k,v in raw_state['links'].iteritems()])
20422055
self._state = raw_state
2043-
return self
2056+
return self
20442057

20452058
def results(self, timeout=None, wait_time=1, **query_params):
20462059
"""Fetch search results as an InputStream IO handle.
@@ -2151,6 +2164,10 @@ def searchlog(self, **kwargs):
21512164
def set_priority(self, value):
21522165
"""Sets this job's search priority in the range of 0-10.
21532166
2167+
Higher numbers indicate higher priority. Unless splunkd is
2168+
running as root, you can only decrease the priority of
2169+
a running job.
2170+
21542171
:param `value`: The search priority.
21552172
"""
21562173
self.post('control', action="setpriority", priority=value)

tests/test_app.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
class TestApp(testlib.SDKTestCase):
2424
app = None
2525
app_name = None
26+
2627
def setUp(self):
2728
super(TestApp, self).setUp()
2829
if self.app is None:
@@ -39,13 +40,17 @@ def setUp(self):
3940
else:
4041
logging.debug("App %s already exists. Skipping creation.", self.app_name)
4142

42-
@classmethod
43-
def tearDownClass(cls):
44-
import splunklib.client as client
45-
service = client.connect(**cls.opts.kwargs)
46-
for app in service.apps:
47-
if app.name.startswith('delete-me'):
48-
service.apps.delete(app.name)
43+
def tearDown(self):
44+
super(TestApp, self).tearDown()
45+
# The rest of this will leave Splunk in a state requiring a restart.
46+
# It doesn't actually matter, though.
47+
self.service = client.connect(**self.opts.kwargs)
48+
for app in self.service.apps:
49+
app_name = app.name
50+
if app_name.startswith('delete-me'):
51+
self.service.apps.delete(app_name)
52+
self.assertEventuallyTrue(lambda: app_name not in self.service.apps)
53+
self.clearRestartMessage()
4954

5055
def test_app_integrity(self):
5156
self.check_entity(self.app)
@@ -81,6 +86,7 @@ def test_delete(self):
8186
self.assertTrue(name in self.service.apps)
8287
self.service.apps.delete(name)
8388
self.assertFalse(name in self.service.apps)
89+
self.clearRestartMessage() # We don't actually have to restart here.
8490

8591
def test_package(self):
8692
p = self.app.package()

tests/test_conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def test_confs(self):
7979
key = testlib.tmpname()
8080
val = testlib.tmpname()
8181
stanza.update(**{key: val})
82-
testlib.retry(stanza, lambda s: len(s), 1, step=0.2)
82+
self.assertEventuallyEqual(1, lambda: stanza.refresh() and len(stanza), pause_time=0.2)
8383
self.assertEqual(len(stanza), 1)
8484
self.assertTrue(key in stanza)
8585

tests/test_examples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def test_analytics(self):
283283
tracker.track("test_event", distinct_id="123abc", abc="12345")
284284

285285
# Wait until the events get indexed
286-
testlib.wait(index, lambda index: index['totalEventCount'] == '2')
286+
self.assertEventuallyEqual('2', lambda: index.refresh()['totalEventCount'])
287287

288288
# Now, we create a retriever to retrieve the events
289289
retriever = analytics.output.AnalyticsRetriever(

tests/test_fired_alert.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,22 @@ def test_new_search_is_empty(self):
5959
def test_alerts_on_events(self):
6060
self.assertEqual(self.saved_search.alert_count, 0)
6161
self.assertEqual(len(self.saved_search.fired_alerts), 0)
62+
6263
self.index.enable()
63-
testlib.retry(self.index, 'disabled', '0', step=0.5, times=50)
64+
self.assertEventuallyEqual('0', lambda: self.index.refresh() and self.index['disabled'], timeout=25)
65+
6466
eventCount = int(self.index['totalEventCount'])
6567
self.assertEqual(self.index['sync'], '0')
6668
self.assertEqual(self.index['disabled'], '0')
6769
self.index.refresh()
6870
self.index.submit('This is a test ' + testlib.tmpname(),
6971
sourcetype='sdk_use', host='boris')
70-
testlib.retry(self.index, 'totalEventCount', str(eventCount+1), step=1, times=50)
71-
self.assertEqual(self.index['totalEventCount'], str(eventCount+1))
72-
testlib.retry(self.saved_search, lambda s: s.alert_count, 1, step=2, times=100)
73-
self.assertEqual(self.saved_search.alert_count, 1)
72+
self.assertEventuallyEqual(str(eventCount+1), lambda: self.index.refresh() and self.index['totalEventCount'], timeout=50)
73+
self.assertEventuallyEqual(
74+
1,
75+
lambda: self.saved_search.refresh() and self.saved_search.alert_count,
76+
timeout=200
77+
)
7478
alerts = self.saved_search.fired_alerts
7579
self.assertEqual(len(alerts), 1)
7680

tests/test_index.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def setUp(self):
2727
super(IndexTest, self).setUp()
2828
self.index_name = testlib.tmpname()
2929
self.index = self.service.indexes.create(self.index_name)
30+
self.assertEventuallyEqual('0', lambda: self.index.refresh()['disabled'])
3031

3132
def tearDown(self):
3233
super(IndexTest, self).tearDown()
@@ -36,12 +37,17 @@ def tearDown(self):
3637
# clashes, though.
3738
if self.service.splunk_version >= (5,):
3839
self.service.indexes.delete(self.index_name)
40+
self.assertEventuallyTrue(lambda: self.index_name not in self.service.indexes)
3941
else:
4042
logging.warning("test_index.py:TestDeleteIndex: Skipped: cannot "
4143
"delete indexes via the REST API in Splunk 4.x")
4244

4345

4446
class IndexWithoutRestart(IndexTest):
47+
def totalEventCount(self):
48+
self.index.refresh()
49+
return int(self.index['totalEventCount'])
50+
4551
def test_integrity(self):
4652
self.check_entity(self.index)
4753

@@ -62,55 +68,41 @@ def test_submit_and_clean(self):
6268

6369
originalCount = int(self.index['totalEventCount'])
6470
self.index.submit("Hello again!", sourcetype="Boris", host="meep")
65-
testlib.retry(self.index, 'totalEventCount', str(originalCount+1), step=1)
66-
self.assertEqual(self.index['totalEventCount'], str(originalCount+1))
67-
71+
self.assertEventuallyEqual(originalCount+1, self.totalEventCount)
6872
self.index.clean(timeout=500)
6973
self.assertEqual(self.index['totalEventCount'], '0')
7074

71-
class IndexWithRestartTest(IndexTest):
72-
def setUp(self):
73-
super(IndexWithRestartTest, self).setUp()
74-
self.service.restart(timeout=300)
75-
self.index = self.service.indexes[self.index_name]
76-
7775
def test_prefresh(self):
78-
index = self.service.indexes[self.index_name]
7976
self.assertEqual(self.index['disabled'], '0') # Index is prefreshed
8077

8178
def test_submit(self):
8279
eventCount = int(self.index['totalEventCount'])
8380
self.assertEqual(self.index['sync'], '0')
8481
self.assertEqual(self.index['disabled'], '0')
8582
self.index.submit("Hello again!", sourcetype="Boris", host="meep")
86-
testlib.retry(self.index, 'totalEventCount', str(eventCount+1), step=1)
87-
self.assertEqual(self.index['totalEventCount'], str(eventCount+1))
83+
self.assertEventuallyEqual(eventCount+1, self.totalEventCount)
8884

8985
def test_submit_via_attach(self):
9086
eventCount = int(self.index['totalEventCount'])
9187
cn = self.index.attach()
9288
cn.send("Hello Boris!\r\n")
9389
cn.close()
94-
testlib.retry(self.index, 'totalEventCount', str(eventCount+1), step=1)
95-
self.index.refresh()
96-
self.assertEqual(self.index['totalEventCount'], str(eventCount+1))
90+
self.assertEventuallyEqual(eventCount+1, self.totalEventCount)
9791

9892
def test_submit_via_attached_socket(self):
9993
eventCount = int(self.index['totalEventCount'])
10094
f = self.index.attached_socket
10195
with f() as sock:
10296
sock.send('Hello world!\r\n')
103-
testlib.retry(self.index, 'totalEventCount', str(eventCount+1), step=1)
104-
self.assertEqual(self.index['totalEventCount'], str(eventCount+1))
97+
self.assertEventuallyEqual(eventCount+1, self.totalEventCount)
10598

10699
def test_upload(self):
107100
# The following test must run on machine where splunkd runs,
108101
# otherwise a failure is expected
109102
eventCount = int(self.index['totalEventCount'])
110103
testpath = path.dirname(path.abspath(__file__))
111104
self.index.upload(path.join(testpath, "testfile.txt"))
112-
testlib.retry(self.index, 'totalEventCount', str(eventCount+1), step=1)
113-
self.assertEqual(self.index['totalEventCount'], str(eventCount+1))
105+
self.assertEventuallyEqual(eventCount+1, self.totalEventCount)
114106

115107
if __name__ == "__main__":
116108
testlib.main()

tests/test_input.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,16 @@ def test_inputs_list_on_one_kind_with_search(self):
6161
def test_oneshot(self):
6262
index_name = testlib.tmpname()
6363
index = self.service.indexes.create(index_name)
64-
self.service.restart(timeout=120)
64+
self.restartSplunk(timeout=120)
6565
index = self.service.indexes[index_name]
6666
eventCount = int(index['totalEventCount'])
6767
from os import path
6868
testpath = path.dirname(path.abspath(__file__))
6969
self.service.inputs.oneshot(path.join(testpath, 'testfile.txt'), index=index_name)
70-
testlib.retry(index, 'totalEventCount', str(eventCount+1), step=1)
71-
self.assertEqual(index['totalEventCount'], str(eventCount+1))
70+
self.assertEventuallyEqual(
71+
str(eventCount+1),
72+
lambda: index.refresh()['totalEventCount']
73+
)
7274

7375
def test_oneshot_on_nonexistant_file(self):
7476
name = testlib.tmpname()

tests/test_job.py

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -88,34 +88,6 @@ def test_cancel_is_idempotent(self):
8888
job.cancel()
8989
job.cancel() # Second call should be nop
9090

91-
def test_enable_preview(self):
92-
query = "search index=_internal"
93-
job = self.service.jobs.create(
94-
query=query,
95-
earliest_time="-1m",
96-
latest_time="now")
97-
self.assertEqual(job['isPreviewEnabled'], '0')
98-
job.enable_preview()
99-
tries = 10
100-
while tries > 0:
101-
if job.is_done():
102-
self.fail('Job finished before preview enabled.')
103-
if job['isPreviewEnabled'] == '1':
104-
break
105-
tries -= 1
106-
self.assertEqual(job['isPreviewEnabled'], '1')
107-
job.disable_preview()
108-
tries = 10
109-
while tries > 0:
110-
if job.is_done():
111-
self.fail('Job finished before preview disabled.')
112-
if job['isPreviewEnabled'] == '0':
113-
break
114-
tries -= 1
115-
self.assertEqual(job['isPreviewEnabled'], '0')
116-
117-
118-
11991
def check_job(self, job):
12092
self.check_entity(job)
12193
keys = ['cursorTime', 'delegate', 'diskUsage', 'dispatchState',
@@ -139,11 +111,53 @@ def test_read_jobs(self):
139111
job.refresh()
140112
self.check_job(job)
141113

114+
class TestJobWithDelayedDone(testlib.SDKTestCase):
115+
def setUp(self):
116+
super(TestJobWithDelayedDone, self).setUp()
117+
self.installAppFromCollection("sleep_command")
118+
self.query = "search index=_internal | sleep done=100"
119+
self.job = self.service.jobs.create(
120+
query=self.query,
121+
earliest_time="-1m",
122+
priority=5,
123+
latest_time="now")
124+
125+
def tearDown(self):
126+
super(TestJobWithDelayedDone, self).tearDown()
127+
self.job.cancel()
128+
self.assertEventuallyTrue(lambda: self.job.sid not in self.service.jobs)
129+
130+
def test_enable_preview(self):
131+
self.assertEqual(self.job['isPreviewEnabled'], '0')
132+
self.job.enable_preview()
133+
def is_preview():
134+
if self.job.is_done():
135+
self.fail('Job finished before preview enabled.')
136+
return self.job['isPreviewEnabled'] == '1'
137+
self.assertEventuallyTrue(is_preview)
138+
139+
def test_setpriority(self):
140+
# Note that you can only *decrease* the priority (i.e., 5 decreased to 3)
141+
# of a job unless Splunk is running as root. This is because Splunk jobs
142+
# are tied up with operating system processes and their priorities.
143+
self.assertEqual(5, int(self.job['priority']))
144+
new_priority = 3
145+
self.job.set_priority(new_priority)
146+
def priority():
147+
if self.job.is_done():
148+
self.fail("Job already done before priority was set.")
149+
self.job.refresh()
150+
return int(self.job['priority'])
151+
self.assertEventuallyEqual(
152+
new_priority,
153+
priority,
154+
timeout=120
155+
)
142156

143157
class TestJob(testlib.SDKTestCase):
144158
def setUp(self):
145159
super(TestJob, self).setUp()
146-
self.query = "search index=_internal earliest=-1m | head 3"
160+
self.query = "search index=_internal | head 3"
147161
self.job = self.service.jobs.create(
148162
query=self.query,
149163
earliest_time="-1m",
@@ -155,7 +169,7 @@ def tearDown(self):
155169

156170
@log_duration
157171
def test_get_preview_and_events(self):
158-
testlib.retry(self.job, 'isDone', '1')
172+
self.assertEventuallyTrue(self.job.is_done)
159173
self.assertLessEqual(int(self.job['eventCount']), 3)
160174

161175
preview_stream = self.job.preview()
@@ -176,34 +190,28 @@ def test_pause(self):
176190
self.assertEqual(self.job['isPaused'], '0')
177191

178192
self.job.pause()
179-
testlib.retry(self.job, 'isPaused', '1')
180-
self.assertEqual(self.job['isPaused'], '1')
193+
self.assertEventuallyEqual(
194+
'1',
195+
lambda: self.job.refresh()['isPaused']
196+
)
181197

182198
def test_unpause(self):
183199
if self.job['isPaused'] == '0':
184200
self.job.pause()
185201
self.job.refresh()
186202
self.assertEqual(self.job['isPaused'], '1')
187203
self.job.unpause()
188-
testlib.retry(self.job, 'isPaused', '0')
189-
self.assertEqual(self.job['isPaused'], '0')
204+
self.assertEventuallyEqual(
205+
'0',
206+
lambda: self.job.refresh()['isPaused']
207+
)
190208

191209
def test_finalize(self):
192210
if self.job['isFinalized'] == '1':
193211
self.fail("Job is already finalized; can't test .finalize() method.")
194212
else:
195213
self.job.finalize()
196-
testlib.retry(self.job, 'isFinalized', '1')
197-
self.assertEqual(self.job['isFinalized'], '1')
198-
199-
def test_setpriority(self):
200-
old_priority = int(self.job['priority'])
201-
new_priority = old_priority%10 + 1
202-
self.assertNotEqual(old_priority, new_priority)
203-
204-
self.job.set_priority(new_priority)
205-
testlib.retry(self.job, 'priority', str(new_priority))
206-
self.assertEqual(int(self.job['priority']), new_priority)
214+
self.assertEventuallyEqual('1', lambda: self.job.refresh()['isFinalized'])
207215

208216
def test_setttl(self):
209217
old_ttl = int(self.job['ttl'])

tests/test_modular_input_kinds.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
import splunklib.client as client
1919

2020
class ModularInputKindTestCase(testlib.SDKTestCase):
21+
def setUp(self):
22+
super(ModularInputKindTestCase, self).setUp()
23+
self.installAppFromCollection("modular-inputs")
24+
2125
def test_list_arguments(self):
2226
if self.service.splunk_version[0] < 5:
2327
# Not implemented before 5.0

tests/test_service.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def test_update_settings(self):
128128
settings.refresh()
129129
updated = settings['sessionTimeout']
130130
self.assertEqual(updated, original)
131+
self.restartSplunk()
131132

132133
class TestTrailing(unittest.TestCase):
133134
template = '/servicesNS/boris/search/another/path/segment/that runs on'

0 commit comments

Comments
 (0)