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."""
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
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
56 self
.normalized_libraries
= []
57 self
.env_variables
= []
59 self
.automatic_scaling
= appinfo
.AutomaticScaling()
60 self
.manual_scaling
= None
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
):
70 class DispatchConfigurationStub(object):
75 MODULE_CONFIGURATIONS
= [
76 ModuleConfigurationStub(application
='app',
77 module_name
='default',
79 manual_scaling
=False),
80 ModuleConfigurationStub(application
='app',
87 class AutoScalingModuleFacade(module
.AutoScalingModule
):
92 super(AutoScalingModuleFacade
, self
).__init
__(
98 auth_domain
='gmail.com',
99 runtime_stderr_loglevel
=1,
102 cloud_sql_config
=None,
103 unused_vm_config
=None,
104 default_version_port
=8080,
109 use_mtime_file_watcher
=False,
110 automatic_restarts
=True,
111 allow_skipped_files
=False,
112 threadsafe_override
=None)
121 def balanced_address(self
):
122 return '%s:%s' % (self
._host
, self
._balanced
_port
)
125 def balanced_port(self
):
126 return self
._balanced
_port
129 class ManualScalingModuleFacade(module
.ManualScalingModule
):
131 module_configuration
,
134 super(ManualScalingModuleFacade
, self
).__init
__(
135 module_configuration
,
138 api_host
='localhost',
140 auth_domain
='gmail.com',
141 runtime_stderr_loglevel
=1,
144 cloud_sql_config
=None,
146 default_version_port
=8080,
151 use_mtime_file_watcher
=False,
152 automatic_restarts
=True,
153 allow_skipped_files
=False,
154 threadsafe_override
=None)
163 def balanced_address(self
):
164 return '%s:%s' % (self
._host
, self
._balanced
_port
)
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(
186 cloud_sql_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
):
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],
215 self
.module2
= ManualScalingModuleFacade(app_config
.modules
[0],
219 self
.mox
.StubOutWithMock(self
.dispatcher
, '_create_module')
220 self
.dispatcher
._create
_module
(app_config
.modules
[0], 1).AndReturn(
222 self
.dispatcher
._create
_module
(app_config
.modules
[1], 2).AndReturn(
225 self
.dispatcher
.start('localhost', 12345, object())
226 app_config
.dispatch
= self
.dispatch_config
228 self
.mox
.StubOutWithMock(module
.Module
, 'build_request_environ')
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',
252 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
253 self
.dispatcher
.get_hostname
,
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')
281 scheduled_executor
.ScheduledExecutor
.add_event(runnable
, 123, ('foo',
283 scheduled_executor
.ScheduledExecutor
.add_event(runnable
, 124, None)
285 self
.dispatcher
.add_event(runnable
, 123, 'foo', 'bar')
286 self
.dispatcher
.add_event(runnable
, 124)
289 def test_update_event(self
):
290 self
.mox
.StubOutWithMock(scheduled_executor
.ScheduledExecutor
,
292 scheduled_executor
.ScheduledExecutor
.update_event(123, ('foo', 'bar'))
294 self
.dispatcher
.update_event(123, 'foo', 'bar')
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(
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)
309 self
.dispatcher
.add_async_request(
310 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
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(
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)
326 self
.dispatcher
.add_async_request(
327 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
328 'body', '1.2.3.4', module_name
='other')
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(
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)
344 self
.dispatcher
.add_async_request(
345 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
346 'body', '1.2.3.4', module_name
='nomodule')
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(
359 self
.dispatcher
._handle
_request
(
360 dummy_environ
, mox
.IgnoreArg(),
361 self
.dispatcher
._module
_name
_to
_module
['default'],
362 None).AndReturn(['Hello World'])
364 response
= self
.dispatcher
.add_request(
365 'PUT', '/foo?bar=baz', [('Header', 'Value'), ('Other', 'Values')],
366 'body', '1.2.3.4', fake_login
=True)
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(
378 self
.dispatcher
._handle
_request
(
379 dummy_environ
, mox
.IgnoreArg(),
380 self
.dispatcher
._module
_name
_to
_module
['default'],
381 None).AndReturn(['Hello World'])
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')
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'])
396 self
.dispatcher
._handle
_request
({'foo': 'bar'}, start_response
, servr
, None,
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)
406 self
.assertRaises(Exception, self
.dispatcher
._handle
_request
,
407 {'foo': 'bar'}, start_response
, servr
, None)
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.')
418 self
.dispatcher
._handle
_request
({'foo': 'bar'}, start_response
, servr
, None,
419 catch_and_log_exceptions
=True)
423 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
424 self
.mox
.StubOutWithMock(self
.dispatcher
, '_handle_request')
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
)
431 self
.dispatcher(environ
, start_response
)
434 def test_module_for_request(self
):
436 class FakeDict(dict):
437 def __contains__(self
, key
):
440 def __getitem__(self
, 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
(
471 self
.assertFalse(self
.dispatcher
._should
_use
_dispatch
_config
(
474 def test_resolve_target(self
):
477 self
.dispatcher
._port
_registry
.add(8080, servr
, inst
)
478 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
480 self
.assertEqual((servr
, inst
),
481 self
.dispatcher
._resolve
_target
('localhost:8080', '/foo'))
484 def test_resolve_target_no_hostname(self
):
485 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
487 self
.dispatcher
._module
_for
_request
('/foo').AndReturn(servr
)
489 self
.assertEqual((servr
, None),
490 self
.dispatcher
._resolve
_target
(None, '/foo'))
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')
497 self
.dispatcher
._module
_for
_request
('/foo').AndReturn(servr
)
499 self
.assertEqual((servr
, None),
500 self
.dispatcher
._resolve
_target
('localhost', '/foo'))
503 def test_resolve_target_unknown_port(self
):
504 self
.mox
.StubOutWithMock(self
.dispatcher
, '_module_for_request')
506 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
507 self
.dispatcher
._resolve
_target
, 'localhost:100', '/foo')
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')
514 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
517 self
.assertEqual((servr
, None),
518 self
.dispatcher
._resolve
_target
('backend.localhost:1',
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')
526 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
529 self
.assertEqual((servr
, None),
530 self
.dispatcher
._resolve
_target
('1.backend.localhost:1',
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')
538 self
.dispatcher
._get
_module
_with
_soft
_routing
('backend', None).AndReturn(
541 self
.assertEqual((servr
, None),
542 self
.dispatcher
._resolve
_target
('1.v1.backend.localhost:1',
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
,
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
,
568 # Test version handling.
569 self
.dispatcher
._module
_configurations
['default'] = MODULE_CONFIGURATIONS
[0]
570 self
.assertEqual(self
.dispatcher
._get
_module
('default', 'version'),
572 self
.assertRaises(request_info
.VersionDoesNotExistError
,
573 self
.dispatcher
._get
_module
,
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),
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'),
588 self
.assertRaises(request_info
.VersionDoesNotExistError
,
589 self
.dispatcher
._get
_module
,
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),
598 self
.assertRaises(request_info
.ModuleDoesNotExistError
,
599 self
.dispatcher
._get
_module
,
602 # Test version handling.
603 self
.dispatcher
._module
_configurations
['other'] = MODULE_CONFIGURATIONS
[0]
604 self
.assertEqual(self
.dispatcher
._get
_module
('other', 'version'),
606 self
.assertRaises(request_info
.VersionDoesNotExistError
,
607 self
.dispatcher
._get
_module
,
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
,
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),
626 self
.dispatcher
._module
_name
_to
_module
['other'] = self
.module2
627 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
(None, None),
630 # Test soft-routing. Querying for a non-existing module should return
632 self
.dispatcher
._module
_name
_to
_module
= {'default': self
.module1
}
633 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
637 # Test version handling.
638 self
.dispatcher
._module
_configurations
['default'] = MODULE_CONFIGURATIONS
[0]
639 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
642 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('default',
645 self
.assertRaises(request_info
.VersionDoesNotExistError
,
646 self
.dispatcher
._get
_module
_with
_soft
_routing
,
649 self
.assertRaises(request_info
.VersionDoesNotExistError
,
650 self
.dispatcher
._get
_module
_with
_soft
_routing
,
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',
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',
667 self
.assertRaises(request_info
.VersionDoesNotExistError
,
668 self
.dispatcher
._get
_module
_with
_soft
_routing
,
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',
678 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
681 # Test version handling.
682 self
.dispatcher
._module
_configurations
['other'] = MODULE_CONFIGURATIONS
[0]
683 self
.assertEqual(self
.dispatcher
._get
_module
_with
_soft
_routing
('other',
686 self
.assertRaises(request_info
.VersionDoesNotExistError
,
687 self
.dispatcher
._get
_module
_with
_soft
_routing
,
691 if __name__
== '__main__':