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."""
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
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
57 self
.normalized_libraries
= []
58 self
.env_variables
= []
60 self
.automatic_scaling
= appinfo
.AutomaticScaling()
61 self
.manual_scaling
= None
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
):
71 class DispatchConfigurationStub(object):
76 MODULE_CONFIGURATIONS
= [
77 ModuleConfigurationStub(application
='app',
78 module_name
='default',
80 manual_scaling
=False),
81 ModuleConfigurationStub(application
='app',
85 ModuleConfigurationStub(application
='app',
86 module_name
='another',
92 class AutoScalingModuleFacade(module
.AutoScalingModule
):
97 super(AutoScalingModuleFacade
, self
).__init
__(
101 api_host
='localhost',
103 auth_domain
='gmail.com',
104 runtime_stderr_loglevel
=1,
108 cloud_sql_config
=None,
109 unused_vm_config
=None,
110 default_version_port
=8080,
115 use_mtime_file_watcher
=False,
116 automatic_restarts
=True,
117 allow_skipped_files
=False,
118 threadsafe_override
=None)
127 def balanced_address(self
):
128 return '%s:%s' % (self
._host
, self
._balanced
_port
)
131 def balanced_port(self
):
132 return self
._balanced
_port
135 class ManualScalingModuleFacade(module
.ManualScalingModule
):
137 module_configuration
,
140 super(ManualScalingModuleFacade
, self
).__init
__(
141 module_configuration
,
144 api_host
='localhost',
146 auth_domain
='gmail.com',
147 runtime_stderr_loglevel
=1,
151 cloud_sql_config
=None,
153 default_version_port
=8080,
158 use_mtime_file_watcher
=False,
159 automatic_restarts
=True,
160 allow_skipped_files
=False,
161 threadsafe_override
=None)
170 def balanced_address(self
):
171 return '%s:%s' % (self
._host
, self
._balanced
_port
)
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(
194 cloud_sql_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
):
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],
223 self
.module2
= ManualScalingModuleFacade(app_config
.modules
[0],
226 self
.module3
= ManualScalingModuleFacade(app_config
.modules
[0],
230 self
.mox
.StubOutWithMock(self
.dispatcher
, '_create_module')
231 self
.dispatcher
._create
_module
(app_config
.modules
[0], 1).AndReturn(
233 self
.dispatcher
._create
_module
(app_config
.modules
[1], 2).AndReturn(
235 self
.dispatcher
._create
_module
(app_config
.modules
[2], 3).AndReturn(
238 self
.dispatcher
.start('localhost', 12345, object())
239 app_config
.dispatch
= self
.dispatch_config
241 self
.mox
.StubOutWithMock(module
.Module
, 'build_request_environ')
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',
265 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
266 self
.dispatcher
.get_hostname
,
270 self
.assertEqual('%s:3' % socket
.gethostname(),
271 self
.dispatcher
.get_hostname('another', 'version3'))
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')
299 scheduled_executor
.ScheduledExecutor
.add_event(runnable
, 123, ('foo',
301 scheduled_executor
.ScheduledExecutor
.add_event(runnable
, 124, None)
303 self
.dispatcher
.add_event(runnable
, 123, 'foo', 'bar')
304 self
.dispatcher
.add_event(runnable
, 124)
307 def test_update_event(self
):
308 self
.mox
.StubOutWithMock(scheduled_executor
.ScheduledExecutor
,
310 scheduled_executor
.ScheduledExecutor
.update_event(123, ('foo', 'bar'))
312 self
.dispatcher
.update_event(123, 'foo', 'bar')
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(
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)
327 self
.dispatcher
.add_async_request(
328 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
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(
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)
344 self
.dispatcher
.add_async_request(
345 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
346 'body', '1.2.3.4', module_name
='other')
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(
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)
362 self
.dispatcher
.add_async_request(
363 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
364 'body', '1.2.3.4', module_name
='nomodule')
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(
377 self
.dispatcher
._handle
_request
(
378 dummy_environ
, mox
.IgnoreArg(),
379 self
.dispatcher
._module
_name
_to
_module
['default'],
380 None).AndReturn(['Hello World'])
382 response
= self
.dispatcher
.add_request(
383 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
384 'body', '1.2.3.4', fake_login
=True)
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(
396 self
.dispatcher
._handle
_request
(
397 dummy_environ
, mox
.IgnoreArg(),
398 self
.dispatcher
._module
_name
_to
_module
['default'],
399 None).AndReturn(['Hello World'])
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')
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'])
414 self
.dispatcher
._handle
_request
({'foo': 'bar'}, start_response
, servr
, None,
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)
424 self
.assertRaises(Exception, self
.dispatcher
._handle
_request
,
425 {'foo': 'bar'}, start_response
, servr
, None)
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.')
436 self
.dispatcher
._handle
_request
({'foo': 'bar'}, start_response
, servr
, None,
437 catch_and_log_exceptions
=True)
441 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
442 self
.mox
.StubOutWithMock(self
.dispatcher
, '_handle_request')
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
)
449 self
.dispatcher(environ
, start_response
)
452 def test_module_for_request(self
):
454 class FakeDict(dict):
455 def __contains__(self
, key
):
458 def __getitem__(self
, 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
(
489 self
.assertFalse(self
.dispatcher
._should
_use
_dispatch
_config
(
492 def test_resolve_target(self
):
495 self
.dispatcher
._port
_registry
.add(8080, servr
, inst
)
496 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
498 self
.assertEqual((servr
, inst
),
499 self
.dispatcher
._resolve
_target
('localhost:8080', '/foo'))
502 def test_resolve_target_no_hostname(self
):
503 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
505 self
.dispatcher
._module
_for
_request
('/foo').AndReturn(servr
)
507 self
.assertEqual((servr
, None),
508 self
.dispatcher
._resolve
_target
(None, '/foo'))
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')
515 self
.dispatcher
._module
_for
_request
('/foo').AndReturn(servr
)
517 self
.assertEqual((servr
, None),
518 self
.dispatcher
._resolve
_target
('localhost', '/foo'))
521 def test_resolve_target_unknown_port(self
):
522 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
524 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
525 self
.dispatcher
._resolve
_target
, 'localhost:100', '/foo')
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')
532 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
535 self
.assertEqual((servr
, None),
536 self
.dispatcher
._resolve
_target
('backend.localhost:1',
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')
544 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
547 self
.assertEqual((servr
, None),
548 self
.dispatcher
._resolve
_target
('1.backend.localhost:1',
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')
556 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
559 self
.assertEqual((servr
, None),
560 self
.dispatcher
._resolve
_target
('1.v1.backend.localhost:1',
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
,
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
,
586 # Test version handling.
587 self
.dispatcher
._module
_configurations
['default'] = MODULE_CONFIGURATIONS
[0]
588 self
.assertEqual(self
.dispatcher
._get
_module
('default', 'version'),
590 self
.assertRaises(request_info
.VersionDoesNotExistError
,
591 self
.dispatcher
._get
_module
,
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),
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'),
606 self
.assertRaises(request_info
.VersionDoesNotExistError
,
607 self
.dispatcher
._get
_module
,
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),
616 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
617 self
.dispatcher
._get
_module
,
620 # Test version handling.
621 self
.dispatcher
._module
_configurations
['other'] = MODULE_CONFIGURATIONS
[0]
622 self
.assertEqual(self
.dispatcher
._get
_module
('other', 'version'),
624 self
.assertRaises(request_info
.VersionDoesNotExistError
,
625 self
.dispatcher
._get
_module
,
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
,
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),
644 self
.dispatcher
._module
_name
_to
_module
['other'] = self
.module2
645 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
(None, None),
648 # Test soft-routing. Querying for a non-existing module should return
650 self
.dispatcher
._module
_name
_to
_module
= {'default': self
.module1
}
651 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
655 # Test version handling.
656 self
.dispatcher
._module
_configurations
['default'] = MODULE_CONFIGURATIONS
[0]
657 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
660 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('default',
663 self
.assertRaises(request_info
.VersionDoesNotExistError
,
664 self
.dispatcher
._get
_module
_with
_soft
_routing
,
667 self
.assertRaises(request_info
.VersionDoesNotExistError
,
668 self
.dispatcher
._get
_module
_with
_soft
_routing
,
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',
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',
685 self
.assertRaises(request_info
.VersionDoesNotExistError
,
686 self
.dispatcher
._get
_module
_with
_soft
_routing
,
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',
696 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
699 # Test version handling.
700 self
.dispatcher
._module
_configurations
['other'] = MODULE_CONFIGURATIONS
[0]
701 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
704 self
.assertRaises(request_info
.VersionDoesNotExistError
,
705 self
.dispatcher
._get
_module
_with
_soft
_routing
,
709 if __name__
== '__main__':