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_negative(self): 40 self.assertIn('error', self.conf({ 41 "spare": -1 42 }, 'applications/' + self.app_name + '/processes'), 'negative spare') 43 44 def test_python_processes_max_negative(self): 45 self.assertIn('error', self.conf({ 46 "max": -1 47 }, 'applications/' + self.app_name + '/processes'), 'negative max') 48 49 def test_python_processes_idle_timeout_negative(self): 50 self.assertIn('error', self.conf({ 51 "idle_timeout": -1 52 }, 'applications/' + self.app_name + '/processes'), 53 'negative idle_timeout') 54 55 def test_python_processes_spare_gt_max_default(self): 56 self.assertIn('error', self.conf({"spare": 2}, 57 'applications/' + self.app_name + '/processes'), 58 'spare greater than max default') 59 60 def test_python_processes_spare_gt_max(self): 61 self.assertIn('error', self.conf({ 62 "spare": 2, 63 "max": 1, 64 "idle_timeout": 1 65 }, '/applications/' + self.app_name + '/processes'), 66 'spare greater than max') 67 68 def test_python_processes_max_zero(self): 69 self.assertIn('error', self.conf({ 70 "spare": 0, 71 "max": 0, 72 "idle_timeout": 1 73 }, 'applications/' + self.app_name + '/processes'), 'max 0') 74 75 def test_python_processes_idle_timeout_zero(self): 76 self.conf({ 77 "spare": 0, 78 "max": 2, 79 "idle_timeout": 0 80 }, 'applications/' + self.app_name + '/processes') 81 82 self.get() 83 self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0') 84 85 def test_python_prefork(self): 86 self.conf('2', 'applications/' + self.app_name + '/processes') 87 88 pids = self.pids_for_process() 89 self.assertEqual(len(pids), 2, 'prefork 2') 90 91 self.get() 92 self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2') 93 94 self.conf('4', 'applications/' + self.app_name + '/processes') 95 96 pids = self.pids_for_process() 97 self.assertEqual(len(pids), 4, 'prefork 4') 98 99 self.get() 100 self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 4') 101 102 self.stop_all() 103 104 @unittest.expectedFailure 105 def test_python_prefork_same_processes(self): 106 self.conf('2', 'applications/' + self.app_name + '/processes') 107 108 pids = self.pids_for_process() 109 110 self.conf('4', 'applications/' + self.app_name + '/processes') 111 112 pids_new = self.pids_for_process() 113 114 self.assertTrue(pids.issubset(pids_new), 'prefork same processes') 115 116 def test_python_ondemand(self): 117 self.conf({ 118 "spare": 0, 119 "max": 8, 120 "idle_timeout": 1 121 }, 'applications/' + self.app_name + '/processes') 122 123 self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0') 124 125 self.get() 126 pids = self.pids_for_process() 127 self.assertEqual(len(pids), 1, 'on-demand 1') 128 129 self.get() 130 self.assertSetEqual(self.pids_for_process(), pids, 'on-demand still 1') 131 132 time.sleep(1) 133 134 self.assertEqual(len(self.pids_for_process()), 0, 'on-demand stop idle') 135 136 self.stop_all() 137 138 def test_python_scale_updown(self): 139 self.conf({ 140 "spare": 2, 141 "max": 8, 142 "idle_timeout": 1 143 }, 'applications/' + self.app_name + '/processes') 144 145 pids = self.pids_for_process() 146 self.assertEqual(len(pids), 2, 'updown 2') 147 148 self.get() 149 pids_new = self.pids_for_process() 150 self.assertEqual(len(pids_new), 3, 'updown 3') 151 self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new') 152 153 self.get() 154 self.assertSetEqual(self.pids_for_process(), pids_new, 'updown still 3') 155 156 time.sleep(1) 157 158 pids = self.pids_for_process() 159 self.assertEqual(len(pids), 2, 'updown stop idle') 160 161 self.get() 162 pids_new = self.pids_for_process() 163 self.assertEqual(len(pids_new), 3, 'updown again 3') 164 self.assertTrue(pids.issubset(pids_new), 'updown again 3 only 1 new') 165 166 self.stop_all() 167 168 def test_python_reconfigure(self): 169 self.conf({ 170 "spare": 2, 171 "max": 6, 172 "idle_timeout": 1 173 }, 'applications/' + self.app_name + '/processes') 174 175 pids = self.pids_for_process() 176 self.assertEqual(len(pids), 2, 'reconf 2') 177 178 self.get() 179 pids_new = self.pids_for_process() 180 self.assertEqual(len(pids_new), 3, 'reconf 3') 181 self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new') 182 183 self.conf('6', 'applications/' + self.app_name + '/processes/spare') 184 185 pids = self.pids_for_process() 186 self.assertEqual(len(pids), 6, 'reconf 6') 187 188 self.get() 189 self.assertSetEqual(self.pids_for_process(), pids, 'reconf still 6') 190 191 self.stop_all() 192 193 def test_python_idle_timeout(self): 194 self.conf({ 195 "spare": 0, 196 "max": 6, 197 "idle_timeout": 2 198 }, 'applications/' + self.app_name + '/processes') 199 200 self.get() 201 pids = self.pids_for_process() 202 self.assertEqual(len(pids), 1, 'idle timeout 1') 203 204 time.sleep(1) 205 206 self.get() 207 208 time.sleep(1) 209 210 pids_new = self.pids_for_process() 211 self.assertEqual(len(pids_new), 1, 'idle timeout still 1') 212 self.assertSetEqual(self.pids_for_process(), pids, 213 'idle timeout still 1 same pid') 214 215 time.sleep(1) 216 217 self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out') 218 219 def test_python_processes_connection_keepalive(self): 220 self.conf({ 221 "spare": 0, 222 "max": 6, 223 "idle_timeout": 2 224 }, 'applications/' + self.app_name + '/processes') 225 226 (resp, sock) = self.get(headers={ 227 'Host': 'localhost', 228 'Connection': 'keep-alive' 229 }, start=True) 230 self.assertEqual(len(self.pids_for_process()), 1, 231 'keepalive connection 1') 232 233 time.sleep(2) 234 235 self.assertEqual(len(self.pids_for_process()), 0, 'keepalive connection 0') 236 237 sock.close() 238 239 def stop_all(self): 240 self.conf({ 241 "listeners": {}, 242 "applications": {} 243 }) 244 245 self.assertEqual(len(self.pids_for_process()), 0, 'stop all') 246 247if __name__ == '__main__': 248 unittest.main() 249