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