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