App Engine Python SDK version 1.9.3
[gae.git] / python / google / appengine / tools / devappserver2 / dispatcher_test.py
blob35878fd1ff0089c2e90ba6dd06bc8353173d85e7
1 #!/usr/bin/env python
3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """Tests for google.appengine.tools.devappserver2.dispatcher."""
19 import logging
20 import unittest
22 import google
24 import mox
26 from google.appengine.api import appinfo
27 from google.appengine.api import dispatchinfo
28 from google.appengine.api import request_info
29 from google.appengine.tools.devappserver2 import api_server
30 from google.appengine.tools.devappserver2 import constants
31 from google.appengine.tools.devappserver2 import dispatcher
32 from google.appengine.tools.devappserver2 import scheduled_executor
33 from google.appengine.tools.devappserver2 import module
35 # This file uses pep8 naming.
36 # pylint: disable=invalid-name
39 class ApplicationConfigurationStub(object):
40 def __init__(self, modules):
41 self.modules = modules
42 self.dispatch = None
45 class ModuleConfigurationStub(object):
46 def __init__(self, application, module_name, version, manual_scaling):
47 self.application_root = '/'
48 self.application = application
49 self.module_name = module_name
50 self.major_version = version
51 self.version_id = '%s:%s.%s' % (module_name, version, '12345')
52 self.runtime = 'python27'
53 self.threadsafe = False
54 self.handlers = []
55 self.skip_files = []
56 self.normalized_libraries = []
57 self.env_variables = []
58 if manual_scaling:
59 self.automatic_scaling = appinfo.AutomaticScaling()
60 self.manual_scaling = None
61 else:
62 self.automatic_scaling = None
63 self.manual_scaling = appinfo.ManualScaling(instances=1)
64 self.inbound_services = None
66 def add_change_callback(self, fn):
67 pass
70 class DispatchConfigurationStub(object):
71 def __init__(self):
72 self.dispatch = []
75 MODULE_CONFIGURATIONS = [
76 ModuleConfigurationStub(application='app',
77 module_name='default',
78 version='version',
79 manual_scaling=False),
80 ModuleConfigurationStub(application='app',
81 module_name='other',
82 version='version2',
83 manual_scaling=True),
87 class AutoScalingModuleFacade(module.AutoScalingModule):
88 def __init__(self,
89 module_configuration,
90 host='fakehost',
91 balanced_port=0):
92 super(AutoScalingModuleFacade, self).__init__(
93 module_configuration,
94 host,
95 balanced_port,
96 api_host='localhost',
97 api_port=8080,
98 auth_domain='gmail.com',
99 runtime_stderr_loglevel=1,
100 php_config=None,
101 python_config=None,
102 cloud_sql_config=None,
103 unused_vm_config=None,
104 default_version_port=8080,
105 port_registry=None,
106 request_data=None,
107 dispatcher=None,
108 max_instances=None,
109 use_mtime_file_watcher=False,
110 automatic_restarts=True,
111 allow_skipped_files=False,
112 threadsafe_override=None)
114 def start(self):
115 pass
117 def quit(self):
118 pass
120 @property
121 def balanced_address(self):
122 return '%s:%s' % (self._host, self._balanced_port)
124 @property
125 def balanced_port(self):
126 return self._balanced_port
129 class ManualScalingModuleFacade(module.ManualScalingModule):
130 def __init__(self,
131 module_configuration,
132 host='fakehost',
133 balanced_port=0):
134 super(ManualScalingModuleFacade, self).__init__(
135 module_configuration,
136 host,
137 balanced_port,
138 api_host='localhost',
139 api_port=8080,
140 auth_domain='gmail.com',
141 runtime_stderr_loglevel=1,
142 php_config=None,
143 python_config=None,
144 cloud_sql_config=None,
145 vm_config=None,
146 default_version_port=8080,
147 port_registry=None,
148 request_data=None,
149 dispatcher=None,
150 max_instances=None,
151 use_mtime_file_watcher=False,
152 automatic_restarts=True,
153 allow_skipped_files=False,
154 threadsafe_override=None)
156 def start(self):
157 pass
159 def quit(self):
160 pass
162 @property
163 def balanced_address(self):
164 return '%s:%s' % (self._host, self._balanced_port)
166 @property
167 def balanced_port(self):
168 return self._balanced_port
170 def get_instance_address(self, instance):
171 if instance == 'invalid':
172 raise request_info.InvalidInstanceIdError()
173 return '%s:%s' % (self._host, int(instance) + 1000)
176 def _make_dispatcher(app_config):
177 """Make a new dispatcher with the given ApplicationConfigurationStub."""
178 return dispatcher.Dispatcher(
179 app_config,
180 'localhost',
182 'gmail.com',
184 php_config=None,
185 python_config=None,
186 cloud_sql_config=None,
187 vm_config=None,
188 module_to_max_instances={},
189 use_mtime_file_watcher=False,
190 automatic_restart=True,
191 allow_skipped_files=False,
192 module_to_threadsafe_override={})
195 class DispatcherQuitWithoutStartTest(unittest.TestCase):
197 def test_quit_without_start(self):
198 """Test that calling quit on a dispatcher without calling start is safe."""
199 app_config = ApplicationConfigurationStub(MODULE_CONFIGURATIONS)
200 unstarted_dispatcher = _make_dispatcher(app_config)
201 unstarted_dispatcher.quit()
204 class DispatcherTest(unittest.TestCase):
206 def setUp(self):
207 self.mox = mox.Mox()
208 api_server.test_setup_stubs()
209 self.dispatch_config = DispatchConfigurationStub()
210 app_config = ApplicationConfigurationStub(MODULE_CONFIGURATIONS)
211 self.dispatcher = _make_dispatcher(app_config)
212 self.module1 = AutoScalingModuleFacade(app_config.modules[0],
213 balanced_port=1,
214 host='localhost')
215 self.module2 = ManualScalingModuleFacade(app_config.modules[0],
216 balanced_port=2,
217 host='localhost')
219 self.mox.StubOutWithMock(self.dispatcher, '_create_module')
220 self.dispatcher._create_module(app_config.modules[0], 1).AndReturn(
221 (self.module1, 2))
222 self.dispatcher._create_module(app_config.modules[1], 2).AndReturn(
223 (self.module2, 3))
224 self.mox.ReplayAll()
225 self.dispatcher.start('localhost', 12345, object())
226 app_config.dispatch = self.dispatch_config
227 self.mox.VerifyAll()
228 self.mox.StubOutWithMock(module.Module, 'build_request_environ')
230 def tearDown(self):
231 self.dispatcher.quit()
232 self.mox.UnsetStubs()
234 def test_get_module_names(self):
235 self.assertItemsEqual(['default', 'other'],
236 self.dispatcher.get_module_names())
238 def test_get_hostname(self):
239 self.assertEqual('localhost:1',
240 self.dispatcher.get_hostname('default', 'version'))
241 self.assertEqual('localhost:2',
242 self.dispatcher.get_hostname('other', 'version2'))
243 self.assertRaises(request_info.VersionDoesNotExistError,
244 self.dispatcher.get_hostname, 'default', 'fake')
245 self.assertRaises(request_info.NotSupportedWithAutoScalingError,
246 self.dispatcher.get_hostname, 'default', 'version', '0')
247 self.assertEqual('localhost:1000',
248 self.dispatcher.get_hostname('other', 'version2', '0'))
249 self.assertRaises(request_info.InvalidInstanceIdError,
250 self.dispatcher.get_hostname, 'other', 'version2',
251 'invalid')
252 self.assertRaises(request_info.ModuleDoesNotExistError,
253 self.dispatcher.get_hostname,
254 'nomodule',
255 'version2',
256 None)
258 def test_get_module_by_name(self):
259 self.assertEqual(self.module1,
260 self.dispatcher.get_module_by_name('default'))
261 self.assertEqual(self.module2,
262 self.dispatcher.get_module_by_name('other'))
263 self.assertRaises(request_info.ModuleDoesNotExistError,
264 self.dispatcher.get_module_by_name, 'fake')
266 def test_get_versions(self):
267 self.assertEqual(['version'], self.dispatcher.get_versions('default'))
268 self.assertEqual(['version2'], self.dispatcher.get_versions('other'))
269 self.assertRaises(request_info.ModuleDoesNotExistError,
270 self.dispatcher.get_versions, 'fake')
272 def test_get_default_version(self):
273 self.assertEqual('version', self.dispatcher.get_default_version('default'))
274 self.assertEqual('version2', self.dispatcher.get_default_version('other'))
275 self.assertRaises(request_info.ModuleDoesNotExistError,
276 self.dispatcher.get_default_version, 'fake')
278 def test_add_event(self):
279 self.mox.StubOutWithMock(scheduled_executor.ScheduledExecutor, 'add_event')
280 runnable = object()
281 scheduled_executor.ScheduledExecutor.add_event(runnable, 123, ('foo',
282 'bar'))
283 scheduled_executor.ScheduledExecutor.add_event(runnable, 124, None)
284 self.mox.ReplayAll()
285 self.dispatcher.add_event(runnable, 123, 'foo', 'bar')
286 self.dispatcher.add_event(runnable, 124)
287 self.mox.VerifyAll()
289 def test_update_event(self):
290 self.mox.StubOutWithMock(scheduled_executor.ScheduledExecutor,
291 'update_event')
292 scheduled_executor.ScheduledExecutor.update_event(123, ('foo', 'bar'))
293 self.mox.ReplayAll()
294 self.dispatcher.update_event(123, 'foo', 'bar')
295 self.mox.VerifyAll()
297 def test_add_async_request(self):
298 dummy_environ = object()
299 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
300 self.dispatcher._module_name_to_module['default'].build_request_environ(
301 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
302 'body', '1.2.3.4', 1).AndReturn(
303 dummy_environ)
304 dispatcher._THREAD_POOL.submit(
305 self.dispatcher._handle_request, dummy_environ, mox.IgnoreArg(),
306 self.dispatcher._module_name_to_module['default'],
307 None, catch_and_log_exceptions=True)
308 self.mox.ReplayAll()
309 self.dispatcher.add_async_request(
310 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
311 'body', '1.2.3.4')
312 self.mox.VerifyAll()
314 def test_add_async_request_specific_module(self):
315 dummy_environ = object()
316 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
317 self.dispatcher._module_name_to_module['other'].build_request_environ(
318 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
319 'body', '1.2.3.4', 2).AndReturn(
320 dummy_environ)
321 dispatcher._THREAD_POOL.submit(
322 self.dispatcher._handle_request, dummy_environ, mox.IgnoreArg(),
323 self.dispatcher._module_name_to_module['other'],
324 None, catch_and_log_exceptions=True)
325 self.mox.ReplayAll()
326 self.dispatcher.add_async_request(
327 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
328 'body', '1.2.3.4', module_name='other')
329 self.mox.VerifyAll()
331 def test_add_async_request_soft_routing(self):
332 """Tests add_async_request with soft routing."""
333 dummy_environ = object()
334 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
335 self.dispatcher._module_name_to_module['default'].build_request_environ(
336 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
337 'body', '1.2.3.4', 1).AndReturn(
338 dummy_environ)
339 dispatcher._THREAD_POOL.submit(
340 self.dispatcher._handle_request, dummy_environ, mox.IgnoreArg(),
341 self.dispatcher._module_name_to_module['default'],
342 None, catch_and_log_exceptions=True)
343 self.mox.ReplayAll()
344 self.dispatcher.add_async_request(
345 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
346 'body', '1.2.3.4', module_name='nomodule')
347 self.mox.VerifyAll()
349 def test_add_request(self):
350 dummy_environ = object()
351 self.mox.StubOutWithMock(self.dispatcher, '_resolve_target')
352 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
353 self.dispatcher._resolve_target(None, '/foo').AndReturn(
354 (self.dispatcher._module_name_to_module['default'], None))
355 self.dispatcher._module_name_to_module['default'].build_request_environ(
356 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
357 'body', '1.2.3.4', 1, fake_login=True).AndReturn(
358 dummy_environ)
359 self.dispatcher._handle_request(
360 dummy_environ, mox.IgnoreArg(),
361 self.dispatcher._module_name_to_module['default'],
362 None).AndReturn(['Hello World'])
363 self.mox.ReplayAll()
364 response = self.dispatcher.add_request(
365 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
366 'body', '1.2.3.4', fake_login=True)
367 self.mox.VerifyAll()
368 self.assertEqual('Hello World', response.content)
370 def test_add_request_soft_routing(self):
371 """Tests soft routing to the default module."""
372 dummy_environ = object()
373 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
374 self.dispatcher._module_name_to_module['default'].build_request_environ(
375 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
376 'body', '1.2.3.4', 1, fake_login=True).AndReturn(
377 dummy_environ)
378 self.dispatcher._handle_request(
379 dummy_environ, mox.IgnoreArg(),
380 self.dispatcher._module_name_to_module['default'],
381 None).AndReturn(['Hello World'])
382 self.mox.ReplayAll()
383 response = self.dispatcher.add_request(
384 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
385 'body', '1.2.3.4', fake_login=True, module_name='nomodule')
386 self.mox.VerifyAll()
387 self.assertEqual('Hello World', response.content)
389 def test_handle_request(self):
390 start_response = object()
391 servr = self.dispatcher._module_name_to_module['other']
392 self.mox.StubOutWithMock(servr, '_handle_request')
393 servr._handle_request({'foo': 'bar'}, start_response, inst=None,
394 request_type=3).AndReturn(['body'])
395 self.mox.ReplayAll()
396 self.dispatcher._handle_request({'foo': 'bar'}, start_response, servr, None,
397 request_type=3)
398 self.mox.VerifyAll()
400 def test_handle_request_reraise_exception(self):
401 start_response = object()
402 servr = self.dispatcher._module_name_to_module['other']
403 self.mox.StubOutWithMock(servr, '_handle_request')
404 servr._handle_request({'foo': 'bar'}, start_response).AndRaise(Exception)
405 self.mox.ReplayAll()
406 self.assertRaises(Exception, self.dispatcher._handle_request,
407 {'foo': 'bar'}, start_response, servr, None)
408 self.mox.VerifyAll()
410 def test_handle_request_log_exception(self):
411 start_response = object()
412 servr = self.dispatcher._module_name_to_module['other']
413 self.mox.StubOutWithMock(servr, '_handle_request')
414 self.mox.StubOutWithMock(logging, 'exception')
415 servr._handle_request({'foo': 'bar'}, start_response).AndRaise(Exception)
416 logging.exception('Internal error while handling request.')
417 self.mox.ReplayAll()
418 self.dispatcher._handle_request({'foo': 'bar'}, start_response, servr, None,
419 catch_and_log_exceptions=True)
420 self.mox.VerifyAll()
422 def test_call(self):
423 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
424 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
425 servr = object()
426 environ = {'PATH_INFO': '/foo', 'QUERY_STRING': 'bar=baz'}
427 start_response = object()
428 self.dispatcher._module_for_request('/foo').AndReturn(servr)
429 self.dispatcher._handle_request(environ, start_response, servr)
430 self.mox.ReplayAll()
431 self.dispatcher(environ, start_response)
432 self.mox.VerifyAll()
434 def test_module_for_request(self):
436 class FakeDict(dict):
437 def __contains__(self, key):
438 return True
440 def __getitem__(self, key):
441 return key
443 self.dispatcher._module_name_to_module = FakeDict()
444 self.dispatch_config.dispatch = [
445 (dispatchinfo.ParsedURL('*/path'), '1'),
446 (dispatchinfo.ParsedURL('*/other_path/*'), '2'),
447 (dispatchinfo.ParsedURL('*/other_path/'), '3'),
448 (dispatchinfo.ParsedURL('*/other_path'), '3'),
450 self.assertEqual('1', self.dispatcher._module_for_request('/path'))
451 self.assertEqual('2', self.dispatcher._module_for_request('/other_path/'))
452 self.assertEqual('2', self.dispatcher._module_for_request('/other_path/a'))
453 self.assertEqual('3',
454 self.dispatcher._module_for_request('/other_path'))
455 self.assertEqual('default',
456 self.dispatcher._module_for_request('/undispatched'))
458 def test_should_use_dispatch_config(self):
459 """Tests the _should_use_dispatch_config method."""
460 self.assertTrue(self.dispatcher._should_use_dispatch_config('/'))
461 self.assertTrue(self.dispatcher._should_use_dispatch_config('/foo/'))
462 self.assertTrue(self.dispatcher._should_use_dispatch_config(
463 '/_ah/queue/deferred'))
464 self.assertTrue(self.dispatcher._should_use_dispatch_config(
465 '/_ah/queue/deferred/blah'))
467 self.assertFalse(self.dispatcher._should_use_dispatch_config('/_ah/'))
468 self.assertFalse(self.dispatcher._should_use_dispatch_config('/_ah/foo/'))
469 self.assertFalse(self.dispatcher._should_use_dispatch_config(
470 '/_ah/foo/bar/'))
471 self.assertFalse(self.dispatcher._should_use_dispatch_config(
472 '/_ah/queue/'))
474 def test_resolve_target(self):
475 servr = object()
476 inst = object()
477 self.dispatcher._port_registry.add(8080, servr, inst)
478 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
479 self.mox.ReplayAll()
480 self.assertEqual((servr, inst),
481 self.dispatcher._resolve_target('localhost:8080', '/foo'))
482 self.mox.VerifyAll()
484 def test_resolve_target_no_hostname(self):
485 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
486 servr = object()
487 self.dispatcher._module_for_request('/foo').AndReturn(servr)
488 self.mox.ReplayAll()
489 self.assertEqual((servr, None),
490 self.dispatcher._resolve_target(None, '/foo'))
491 self.mox.VerifyAll()
493 def test_resolve_target_dispatcher_port(self):
494 self.dispatcher._port_registry.add(80, None, None)
495 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
496 servr = object()
497 self.dispatcher._module_for_request('/foo').AndReturn(servr)
498 self.mox.ReplayAll()
499 self.assertEqual((servr, None),
500 self.dispatcher._resolve_target('localhost', '/foo'))
501 self.mox.VerifyAll()
503 def test_resolve_target_unknown_port(self):
504 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
505 self.mox.ReplayAll()
506 self.assertRaises(request_info.ModuleDoesNotExistError,
507 self.dispatcher._resolve_target, 'localhost:100', '/foo')
508 self.mox.VerifyAll()
510 def test_resolve_target_module_prefix(self):
511 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
512 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
513 servr = object()
514 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
515 servr)
516 self.mox.ReplayAll()
517 self.assertEqual((servr, None),
518 self.dispatcher._resolve_target('backend.localhost:1',
519 '/foo'))
520 self.mox.VerifyAll()
522 def test_resolve_target_instance_module_prefix(self):
523 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
524 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
525 servr = object()
526 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
527 servr)
528 self.mox.ReplayAll()
529 self.assertEqual((servr, None),
530 self.dispatcher._resolve_target('1.backend.localhost:1',
531 '/foo'))
532 self.mox.VerifyAll()
534 def test_resolve_target_instance_version_module_prefix(self):
535 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
536 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
537 servr = object()
538 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
539 servr)
540 self.mox.ReplayAll()
541 self.assertEqual((servr, None),
542 self.dispatcher._resolve_target('1.v1.backend.localhost:1',
543 '/foo'))
544 self.mox.VerifyAll()
546 def test_get_module_no_modules(self):
547 """Tests the _get_module method with no modules."""
548 self.dispatcher._module_name_to_module = {}
549 self.assertRaises(request_info.ModuleDoesNotExistError,
550 self.dispatcher._get_module,
551 None,
552 None)
554 def test_get_module_default_module(self):
555 """Tests the _get_module method with a default module."""
556 # Test default mopdule is returned for an empty query.
557 self.dispatcher._module_name_to_module = {'default': self.module1}
558 self.assertEqual(self.dispatcher._get_module(None, None), self.module1)
560 self.dispatcher._module_name_to_module['nondefault'] = self.module2
561 self.assertEqual(self.dispatcher._get_module(None, None), self.module1)
563 self.dispatcher._module_name_to_module = {'default': self.module1}
564 self.assertRaises(request_info.ModuleDoesNotExistError,
565 self.dispatcher._get_module,
566 'nondefault',
567 None)
568 # Test version handling.
569 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
570 self.assertEqual(self.dispatcher._get_module('default', 'version'),
571 self.module1)
572 self.assertRaises(request_info.VersionDoesNotExistError,
573 self.dispatcher._get_module,
574 'default',
575 'version2')
577 def test_get_module_non_default(self):
578 """Tests the _get_module method with a non-default module."""
579 self.dispatcher._module_name_to_module = {'default': self.module1,
580 'other': self.module2}
581 self.assertEqual(self.dispatcher._get_module('other', None),
582 self.module2)
583 # Test version handling.
584 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
585 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[1]
586 self.assertEqual(self.dispatcher._get_module('other', 'version2'),
587 self.module2)
588 self.assertRaises(request_info.VersionDoesNotExistError,
589 self.dispatcher._get_module,
590 'other',
591 'version3')
593 def test_get_module_no_default(self):
594 """Tests the _get_module method with no default module."""
595 self.dispatcher._module_name_to_module = {'other': self.module1}
596 self.assertEqual(self.dispatcher._get_module('other', None),
597 self.module1)
598 self.assertRaises(request_info.ModuleDoesNotExistError,
599 self.dispatcher._get_module,
600 None,
601 None)
602 # Test version handling.
603 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[0]
604 self.assertEqual(self.dispatcher._get_module('other', 'version'),
605 self.module1)
606 self.assertRaises(request_info.VersionDoesNotExistError,
607 self.dispatcher._get_module,
608 'other',
609 'version2')
611 def test_get_module_soft_routing_no_modules(self):
612 """Tests the _get_module_soft_routing method with no modules."""
613 self.dispatcher._module_name_to_module = {}
614 self.assertRaises(request_info.ModuleDoesNotExistError,
615 self.dispatcher._get_module_with_soft_routing,
616 None,
617 None)
619 def test_get_module_soft_routing_default_module(self):
620 """Tests the _get_module_soft_routing method with a default module."""
621 # Test default mopdule is returned for an empty query.
622 self.dispatcher._module_name_to_module = {'default': self.module1}
623 self.assertEqual(self.dispatcher._get_module_with_soft_routing(None, None),
624 self.module1)
626 self.dispatcher._module_name_to_module['other'] = self.module2
627 self.assertEqual(self.dispatcher._get_module_with_soft_routing(None, None),
628 self.module1)
630 # Test soft-routing. Querying for a non-existing module should return
631 # default.
632 self.dispatcher._module_name_to_module = {'default': self.module1}
633 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
634 None),
635 self.module1)
637 # Test version handling.
638 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
639 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
640 'version'),
641 self.module1)
642 self.assertEqual(self.dispatcher._get_module_with_soft_routing('default',
643 'version'),
644 self.module1)
645 self.assertRaises(request_info.VersionDoesNotExistError,
646 self.dispatcher._get_module_with_soft_routing,
647 'default',
648 'version2')
649 self.assertRaises(request_info.VersionDoesNotExistError,
650 self.dispatcher._get_module_with_soft_routing,
651 'other',
652 'version2')
654 def test_get_module_soft_routing_non_default(self):
655 """Tests the _get_module_soft_routing method with a non-default module."""
656 self.dispatcher._module_name_to_module = {'default': self.module1,
657 'other': self.module2}
658 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
659 None),
660 self.module2)
661 # Test version handling.
662 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
663 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[1]
664 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
665 'version2'),
666 self.module2)
667 self.assertRaises(request_info.VersionDoesNotExistError,
668 self.dispatcher._get_module_with_soft_routing,
669 'other',
670 'version3')
672 def test_get_module_soft_routing_no_default(self):
673 """Tests the _get_module_soft_routing method with no default module."""
674 self.dispatcher._module_name_to_module = {'other': self.module1}
675 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
676 None),
677 self.module1)
678 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
679 None),
680 self.module1)
681 # Test version handling.
682 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[0]
683 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
684 'version'),
685 self.module1)
686 self.assertRaises(request_info.VersionDoesNotExistError,
687 self.dispatcher._get_module_with_soft_routing,
688 'other',
689 'version2')
691 if __name__ == '__main__':
692 unittest.main()