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