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