xref: /unit/test/test_python_procman.py (revision 552:2e4ea9cc507e)
1import re
2import time
3import subprocess
4import unittest
5import unit
6
7class TestUnitPythonProcman(unit.TestUnitApplicationPython):
8
9    def setUpClass():
10        unit.TestUnit().check_modules('python')
11
12    def pids_for_process(self):
13        time.sleep(0.2)
14
15        output = subprocess.check_output(['ps', 'ax'])
16
17        pids = set()
18        for m in re.findall('.*' + self.app_name, output.decode()):
19            pids.add(re.search('^\s*(\d+)', m).group(1))
20
21        return pids
22
23    def setUp(self):
24        super().setUp()
25
26        self.app_name = "app-" + self.testdir.split('/')[-1]
27        self.load('empty', self.app_name)
28
29    def test_python_processes_access(self):
30        self.conf('1', '/applications/' + self.app_name + '/processes')
31
32        self.assertIn('error', self.conf_get('/applications/' + self.app_name +
33            '/processes/max'), 'max no access')
34        self.assertIn('error', self.conf_get('/applications/' + self.app_name +
35            '/processes/spare'), 'spare no access')
36        self.assertIn('error', self.conf_get('/applications/' + self.app_name +
37            '/processes/idle_timeout'), 'idle_timeout no access')
38
39    def test_python_processes_spare_gt_max_default(self):
40        self.assertIn('error', self.conf({"spare": 2},
41            '/applications/' + self.app_name + '/processes'),
42            'spare greater than max default')
43
44    def test_python_processes_spare_gt_max(self):
45        self.assertIn('error', self.conf({
46            "spare": 2,
47            "max": 1,
48            "idle_timeout": 1
49        }, '/applications/' + self.app_name + '/processes'),
50            'spare greater than max')
51
52    def test_python_processes_max_zero(self):
53        self.assertIn('error', self.conf({
54            "spare": 0,
55            "max": 0,
56            "idle_timeout": 1
57        }, '/applications/' + self.app_name + '/processes'), 'max 0')
58
59    def test_python_processes_idle_timeout_zero(self):
60        self.conf({
61            "spare": 0,
62            "max": 2,
63            "idle_timeout": 0
64        }, '/applications/' + self.app_name + '/processes')
65
66        self.get()
67        self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0')
68
69    def test_python_prefork(self):
70        self.conf('2', '/applications/' + self.app_name + '/processes')
71
72        pids = self.pids_for_process()
73        self.assertEqual(len(pids), 2, 'prefork 2')
74
75        self.get()
76        self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2')
77
78        self.conf('4', '/applications/' + self.app_name + '/processes')
79
80        pids = self.pids_for_process()
81        self.assertEqual(len(pids), 4, 'prefork 4')
82
83        self.get()
84        self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 4')
85
86        self.stop_all()
87
88    @unittest.expectedFailure
89    def test_python_prefork_same_processes(self):
90        self.conf('2', '/applications/' + self.app_name + '/processes')
91
92        pids = self.pids_for_process()
93
94        self.conf('4', '/applications/' + self.app_name + '/processes')
95
96        pids_new = self.pids_for_process()
97
98        self.assertTrue(pids.issubset(pids_new), 'prefork same processes')
99
100    def test_python_ondemand(self):
101        self.conf({
102            "spare": 0,
103            "max": 8,
104            "idle_timeout": 1
105        }, '/applications/' + self.app_name + '/processes')
106
107        self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0')
108
109        self.get()
110        pids = self.pids_for_process()
111        self.assertEqual(len(pids), 1, 'on-demand 1')
112
113        self.get()
114        self.assertSetEqual(self.pids_for_process(), pids, 'on-demand still 1')
115
116        time.sleep(1)
117
118        self.assertEqual(len(self.pids_for_process()), 0, 'on-demand stop idle')
119
120        self.stop_all()
121
122    def test_python_scale_updown(self):
123        self.conf({
124            "spare": 2,
125            "max": 8,
126            "idle_timeout": 1
127        }, '/applications/' + self.app_name + '/processes')
128
129        pids = self.pids_for_process()
130        self.assertEqual(len(pids), 2, 'updown 2')
131
132        self.get()
133        pids_new = self.pids_for_process()
134        self.assertEqual(len(pids_new), 3, 'updown 3')
135        self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new')
136
137        self.get()
138        self.assertSetEqual(self.pids_for_process(), pids_new, 'updown still 3')
139
140        time.sleep(1)
141
142        pids = self.pids_for_process()
143        self.assertEqual(len(pids), 2, 'updown stop idle')
144
145        self.get()
146        pids_new = self.pids_for_process()
147        self.assertEqual(len(pids_new), 3, 'updown again 3')
148        self.assertTrue(pids.issubset(pids_new), 'updown again 3 only 1 new')
149
150        self.stop_all()
151
152    def test_python_reconfigure(self):
153        self.conf({
154            "spare": 2,
155            "max": 6,
156            "idle_timeout": 1
157        }, '/applications/' + self.app_name + '/processes')
158
159        pids = self.pids_for_process()
160        self.assertEqual(len(pids), 2, 'reconf 2')
161
162        self.get()
163        pids_new = self.pids_for_process()
164        self.assertEqual(len(pids_new), 3, 'reconf 3')
165        self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new')
166
167        self.conf('6', '/applications/' + self.app_name + '/processes/spare')
168
169        pids = self.pids_for_process()
170        self.assertEqual(len(pids), 6, 'reconf 6')
171
172        self.get()
173        self.assertSetEqual(self.pids_for_process(), pids, 'reconf still 6')
174
175        self.stop_all()
176
177    def test_python_idle_timeout(self):
178        self.conf({
179            "spare": 0,
180            "max": 6,
181            "idle_timeout": 2
182        }, '/applications/' + self.app_name + '/processes')
183
184        self.get()
185        pids = self.pids_for_process()
186        self.assertEqual(len(pids), 1, 'idle timeout 1')
187
188        time.sleep(1)
189
190        self.get()
191
192        time.sleep(1)
193
194        pids_new = self.pids_for_process()
195        self.assertEqual(len(pids_new), 1, 'idle timeout still 1')
196        self.assertSetEqual(self.pids_for_process(), pids,
197            'idle timeout still 1 same pid')
198
199        time.sleep(1)
200
201        self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out')
202
203    def test_python_processes_connection_keepalive(self):
204        self.conf({
205            "spare": 0,
206            "max": 6,
207            "idle_timeout": 2
208        }, '/applications/' + self.app_name + '/processes')
209
210        (resp, sock) = self.get(headers={
211            'Host': 'localhost',
212            'Connection': 'keep-alive'
213        }, start=True)
214        self.assertEqual(len(self.pids_for_process()), 1,
215            'keepalive connection 1')
216
217        time.sleep(2)
218
219        self.assertEqual(len(self.pids_for_process()), 0, 'keepalive connection 0')
220
221        sock.close()
222
223    def stop_all(self):
224        self.conf({
225            "listeners": {},
226            "applications": {}
227        })
228
229        self.assertEqual(len(self.pids_for_process()), 0, 'stop all')
230
231if __name__ == '__main__':
232    unittest.main()
233