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