App Engine Python SDK version 1.9.12
[gae.git] / python / google / appengine / tools / devappserver2 / dispatcher_test.py
blobba1b88aeb48b25a4ee8bcb5ebb736a76a160a9ad
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 socket
21 import unittest
23 import google
25 import mox
27 from google.appengine.api import appinfo
28 from google.appengine.api import dispatchinfo
29 from google.appengine.api import request_info
30 from google.appengine.tools.devappserver2 import api_server
31 from google.appengine.tools.devappserver2 import constants
32 from google.appengine.tools.devappserver2 import dispatcher
33 from google.appengine.tools.devappserver2 import scheduled_executor
34 from google.appengine.tools.devappserver2 import module
36 # This file uses pep8 naming.
37 # pylint: disable=invalid-name
40 class ApplicationConfigurationStub(object):
41 def __init__(self, modules):
42 self.modules = modules
43 self.dispatch = None
46 class ModuleConfigurationStub(object):
47 def __init__(self, application, module_name, version, manual_scaling):
48 self.application_root = '/'
49 self.application = application
50 self.module_name = module_name
51 self.major_version = version
52 self.version_id = '%s:%s.%s' % (module_name, version, '12345')
53 self.runtime = 'python27'
54 self.threadsafe = False
55 self.handlers = []
56 self.skip_files = []
57 self.normalized_libraries = []
58 self.env_variables = []
59 if manual_scaling:
60 self.automatic_scaling = appinfo.AutomaticScaling()
61 self.manual_scaling = None
62 else:
63 self.automatic_scaling = None
64 self.manual_scaling = appinfo.ManualScaling(instances=1)
65 self.inbound_services = None
67 def add_change_callback(self, fn):
68 pass
71 class DispatchConfigurationStub(object):
72 def __init__(self):
73 self.dispatch = []
76 MODULE_CONFIGURATIONS = [
77 ModuleConfigurationStub(application='app',
78 module_name='default',
79 version='version',
80 manual_scaling=False),
81 ModuleConfigurationStub(application='app',
82 module_name='other',
83 version='version2',
84 manual_scaling=True),
85 ModuleConfigurationStub(application='app',
86 module_name='another',
87 version='version3',
88 manual_scaling=True),
92 class AutoScalingModuleFacade(module.AutoScalingModule):
93 def __init__(self,
94 module_configuration,
95 host='fakehost',
96 balanced_port=0):
97 super(AutoScalingModuleFacade, self).__init__(
98 module_configuration,
99 host,
100 balanced_port,
101 api_host='localhost',
102 api_port=8080,
103 auth_domain='gmail.com',
104 runtime_stderr_loglevel=1,
105 php_config=None,
106 python_config=None,
107 java_config=None,
108 cloud_sql_config=None,
109 unused_vm_config=None,
110 default_version_port=8080,
111 port_registry=None,
112 request_data=None,
113 dispatcher=None,
114 max_instances=None,
115 use_mtime_file_watcher=False,
116 automatic_restarts=True,
117 allow_skipped_files=False,
118 threadsafe_override=None)
120 def start(self):
121 pass
123 def quit(self):
124 pass
126 @property
127 def balanced_address(self):
128 return '%s:%s' % (self._host, self._balanced_port)
130 @property
131 def balanced_port(self):
132 return self._balanced_port
135 class ManualScalingModuleFacade(module.ManualScalingModule):
136 def __init__(self,
137 module_configuration,
138 host='fakehost',
139 balanced_port=0):
140 super(ManualScalingModuleFacade, self).__init__(
141 module_configuration,
142 host,
143 balanced_port,
144 api_host='localhost',
145 api_port=8080,
146 auth_domain='gmail.com',
147 runtime_stderr_loglevel=1,
148 php_config=None,
149 python_config=None,
150 java_config=None,
151 cloud_sql_config=None,
152 vm_config=None,
153 default_version_port=8080,
154 port_registry=None,
155 request_data=None,
156 dispatcher=None,
157 max_instances=None,
158 use_mtime_file_watcher=False,
159 automatic_restarts=True,
160 allow_skipped_files=False,
161 threadsafe_override=None)
163 def start(self):
164 pass
166 def quit(self):
167 pass
169 @property
170 def balanced_address(self):
171 return '%s:%s' % (self._host, self._balanced_port)
173 @property
174 def balanced_port(self):
175 return self._balanced_port
177 def get_instance_address(self, instance):
178 if instance == 'invalid':
179 raise request_info.InvalidInstanceIdError()
180 return '%s:%s' % (self._host, int(instance) + 1000)
183 def _make_dispatcher(app_config):
184 """Make a new dispatcher with the given ApplicationConfigurationStub."""
185 return dispatcher.Dispatcher(
186 app_config,
187 'localhost',
189 'gmail.com',
191 php_config=None,
192 python_config=None,
193 java_config=None,
194 cloud_sql_config=None,
195 vm_config=None,
196 module_to_max_instances={},
197 use_mtime_file_watcher=False,
198 automatic_restart=True,
199 allow_skipped_files=False,
200 module_to_threadsafe_override={})
203 class DispatcherQuitWithoutStartTest(unittest.TestCase):
205 def test_quit_without_start(self):
206 """Test that calling quit on a dispatcher without calling start is safe."""
207 app_config = ApplicationConfigurationStub(MODULE_CONFIGURATIONS)
208 unstarted_dispatcher = _make_dispatcher(app_config)
209 unstarted_dispatcher.quit()
212 class DispatcherTest(unittest.TestCase):
214 def setUp(self):
215 self.mox = mox.Mox()
216 api_server.test_setup_stubs()
217 self.dispatch_config = DispatchConfigurationStub()
218 app_config = ApplicationConfigurationStub(MODULE_CONFIGURATIONS)
219 self.dispatcher = _make_dispatcher(app_config)
220 self.module1 = AutoScalingModuleFacade(app_config.modules[0],
221 balanced_port=1,
222 host='localhost')
223 self.module2 = ManualScalingModuleFacade(app_config.modules[0],
224 balanced_port=2,
225 host='localhost')
226 self.module3 = ManualScalingModuleFacade(app_config.modules[0],
227 balanced_port=3,
228 host='0.0.0.0')
230 self.mox.StubOutWithMock(self.dispatcher, '_create_module')
231 self.dispatcher._create_module(app_config.modules[0], 1).AndReturn(
232 (self.module1, 2))
233 self.dispatcher._create_module(app_config.modules[1], 2).AndReturn(
234 (self.module2, 3))
235 self.dispatcher._create_module(app_config.modules[2], 3).AndReturn(
236 (self.module3, 4))
237 self.mox.ReplayAll()
238 self.dispatcher.start('localhost', 12345, object())
239 app_config.dispatch = self.dispatch_config
240 self.mox.VerifyAll()
241 self.mox.StubOutWithMock(module.Module, 'build_request_environ')
243 def tearDown(self):
244 self.dispatcher.quit()
245 self.mox.UnsetStubs()
247 def test_get_module_names(self):
248 self.assertItemsEqual(['default', 'other', 'another'],
249 self.dispatcher.get_module_names())
251 def test_get_hostname(self):
252 self.assertEqual('localhost:1',
253 self.dispatcher.get_hostname('default', 'version'))
254 self.assertEqual('localhost:2',
255 self.dispatcher.get_hostname('other', 'version2'))
256 self.assertRaises(request_info.VersionDoesNotExistError,
257 self.dispatcher.get_hostname, 'default', 'fake')
258 self.assertRaises(request_info.NotSupportedWithAutoScalingError,
259 self.dispatcher.get_hostname, 'default', 'version', '0')
260 self.assertEqual('localhost:1000',
261 self.dispatcher.get_hostname('other', 'version2', '0'))
262 self.assertRaises(request_info.InvalidInstanceIdError,
263 self.dispatcher.get_hostname, 'other', 'version2',
264 'invalid')
265 self.assertRaises(request_info.ModuleDoesNotExistError,
266 self.dispatcher.get_hostname,
267 'nomodule',
268 'version2',
269 None)
270 self.assertEqual('%s:3' % socket.gethostname(),
271 self.dispatcher.get_hostname('another', 'version3'))
272 self.assertEqual(
273 '%s:1000' % socket.gethostname(),
274 self.dispatcher.get_hostname('another', 'version3', '0'))
276 def test_get_module_by_name(self):
277 self.assertEqual(self.module1,
278 self.dispatcher.get_module_by_name('default'))
279 self.assertEqual(self.module2,
280 self.dispatcher.get_module_by_name('other'))
281 self.assertRaises(request_info.ModuleDoesNotExistError,
282 self.dispatcher.get_module_by_name, 'fake')
284 def test_get_versions(self):
285 self.assertEqual(['version'], self.dispatcher.get_versions('default'))
286 self.assertEqual(['version2'], self.dispatcher.get_versions('other'))
287 self.assertRaises(request_info.ModuleDoesNotExistError,
288 self.dispatcher.get_versions, 'fake')
290 def test_get_default_version(self):
291 self.assertEqual('version', self.dispatcher.get_default_version('default'))
292 self.assertEqual('version2', self.dispatcher.get_default_version('other'))
293 self.assertRaises(request_info.ModuleDoesNotExistError,
294 self.dispatcher.get_default_version, 'fake')
296 def test_add_event(self):
297 self.mox.StubOutWithMock(scheduled_executor.ScheduledExecutor, 'add_event')
298 runnable = object()
299 scheduled_executor.ScheduledExecutor.add_event(runnable, 123, ('foo',
300 'bar'))
301 scheduled_executor.ScheduledExecutor.add_event(runnable, 124, None)
302 self.mox.ReplayAll()
303 self.dispatcher.add_event(runnable, 123, 'foo', 'bar')
304 self.dispatcher.add_event(runnable, 124)
305 self.mox.VerifyAll()
307 def test_update_event(self):
308 self.mox.StubOutWithMock(scheduled_executor.ScheduledExecutor,
309 'update_event')
310 scheduled_executor.ScheduledExecutor.update_event(123, ('foo', 'bar'))
311 self.mox.ReplayAll()
312 self.dispatcher.update_event(123, 'foo', 'bar')
313 self.mox.VerifyAll()
315 def test_add_async_request(self):
316 dummy_environ = object()
317 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
318 self.dispatcher._module_name_to_module['default'].build_request_environ(
319 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
320 'body', '1.2.3.4', 1).AndReturn(
321 dummy_environ)
322 dispatcher._THREAD_POOL.submit(
323 self.dispatcher._handle_request, dummy_environ, mox.IgnoreArg(),
324 self.dispatcher._module_name_to_module['default'],
325 None, catch_and_log_exceptions=True)
326 self.mox.ReplayAll()
327 self.dispatcher.add_async_request(
328 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
329 'body', '1.2.3.4')
330 self.mox.VerifyAll()
332 def test_add_async_request_specific_module(self):
333 dummy_environ = object()
334 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
335 self.dispatcher._module_name_to_module['other'].build_request_environ(
336 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
337 'body', '1.2.3.4', 2).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['other'],
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='other')
347 self.mox.VerifyAll()
349 def test_add_async_request_soft_routing(self):
350 """Tests add_async_request with soft routing."""
351 dummy_environ = object()
352 self.mox.StubOutWithMock(dispatcher._THREAD_POOL, 'submit')
353 self.dispatcher._module_name_to_module['default'].build_request_environ(
354 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
355 'body', '1.2.3.4', 1).AndReturn(
356 dummy_environ)
357 dispatcher._THREAD_POOL.submit(
358 self.dispatcher._handle_request, dummy_environ, mox.IgnoreArg(),
359 self.dispatcher._module_name_to_module['default'],
360 None, catch_and_log_exceptions=True)
361 self.mox.ReplayAll()
362 self.dispatcher.add_async_request(
363 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
364 'body', '1.2.3.4', module_name='nomodule')
365 self.mox.VerifyAll()
367 def test_add_request(self):
368 dummy_environ = object()
369 self.mox.StubOutWithMock(self.dispatcher, '_resolve_target')
370 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
371 self.dispatcher._resolve_target(None, '/foo').AndReturn(
372 (self.dispatcher._module_name_to_module['default'], None))
373 self.dispatcher._module_name_to_module['default'].build_request_environ(
374 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
375 'body', '1.2.3.4', 1, fake_login=True).AndReturn(
376 dummy_environ)
377 self.dispatcher._handle_request(
378 dummy_environ, mox.IgnoreArg(),
379 self.dispatcher._module_name_to_module['default'],
380 None).AndReturn(['Hello World'])
381 self.mox.ReplayAll()
382 response = self.dispatcher.add_request(
383 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
384 'body', '1.2.3.4', fake_login=True)
385 self.mox.VerifyAll()
386 self.assertEqual('Hello World', response.content)
388 def test_add_request_soft_routing(self):
389 """Tests soft routing to the default module."""
390 dummy_environ = object()
391 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
392 self.dispatcher._module_name_to_module['default'].build_request_environ(
393 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
394 'body', '1.2.3.4', 1, fake_login=True).AndReturn(
395 dummy_environ)
396 self.dispatcher._handle_request(
397 dummy_environ, mox.IgnoreArg(),
398 self.dispatcher._module_name_to_module['default'],
399 None).AndReturn(['Hello World'])
400 self.mox.ReplayAll()
401 response = self.dispatcher.add_request(
402 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
403 'body', '1.2.3.4', fake_login=True, module_name='nomodule')
404 self.mox.VerifyAll()
405 self.assertEqual('Hello World', response.content)
407 def test_handle_request(self):
408 start_response = object()
409 servr = self.dispatcher._module_name_to_module['other']
410 self.mox.StubOutWithMock(servr, '_handle_request')
411 servr._handle_request({'foo': 'bar'}, start_response, inst=None,
412 request_type=3).AndReturn(['body'])
413 self.mox.ReplayAll()
414 self.dispatcher._handle_request({'foo': 'bar'}, start_response, servr, None,
415 request_type=3)
416 self.mox.VerifyAll()
418 def test_handle_request_reraise_exception(self):
419 start_response = object()
420 servr = self.dispatcher._module_name_to_module['other']
421 self.mox.StubOutWithMock(servr, '_handle_request')
422 servr._handle_request({'foo': 'bar'}, start_response).AndRaise(Exception)
423 self.mox.ReplayAll()
424 self.assertRaises(Exception, self.dispatcher._handle_request,
425 {'foo': 'bar'}, start_response, servr, None)
426 self.mox.VerifyAll()
428 def test_handle_request_log_exception(self):
429 start_response = object()
430 servr = self.dispatcher._module_name_to_module['other']
431 self.mox.StubOutWithMock(servr, '_handle_request')
432 self.mox.StubOutWithMock(logging, 'exception')
433 servr._handle_request({'foo': 'bar'}, start_response).AndRaise(Exception)
434 logging.exception('Internal error while handling request.')
435 self.mox.ReplayAll()
436 self.dispatcher._handle_request({'foo': 'bar'}, start_response, servr, None,
437 catch_and_log_exceptions=True)
438 self.mox.VerifyAll()
440 def test_call(self):
441 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
442 self.mox.StubOutWithMock(self.dispatcher, '_handle_request')
443 servr = object()
444 environ = {'PATH_INFO': '/foo', 'QUERY_STRING': 'bar=baz'}
445 start_response = object()
446 self.dispatcher._module_for_request('/foo').AndReturn(servr)
447 self.dispatcher._handle_request(environ, start_response, servr)
448 self.mox.ReplayAll()
449 self.dispatcher(environ, start_response)
450 self.mox.VerifyAll()
452 def test_module_for_request(self):
454 class FakeDict(dict):
455 def __contains__(self, key):
456 return True
458 def __getitem__(self, key):
459 return key
461 self.dispatcher._module_name_to_module = FakeDict()
462 self.dispatch_config.dispatch = [
463 (dispatchinfo.ParsedURL('*/path'), '1'),
464 (dispatchinfo.ParsedURL('*/other_path/*'), '2'),
465 (dispatchinfo.ParsedURL('*/other_path/'), '3'),
466 (dispatchinfo.ParsedURL('*/other_path'), '3'),
468 self.assertEqual('1', self.dispatcher._module_for_request('/path'))
469 self.assertEqual('2', self.dispatcher._module_for_request('/other_path/'))
470 self.assertEqual('2', self.dispatcher._module_for_request('/other_path/a'))
471 self.assertEqual('3',
472 self.dispatcher._module_for_request('/other_path'))
473 self.assertEqual('default',
474 self.dispatcher._module_for_request('/undispatched'))
476 def test_should_use_dispatch_config(self):
477 """Tests the _should_use_dispatch_config method."""
478 self.assertTrue(self.dispatcher._should_use_dispatch_config('/'))
479 self.assertTrue(self.dispatcher._should_use_dispatch_config('/foo/'))
480 self.assertTrue(self.dispatcher._should_use_dispatch_config(
481 '/_ah/queue/deferred'))
482 self.assertTrue(self.dispatcher._should_use_dispatch_config(
483 '/_ah/queue/deferred/blah'))
485 self.assertFalse(self.dispatcher._should_use_dispatch_config('/_ah/'))
486 self.assertFalse(self.dispatcher._should_use_dispatch_config('/_ah/foo/'))
487 self.assertFalse(self.dispatcher._should_use_dispatch_config(
488 '/_ah/foo/bar/'))
489 self.assertFalse(self.dispatcher._should_use_dispatch_config(
490 '/_ah/queue/'))
492 def test_resolve_target(self):
493 servr = object()
494 inst = object()
495 self.dispatcher._port_registry.add(8080, servr, inst)
496 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
497 self.mox.ReplayAll()
498 self.assertEqual((servr, inst),
499 self.dispatcher._resolve_target('localhost:8080', '/foo'))
500 self.mox.VerifyAll()
502 def test_resolve_target_no_hostname(self):
503 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
504 servr = object()
505 self.dispatcher._module_for_request('/foo').AndReturn(servr)
506 self.mox.ReplayAll()
507 self.assertEqual((servr, None),
508 self.dispatcher._resolve_target(None, '/foo'))
509 self.mox.VerifyAll()
511 def test_resolve_target_dispatcher_port(self):
512 self.dispatcher._port_registry.add(80, None, None)
513 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
514 servr = object()
515 self.dispatcher._module_for_request('/foo').AndReturn(servr)
516 self.mox.ReplayAll()
517 self.assertEqual((servr, None),
518 self.dispatcher._resolve_target('localhost', '/foo'))
519 self.mox.VerifyAll()
521 def test_resolve_target_unknown_port(self):
522 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
523 self.mox.ReplayAll()
524 self.assertRaises(request_info.ModuleDoesNotExistError,
525 self.dispatcher._resolve_target, 'localhost:100', '/foo')
526 self.mox.VerifyAll()
528 def test_resolve_target_module_prefix(self):
529 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
530 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
531 servr = object()
532 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
533 servr)
534 self.mox.ReplayAll()
535 self.assertEqual((servr, None),
536 self.dispatcher._resolve_target('backend.localhost:1',
537 '/foo'))
538 self.mox.VerifyAll()
540 def test_resolve_target_instance_module_prefix(self):
541 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
542 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
543 servr = object()
544 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
545 servr)
546 self.mox.ReplayAll()
547 self.assertEqual((servr, None),
548 self.dispatcher._resolve_target('1.backend.localhost:1',
549 '/foo'))
550 self.mox.VerifyAll()
552 def test_resolve_target_instance_version_module_prefix(self):
553 self.mox.StubOutWithMock(self.dispatcher, '_module_for_request')
554 self.mox.StubOutWithMock(self.dispatcher, '_get_module_with_soft_routing')
555 servr = object()
556 self.dispatcher._get_module_with_soft_routing('backend', None).AndReturn(
557 servr)
558 self.mox.ReplayAll()
559 self.assertEqual((servr, None),
560 self.dispatcher._resolve_target('1.v1.backend.localhost:1',
561 '/foo'))
562 self.mox.VerifyAll()
564 def test_get_module_no_modules(self):
565 """Tests the _get_module method with no modules."""
566 self.dispatcher._module_name_to_module = {}
567 self.assertRaises(request_info.ModuleDoesNotExistError,
568 self.dispatcher._get_module,
569 None,
570 None)
572 def test_get_module_default_module(self):
573 """Tests the _get_module method with a default module."""
574 # Test default mopdule is returned for an empty query.
575 self.dispatcher._module_name_to_module = {'default': self.module1}
576 self.assertEqual(self.dispatcher._get_module(None, None), self.module1)
578 self.dispatcher._module_name_to_module['nondefault'] = self.module2
579 self.assertEqual(self.dispatcher._get_module(None, None), self.module1)
581 self.dispatcher._module_name_to_module = {'default': self.module1}
582 self.assertRaises(request_info.ModuleDoesNotExistError,
583 self.dispatcher._get_module,
584 'nondefault',
585 None)
586 # Test version handling.
587 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
588 self.assertEqual(self.dispatcher._get_module('default', 'version'),
589 self.module1)
590 self.assertRaises(request_info.VersionDoesNotExistError,
591 self.dispatcher._get_module,
592 'default',
593 'version2')
595 def test_get_module_non_default(self):
596 """Tests the _get_module method with a non-default module."""
597 self.dispatcher._module_name_to_module = {'default': self.module1,
598 'other': self.module2}
599 self.assertEqual(self.dispatcher._get_module('other', None),
600 self.module2)
601 # Test version handling.
602 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
603 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[1]
604 self.assertEqual(self.dispatcher._get_module('other', 'version2'),
605 self.module2)
606 self.assertRaises(request_info.VersionDoesNotExistError,
607 self.dispatcher._get_module,
608 'other',
609 'version3')
611 def test_get_module_no_default(self):
612 """Tests the _get_module method with no default module."""
613 self.dispatcher._module_name_to_module = {'other': self.module1}
614 self.assertEqual(self.dispatcher._get_module('other', None),
615 self.module1)
616 self.assertRaises(request_info.ModuleDoesNotExistError,
617 self.dispatcher._get_module,
618 None,
619 None)
620 # Test version handling.
621 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[0]
622 self.assertEqual(self.dispatcher._get_module('other', 'version'),
623 self.module1)
624 self.assertRaises(request_info.VersionDoesNotExistError,
625 self.dispatcher._get_module,
626 'other',
627 'version2')
629 def test_get_module_soft_routing_no_modules(self):
630 """Tests the _get_module_soft_routing method with no modules."""
631 self.dispatcher._module_name_to_module = {}
632 self.assertRaises(request_info.ModuleDoesNotExistError,
633 self.dispatcher._get_module_with_soft_routing,
634 None,
635 None)
637 def test_get_module_soft_routing_default_module(self):
638 """Tests the _get_module_soft_routing method with a default module."""
639 # Test default mopdule is returned for an empty query.
640 self.dispatcher._module_name_to_module = {'default': self.module1}
641 self.assertEqual(self.dispatcher._get_module_with_soft_routing(None, None),
642 self.module1)
644 self.dispatcher._module_name_to_module['other'] = self.module2
645 self.assertEqual(self.dispatcher._get_module_with_soft_routing(None, None),
646 self.module1)
648 # Test soft-routing. Querying for a non-existing module should return
649 # default.
650 self.dispatcher._module_name_to_module = {'default': self.module1}
651 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
652 None),
653 self.module1)
655 # Test version handling.
656 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
657 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
658 'version'),
659 self.module1)
660 self.assertEqual(self.dispatcher._get_module_with_soft_routing('default',
661 'version'),
662 self.module1)
663 self.assertRaises(request_info.VersionDoesNotExistError,
664 self.dispatcher._get_module_with_soft_routing,
665 'default',
666 'version2')
667 self.assertRaises(request_info.VersionDoesNotExistError,
668 self.dispatcher._get_module_with_soft_routing,
669 'other',
670 'version2')
672 def test_get_module_soft_routing_non_default(self):
673 """Tests the _get_module_soft_routing method with a non-default module."""
674 self.dispatcher._module_name_to_module = {'default': self.module1,
675 'other': self.module2}
676 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
677 None),
678 self.module2)
679 # Test version handling.
680 self.dispatcher._module_configurations['default'] = MODULE_CONFIGURATIONS[0]
681 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[1]
682 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
683 'version2'),
684 self.module2)
685 self.assertRaises(request_info.VersionDoesNotExistError,
686 self.dispatcher._get_module_with_soft_routing,
687 'other',
688 'version3')
690 def test_get_module_soft_routing_no_default(self):
691 """Tests the _get_module_soft_routing method with no default module."""
692 self.dispatcher._module_name_to_module = {'other': self.module1}
693 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
694 None),
695 self.module1)
696 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
697 None),
698 self.module1)
699 # Test version handling.
700 self.dispatcher._module_configurations['other'] = MODULE_CONFIGURATIONS[0]
701 self.assertEqual(self.dispatcher._get_module_with_soft_routing('other',
702 'version'),
703 self.module1)
704 self.assertRaises(request_info.VersionDoesNotExistError,
705 self.dispatcher._get_module_with_soft_routing,
706 'other',
707 'version2')
709 if __name__ == '__main__':
710 unittest.main()