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