1import unittest 2 3from unit.control import TestControl 4 5 6class TestConfiguration(TestControl): 7 prerequisites = {'modules': {'python': 'any'}} 8 9 def test_json_empty(self): 10 self.assertIn('error', self.conf(''), 'empty') 11 12 def test_json_leading_zero(self): 13 self.assertIn('error', self.conf('00'), 'leading zero') 14 15 def test_json_unicode(self): 16 self.assertIn( 17 'success', 18 self.conf( 19 b""" 20 { 21 "ap\u0070": { 22 "type": "\u0070ython", 23 "processes": { "spare": 0 }, 24 "path": "\u002Fapp", 25 "module": "wsgi" 26 } 27 } 28 """, 29 'applications', 30 ), 31 'unicode', 32 ) 33 34 self.assertDictEqual( 35 self.conf_get('applications'), 36 { 37 "app": { 38 "type": "python", 39 "processes": {"spare": 0}, 40 "path": "/app", 41 "module": "wsgi", 42 } 43 }, 44 'unicode get', 45 ) 46 47 def test_json_unicode_2(self): 48 self.assertIn( 49 'success', 50 self.conf( 51 { 52 "приложение": { 53 "type": "python", 54 "processes": {"spare": 0}, 55 "path": "/app", 56 "module": "wsgi", 57 } 58 }, 59 'applications', 60 ), 61 'unicode 2', 62 ) 63 64 self.assertIn( 65 'приложение', self.conf_get('applications'), 'unicode 2 get' 66 ) 67 68 def test_json_unicode_number(self): 69 self.assertIn( 70 'error', 71 self.conf( 72 b""" 73 { 74 "app": { 75 "type": "python", 76 "processes": { "spare": \u0030 }, 77 "path": "/app", 78 "module": "wsgi" 79 } 80 } 81 """, 82 'applications', 83 ), 84 'unicode number', 85 ) 86 87 def test_json_utf8_bom(self): 88 self.assertIn( 89 'success', 90 self.conf( 91 b"""\xEF\xBB\xBF 92 { 93 "app": { 94 "type": "python", 95 "processes": {"spare": 0}, 96 "path": "/app", 97 "module": "wsgi" 98 } 99 } 100 """, 101 'applications', 102 ), 103 'UTF-8 BOM', 104 ) 105 106 def test_json_comment_single_line(self): 107 self.assertIn( 108 'success', 109 self.conf( 110 b""" 111 // this is bridge 112 { 113 "//app": { 114 "type": "python", // end line 115 "processes": {"spare": 0}, 116 // inside of block 117 "path": "/app", 118 "module": "wsgi" 119 } 120 // double // 121 } 122 // end of json \xEF\t 123 """, 124 'applications', 125 ), 126 'single line comments', 127 ) 128 129 def test_json_comment_multi_line(self): 130 self.assertIn( 131 'success', 132 self.conf( 133 b""" 134 /* this is bridge */ 135 { 136 "/*app": { 137 /** 138 * multiple lines 139 **/ 140 "type": "python", 141 "processes": /* inline */ {"spare": 0}, 142 "path": "/app", 143 "module": "wsgi" 144 /* 145 // end of block */ 146 } 147 /* blah * / blah /* blah */ 148 } 149 /* end of json \xEF\t\b */ 150 """, 151 'applications', 152 ), 153 'multi line comments', 154 ) 155 156 def test_json_comment_invalid(self): 157 self.assertIn('error', self.conf(b'/{}', 'applications'), 'slash') 158 self.assertIn('error', self.conf(b'//{}', 'applications'), 'comment') 159 self.assertIn('error', self.conf(b'{} /', 'applications'), 'slash end') 160 self.assertIn( 161 'error', self.conf(b'/*{}', 'applications'), 'slash star' 162 ) 163 self.assertIn( 164 'error', self.conf(b'{} /*', 'applications'), 'slash star end' 165 ) 166 167 def test_applications_open_brace(self): 168 self.assertIn('error', self.conf('{', 'applications'), 'open brace') 169 170 def test_applications_string(self): 171 self.assertIn('error', self.conf('"{}"', 'applications'), 'string') 172 173 @unittest.skip('not yet, unsafe') 174 def test_applications_type_only(self): 175 self.assertIn( 176 'error', 177 self.conf({"app": {"type": "python"}}, 'applications'), 178 'type only', 179 ) 180 181 def test_applications_miss_quote(self): 182 self.assertIn( 183 'error', 184 self.conf( 185 """ 186 { 187 app": { 188 "type": "python", 189 "processes": { "spare": 0 }, 190 "path": "/app", 191 "module": "wsgi" 192 } 193 } 194 """, 195 'applications', 196 ), 197 'miss quote', 198 ) 199 200 def test_applications_miss_colon(self): 201 self.assertIn( 202 'error', 203 self.conf( 204 """ 205 { 206 "app" { 207 "type": "python", 208 "processes": { "spare": 0 }, 209 "path": "/app", 210 "module": "wsgi" 211 } 212 } 213 """, 214 'applications', 215 ), 216 'miss colon', 217 ) 218 219 def test_applications_miss_comma(self): 220 self.assertIn( 221 'error', 222 self.conf( 223 """ 224 { 225 "app": { 226 "type": "python" 227 "processes": { "spare": 0 }, 228 "path": "/app", 229 "module": "wsgi" 230 } 231 } 232 """, 233 'applications', 234 ), 235 'miss comma', 236 ) 237 238 def test_applications_skip_spaces(self): 239 self.assertIn( 240 'success', self.conf(b'{ \n\r\t}', 'applications'), 'skip spaces' 241 ) 242 243 def test_applications_relative_path(self): 244 self.assertIn( 245 'success', 246 self.conf( 247 { 248 "app": { 249 "type": "python", 250 "processes": {"spare": 0}, 251 "path": "../app", 252 "module": "wsgi", 253 } 254 }, 255 'applications', 256 ), 257 'relative path', 258 ) 259 260 @unittest.skip('not yet, unsafe') 261 def test_listeners_empty(self): 262 self.assertIn( 263 'error', self.conf({"*:7080": {}}, 'listeners'), 'listener empty' 264 ) 265 266 def test_listeners_no_app(self): 267 self.assertIn( 268 'error', 269 self.conf({"*:7080": {"pass": "applications/app"}}, 'listeners'), 270 'listeners no app', 271 ) 272 273 def test_listeners_wildcard(self): 274 self.assertIn( 275 'success', 276 self.conf( 277 { 278 "listeners": {"*:7080": {"pass": "applications/app"}}, 279 "applications": { 280 "app": { 281 "type": "python", 282 "processes": {"spare": 0}, 283 "path": "/app", 284 "module": "wsgi", 285 } 286 }, 287 } 288 ), 289 'listeners wildcard', 290 ) 291 292 def test_listeners_explicit(self): 293 self.assertIn( 294 'success', 295 self.conf( 296 { 297 "listeners": {"127.0.0.1:7080": {"pass": "applications/app"}}, 298 "applications": { 299 "app": { 300 "type": "python", 301 "processes": {"spare": 0}, 302 "path": "/app", 303 "module": "wsgi", 304 } 305 }, 306 } 307 ), 308 'explicit', 309 ) 310 311 def test_listeners_explicit_ipv6(self): 312 self.assertIn( 313 'success', 314 self.conf( 315 { 316 "listeners": {"[::1]:7080": {"pass": "applications/app"}}, 317 "applications": { 318 "app": { 319 "type": "python", 320 "processes": {"spare": 0}, 321 "path": "/app", 322 "module": "wsgi", 323 } 324 }, 325 } 326 ), 327 'explicit ipv6', 328 ) 329 330 @unittest.skip('not yet, unsafe') 331 def test_listeners_no_port(self): 332 self.assertIn( 333 'error', 334 self.conf( 335 { 336 "listeners": {"127.0.0.1": {"pass": "applications/app"}}, 337 "applications": { 338 "app": { 339 "type": "python", 340 "processes": {"spare": 0}, 341 "path": "/app", 342 "module": "wsgi", 343 } 344 }, 345 } 346 ), 347 'no port', 348 ) 349 350 def test_json_application_name_large(self): 351 name = "X" * 1024 * 1024 352 353 self.assertIn( 354 'success', 355 self.conf( 356 { 357 "listeners": {"*:7080": {"pass": "applications/" + name}}, 358 "applications": { 359 name: { 360 "type": "python", 361 "processes": {"spare": 0}, 362 "path": "/app", 363 "module": "wsgi", 364 } 365 }, 366 } 367 ), 368 ) 369 370 @unittest.skip('not yet') 371 def test_json_application_many(self): 372 apps = 999 373 374 conf = { 375 "applications": { 376 "app-" 377 + str(a): { 378 "type": "python", 379 "processes": {"spare": 0}, 380 "path": "/app", 381 "module": "wsgi", 382 } 383 for a in range(apps) 384 }, 385 "listeners": { 386 "*:" + str(7000 + a): {"pass": "applications/app-" + str(a)} 387 for a in range(apps) 388 }, 389 } 390 391 self.assertIn('success', self.conf(conf)) 392 393 def test_json_application_many2(self): 394 conf = { 395 "applications": { 396 "app-" 397 + str(a): { 398 "type": "python", 399 "processes": {"spare": 0}, 400 "path": "/app", 401 "module": "wsgi", 402 } 403 # Larger number of applications can cause test fail with default 404 # open files limit due to the lack of file descriptors. 405 for a in range(100) 406 }, 407 "listeners": {"*:7080": {"pass": "applications/app-1"}}, 408 } 409 410 self.assertIn('success', self.conf(conf)) 411 412 def test_unprivileged_user_error(self): 413 self.skip_alerts.extend( 414 [ 415 r'cannot set user "root"', 416 r'failed to apply new conf', 417 ] 418 ) 419 if self.is_su: 420 print('unprivileged tests, skip this') 421 raise unittest.SkipTest() 422 423 self.assertIn( 424 'error', 425 self.conf( 426 { 427 "app": { 428 "type": "external", 429 "processes": 1, 430 "executable": "/app", 431 "user": "root", 432 } 433 }, 434 'applications', 435 ), 436 'setting user', 437 ) 438 439 440if __name__ == '__main__': 441 TestConfiguration.main() 442