1import re 2 3import pytest 4from unit.applications.lang.perl import TestApplicationPerl 5 6 7class TestPerlApplication(TestApplicationPerl): 8 prerequisites = {'modules': {'perl': 'all'}} 9 10 def test_perl_application(self): 11 self.load('variables') 12 13 body = 'Test body string.' 14 15 resp = self.post( 16 headers={ 17 'Host': 'localhost', 18 'Content-Type': 'text/html', 19 'Custom-Header': 'blah', 20 'Connection': 'close', 21 }, 22 body=body, 23 ) 24 25 assert resp['status'] == 200, 'status' 26 headers = resp['headers'] 27 header_server = headers.pop('Server') 28 assert re.search(r'Unit/[\d\.]+', header_server), 'server header' 29 assert ( 30 headers.pop('Server-Software') == header_server 31 ), 'server software header' 32 33 date = headers.pop('Date') 34 assert date[-4:] == ' GMT', 'date header timezone' 35 assert ( 36 abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 37 ), 'date header' 38 39 assert headers == { 40 'Connection': 'close', 41 'Content-Length': str(len(body)), 42 'Content-Type': 'text/html', 43 'Request-Method': 'POST', 44 'Request-Uri': '/', 45 'Http-Host': 'localhost', 46 'Server-Protocol': 'HTTP/1.1', 47 'Custom-Header': 'blah', 48 'Psgi-Version': '11', 49 'Psgi-Url-Scheme': 'http', 50 'Psgi-Multithread': '', 51 'Psgi-Multiprocess': '1', 52 'Psgi-Run-Once': '', 53 'Psgi-Nonblocking': '', 54 'Psgi-Streaming': '1', 55 }, 'headers' 56 assert resp['body'] == body, 'body' 57 58 def test_perl_application_query_string(self): 59 self.load('query_string') 60 61 resp = self.get(url='/?var1=val1&var2=val2') 62 63 assert ( 64 resp['headers']['Query-String'] == 'var1=val1&var2=val2' 65 ), 'Query-String header' 66 67 def test_perl_application_query_string_empty(self): 68 self.load('query_string') 69 70 resp = self.get(url='/?') 71 72 assert resp['status'] == 200, 'query string empty status' 73 assert resp['headers']['Query-String'] == '', 'query string empty' 74 75 def test_perl_application_query_string_absent(self): 76 self.load('query_string') 77 78 resp = self.get() 79 80 assert resp['status'] == 200, 'query string absent status' 81 assert resp['headers']['Query-String'] == '', 'query string absent' 82 83 @pytest.mark.skip('not yet') 84 def test_perl_application_server_port(self): 85 self.load('server_port') 86 87 assert ( 88 self.get()['headers']['Server-Port'] == '7080' 89 ), 'Server-Port header' 90 91 def test_perl_application_input_read_empty(self): 92 self.load('input_read_empty') 93 94 assert self.get()['body'] == '', 'read empty' 95 96 def test_perl_application_input_read_parts(self): 97 self.load('input_read_parts') 98 99 assert ( 100 self.post(body='0123456789')['body'] == '0123456789' 101 ), 'input read parts' 102 103 def test_perl_application_input_buffered_read(self): 104 self.load('input_buffered_read') 105 106 assert self.post(body='012345')['body'] == '012345', 'buffered read #1' 107 assert ( 108 self.post(body='9876543210')['body'] == '9876543210' 109 ), 'buffered read #2' 110 111 def test_perl_application_input_close(self): 112 self.load('input_close') 113 114 assert self.post(body='012345')['body'] == '012345', 'input close #1' 115 assert ( 116 self.post(body='9876543210')['body'] == '9876543210' 117 ), 'input close #2' 118 119 @pytest.mark.skip('not yet') 120 def test_perl_application_input_read_offset(self): 121 self.load('input_read_offset') 122 123 assert self.post(body='0123456789')['body'] == '4567', 'read offset' 124 125 def test_perl_application_input_copy(self): 126 self.load('input_copy') 127 128 body = '0123456789' 129 assert self.post(body=body)['body'] == body, 'input copy' 130 131 def test_perl_application_errors_print(self): 132 self.load('errors_print') 133 134 assert self.get()['body'] == '1', 'errors result' 135 136 assert ( 137 self.wait_for_record(r'\[error\].+Error in application') is not None 138 ), 'errors print' 139 140 def test_perl_application_header_equal_names(self): 141 self.load('header_equal_names') 142 143 assert self.get()['headers']['Set-Cookie'] == [ 144 'tc=one,two,three', 145 'tc=four,five,six', 146 ], 'header equal names' 147 148 def test_perl_application_header_pairs(self): 149 self.load('header_pairs') 150 151 assert self.get()['headers']['blah'] == 'blah', 'header pairs' 152 153 def test_perl_application_body_empty(self): 154 self.load('body_empty') 155 156 assert self.get()['body'] == '', 'body empty' 157 158 def test_perl_application_body_array(self): 159 self.load('body_array') 160 161 assert self.get()['body'] == '0123456789', 'body array' 162 163 def test_perl_application_body_large(self): 164 self.load('variables') 165 166 body = '0123456789' * 1000 167 168 resp = self.post(body=body)['body'] 169 170 assert resp == body, 'body large' 171 172 def test_perl_application_body_io_empty(self): 173 self.load('body_io_empty') 174 175 assert self.get()['status'] == 200, 'body io empty' 176 177 def test_perl_application_body_io_file(self): 178 self.load('body_io_file') 179 180 assert self.get()['body'] == 'body\n', 'body io file' 181 182 @pytest.mark.skip('not yet') 183 def test_perl_application_syntax_error(self, skip_alert): 184 skip_alert(r'PSGI: Failed to parse script') 185 self.load('syntax_error') 186 187 assert self.get()['status'] == 500, 'syntax error' 188 189 def test_perl_keepalive_body(self): 190 self.load('variables') 191 192 assert self.get()['status'] == 200, 'init' 193 194 body = '0123456789' * 500 195 (resp, sock) = self.post( 196 headers={ 197 'Host': 'localhost', 198 'Connection': 'keep-alive', 199 'Content-Type': 'text/html', 200 }, 201 start=True, 202 body=body, 203 read_timeout=1, 204 ) 205 206 assert resp['body'] == body, 'keep-alive 1' 207 208 body = '0123456789' 209 resp = self.post( 210 headers={ 211 'Host': 'localhost', 212 'Connection': 'close', 213 'Content-Type': 'text/html', 214 }, 215 sock=sock, 216 body=body, 217 ) 218 219 assert resp['body'] == body, 'keep-alive 2' 220 221 def test_perl_body_io_fake(self): 222 self.load('body_io_fake') 223 224 assert self.get()['body'] == '21', 'body io fake' 225 226 assert ( 227 self.wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+') 228 is not None 229 ), 'body io fake $/ value' 230 231 assert ( 232 self.wait_for_record(r'\[error\].+IOFake close\(\) called') 233 is not None 234 ), 'body io fake close' 235 236 def test_perl_delayed_response(self): 237 self.load('delayed_response') 238 239 resp = self.get() 240 241 assert resp['status'] == 200, 'status' 242 assert resp['body'] == 'Hello World!', 'body' 243 244 def test_perl_streaming_body(self): 245 self.load('streaming_body') 246 247 resp = self.get() 248 249 assert resp['status'] == 200, 'status' 250 assert resp['body'] == 'Hello World!', 'body' 251 252 def test_perl_application_threads(self): 253 self.load('threads') 254 255 assert 'success' in self.conf( 256 '4', 'applications/threads/threads' 257 ), 'configure 4 threads' 258 259 socks = [] 260 261 for i in range(4): 262 (_, sock) = self.get( 263 headers={ 264 'Host': 'localhost', 265 'X-Delay': '2', 266 'Connection': 'close', 267 }, 268 no_recv=True, 269 start=True, 270 ) 271 272 socks.append(sock) 273 274 threads = set() 275 276 for sock in socks: 277 resp = self.recvall(sock).decode('utf-8') 278 279 self.log_in(resp) 280 281 resp = self._resp_to_dict(resp) 282 283 assert resp['status'] == 200, 'status' 284 285 threads.add(resp['headers']['X-Thread']) 286 287 assert resp['headers']['Psgi-Multithread'] == '1', 'multithread' 288 289 sock.close() 290 291 assert len(socks) == len(threads), 'threads differs' 292