1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 United States Government as represented by the
4
# Administrator of the National Aeronautics and Space Administration.
7
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8
# not use this file except in compliance with the License. You may obtain
9
# a copy of the License at
11
# http://www.apache.org/licenses/LICENSE-2.0
13
# Unless required by applicable law or agreed to in writing, software
14
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
# License for the specific language governing permissions and limitations
20
from twisted.internet import defer
21
from twisted.internet import reactor
22
from xml.etree import ElementTree
24
from nova import exception
25
from nova import flags
26
from nova import process
28
from nova import utils
33
class ProcessTestCase(test.TrialTestCase):
35
logging.getLogger().setLevel(logging.DEBUG)
36
super(ProcessTestCase, self).setUp()
38
def test_execute_stdout(self):
39
pool = process.ProcessPool(2)
40
d = pool.simple_execute('echo test')
43
self.assertEqual(rv[0], 'test\n')
44
self.assertEqual(rv[1], '')
47
d.addErrback(self.fail)
50
def test_execute_stderr(self):
51
pool = process.ProcessPool(2)
52
d = pool.simple_execute('cat BAD_FILE', check_exit_code=False)
55
self.assertEqual(rv[0], '')
56
self.assert_('No such file' in rv[1])
59
d.addErrback(self.fail)
62
def test_execute_unexpected_stderr(self):
63
pool = process.ProcessPool(2)
64
d = pool.simple_execute('cat BAD_FILE')
65
d.addCallback(lambda x: self.fail('should have raised an error'))
66
d.addErrback(lambda failure: failure.trap(IOError))
69
def test_max_processes(self):
70
pool = process.ProcessPool(2)
71
d1 = pool.simple_execute('sleep 0.01')
72
d2 = pool.simple_execute('sleep 0.01')
73
d3 = pool.simple_execute('sleep 0.005')
74
d4 = pool.simple_execute('sleep 0.005')
78
def _called(rv, name):
81
d1.addCallback(_called, 'd1')
82
d2.addCallback(_called, 'd2')
83
d3.addCallback(_called, 'd3')
84
d4.addCallback(_called, 'd4')
86
# Make sure that d3 and d4 had to wait on the other two and were called
88
# NOTE(termie): there may be a race condition in this test if for some
89
# reason one of the sleeps takes longer to complete
91
d4.addCallback(lambda x: self.assertEqual(called[2], 'd3'))
92
d4.addCallback(lambda x: self.assertEqual(called[3], 'd4'))
93
d4.addErrback(self.fail)
96
def test_kill_long_process(self):
97
pool = process.ProcessPool(2)
99
d1 = pool.simple_execute('sleep 1')
100
d2 = pool.simple_execute('sleep 0.005')
102
timeout = reactor.callLater(0.1, self.fail, 'should have been killed')
104
# kill d1 and wait on it to end then cancel the timeout
105
d2.addCallback(lambda _: d1.process.signalProcess('KILL'))
106
d2.addCallback(lambda _: d1)
107
d2.addBoth(lambda _: timeout.active() and timeout.cancel())
108
d2.addErrback(self.fail)
111
def test_process_exit_is_contained(self):
112
pool = process.ProcessPool(2)
114
d1 = pool.simple_execute('sleep 1')
115
d1.addCallback(lambda x: self.fail('should have errbacked'))
116
d1.addErrback(lambda fail: fail.trap(IOError))
117
reactor.callLater(0.05, d1.process.signalProcess, 'KILL')
121
def test_shared_pool_is_singleton(self):
122
pool1 = process.SharedPool()
123
pool2 = process.SharedPool()
124
self.assertEqual(id(pool1._instance), id(pool2._instance))
126
def test_shared_pool_works_as_singleton(self):
127
d1 = process.simple_execute('sleep 1')
128
d2 = process.simple_execute('sleep 0.005')
129
# lp609749: would have failed with
130
# exceptions.AssertionError: Someone released me too many times: