blob: 40c947b4ead0a6081196b26ec1cc35d2dbf80465 [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Tests for google.apphosting.tools.devappserver2.instance."""
import time
import unittest
import google
import mox
from google.appengine.tools.devappserver2 import instance
from google.appengine.tools.devappserver2 import wsgi_request_info
class TestInstance(unittest.TestCase):
"""Tests for instance.Instance."""
def setUp(self):
self.mox = mox.Mox()
self.proxy = self.mox.CreateMock(instance.RuntimeProxy)
self.environ = object()
self.start_response = object()
self.url_map = object()
self.match = object()
self.request_id = object()
self.response = [object()]
self.request_data = self.mox.CreateMock(wsgi_request_info.WSGIRequestInfo)
def tearDown(self):
self.mox.UnsetStubs()
def test_new_instance(self):
inst = instance.Instance(
self.request_data, 'name', self.proxy, max_concurrent_requests=5,
expect_ready_request=True)
self.assertEqual(0, inst.total_requests)
self.assertEqual(5, inst.remaining_request_capacity)
self.assertEqual(0, inst.num_outstanding_requests)
self.assertFalse(inst.can_accept_requests)
self.assertTrue(inst.handling_ready_request)
self.assertAlmostEqual(0, inst.idle_seconds, places=2)
self.assertEqual(0, inst.get_latency_60s())
self.assertEqual(0, inst.get_qps_60s())
self.assertEqual('name', inst.instance_id)
def test_handle(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify')
self.proxy.start()
self.environ = {}
self.request_data.set_request_instance(self.request_id, inst)
self.proxy.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST).AndReturn(self.response)
inst._condition.notify()
self.mox.ReplayAll()
now = time.time()
inst._request_history.append((now - 100, now - 80))
inst.start()
self.assertTrue(inst.can_accept_requests)
self.assertEqual(
self.response,
list(inst.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)))
self.mox.VerifyAll()
self.assertEqual(1, len(inst._request_history))
self.assertEqual(1, inst.total_requests)
self.assertEqual(5, inst.remaining_request_capacity)
self.assertEqual(0, inst.num_outstanding_requests)
self.assertTrue(0 < inst.get_qps_60s())
def test_handle_ready_request(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
expect_ready_request=True)
self.mox.StubOutWithMock(inst._condition, 'notify')
self.proxy.start()
self.environ = {}
self.request_data.set_request_instance(self.request_id, inst)
self.proxy.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.READY_REQUEST).AndReturn(self.response)
inst._condition.notify(5)
self.mox.ReplayAll()
inst.start()
self.assertFalse(inst.can_accept_requests)
self.assertRaises(instance.CannotAcceptRequests,
inst.handle,
self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)
self.assertEqual(
self.response,
list(inst.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.READY_REQUEST)))
self.mox.VerifyAll()
self.assertEqual(1, inst.total_requests)
self.assertEqual(5, inst.remaining_request_capacity)
self.assertEqual(0, inst.num_outstanding_requests)
self.assertTrue(0 < inst.get_qps_60s())
self.assertFalse(inst.handling_ready_request)
def test_handle_background_request(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=2)
inst._num_running_background_threads = 1
self.mox.StubOutWithMock(inst._condition, 'notify')
self.proxy.start()
self.environ = {}
self.request_data.set_request_instance(self.request_id, inst)
self.proxy.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.BACKGROUND_REQUEST).AndReturn(self.response)
self.mox.ReplayAll()
inst.start()
self.assertTrue(inst.can_accept_requests)
self.assertEqual(1, inst.remaining_background_thread_capacity)
self.assertEqual(
self.response,
list(inst.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.BACKGROUND_REQUEST)))
self.mox.VerifyAll()
self.assertEqual(1, inst.total_requests)
self.assertEqual(5, inst.remaining_request_capacity)
self.assertEqual(0, inst.num_outstanding_requests)
self.assertTrue(0 < inst.get_qps_60s())
self.assertEqual(2, inst.remaining_background_thread_capacity)
self.assertFalse(inst.handling_ready_request)
def test_handle_shutdown_request(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1)
inst._num_outstanding_requests = 0
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start()
self.environ = {}
self.request_data.set_request_instance(self.request_id, inst)
self.proxy.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.SHUTDOWN_REQUEST).AndReturn(self.response)
self.proxy.quit()
inst._condition.notify_all()
self.mox.ReplayAll()
inst.start()
self.assertTrue(inst.can_accept_requests)
self.assertFalse(inst.has_quit)
inst.quit(expect_shutdown=True)
self.assertFalse(inst.can_accept_requests)
self.assertTrue(inst.has_quit)
self.assertEqual(
self.response,
list(inst.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.SHUTDOWN_REQUEST)))
self.mox.VerifyAll()
self.assertEqual(1, inst.total_requests)
self.assertEqual(1, inst.remaining_request_capacity)
self.assertEqual(0, inst.num_outstanding_requests)
self.assertTrue(0 < inst.get_qps_60s())
self.assertFalse(inst._quitting)
self.assertTrue(inst._quit)
def test_handle_shutdown_request_running_request(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1)
inst._num_outstanding_requests = 1
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start()
self.environ = {}
self.request_data.set_request_instance(self.request_id, inst)
self.proxy.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.SHUTDOWN_REQUEST).AndReturn(self.response)
self.mox.ReplayAll()
inst.start()
self.assertTrue(inst.can_accept_requests)
self.assertFalse(inst.has_quit)
inst.quit(expect_shutdown=True)
self.assertFalse(inst.can_accept_requests)
self.assertTrue(inst.has_quit)
self.assertEqual(
self.response,
list(inst.handle(self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.SHUTDOWN_REQUEST)))
self.mox.VerifyAll()
self.assertEqual(1, inst.total_requests)
self.assertEqual(0, inst.remaining_request_capacity)
self.assertEqual(1, inst.num_outstanding_requests)
self.assertEqual(0, inst.idle_seconds)
self.assertTrue(0 < inst.get_qps_60s())
self.assertTrue(inst._quitting)
self.assertFalse(inst._quit)
def test_handle_before_start(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify')
self.assertRaises(instance.CannotAcceptRequests,
inst.handle,
self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)
def test_handle_after_quit(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify')
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start()
self.proxy.quit()
inst._condition.notify_all()
self.mox.ReplayAll()
inst.start()
inst.quit()
self.assertRaises(instance.CannotAcceptRequests,
inst.handle,
self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)
self.mox.VerifyAll()
def test_handle_while_quitting(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify')
inst._num_outstanding_requests = 1
self.proxy.start()
self.mox.ReplayAll()
inst.start()
inst.quit(allow_async=True)
self.mox.VerifyAll()
self.assertRaises(instance.CannotAcceptRequests,
inst.handle,
self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)
def test_handle_no_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1)
self.mox.StubOutWithMock(inst._condition, 'notify')
inst._num_outstanding_requests = 1
self.proxy.start()
self.assertRaises(instance.CannotAcceptRequests,
inst.handle,
self.environ,
self.start_response,
self.url_map,
self.match,
self.request_id,
instance.NORMAL_REQUEST)
def test_reserve_background_thread_success(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=2)
inst._started = True
self.mox.ReplayAll()
self.assertEqual(2, inst.remaining_background_thread_capacity)
inst.reserve_background_thread()
self.assertEqual(1, inst.remaining_background_thread_capacity)
self.mox.VerifyAll()
def test_reserve_background_thread_quitting(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=2)
inst._started = True
inst._quitting = True
self.mox.ReplayAll()
self.assertEqual(2, inst.remaining_background_thread_capacity)
inst.reserve_background_thread()
self.assertEqual(1, inst.remaining_background_thread_capacity)
self.mox.VerifyAll()
def test_reserve_background_thread_no_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=0)
inst._started = True
self.mox.ReplayAll()
self.assertEqual(0, inst.remaining_background_thread_capacity)
self.assertRaises(instance.CannotAcceptRequests,
inst.reserve_background_thread)
self.mox.VerifyAll()
self.assertEqual(0, inst.remaining_background_thread_capacity)
def test_reserve_background_thread_not_started(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=1)
self.mox.ReplayAll()
self.assertEqual(1, inst.remaining_background_thread_capacity)
self.assertRaises(instance.CannotAcceptRequests,
inst.reserve_background_thread)
self.mox.VerifyAll()
self.assertEqual(1, inst.remaining_background_thread_capacity)
def test_reserve_background_thread_quit(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=1)
inst._started = True
inst._quit = True
self.mox.ReplayAll()
self.assertEqual(1, inst.remaining_background_thread_capacity)
self.assertRaises(instance.CannotAcceptRequests,
inst.reserve_background_thread)
self.mox.VerifyAll()
self.assertEqual(1, inst.remaining_background_thread_capacity)
def test_reserve_background_thread_not_ready(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5,
max_background_threads=2,
expect_ready_request=True)
inst._started = True
self.mox.ReplayAll()
self.assertEqual(2, inst.remaining_background_thread_capacity)
inst.reserve_background_thread()
self.mox.VerifyAll()
self.assertEqual(1, inst.remaining_background_thread_capacity)
def test_wait_with_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1)
inst._started = True
self.mox.StubOutWithMock(inst._condition, 'wait')
self.mox.stubs.Set(time, 'time', lambda: 0)
self.mox.ReplayAll()
self.assertTrue(inst.wait(1))
self.mox.VerifyAll()
def test_wait_waiting_for_can_accept(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1,
expect_ready_request=True)
inst._started = True
self.mox.StubOutWithMock(inst._condition, 'wait')
self.time = 0
self.mox.stubs.Set(time, 'time', lambda: self.time)
def advance_time(*unused_args):
self.time += 10
inst._condition.wait(1).WithSideEffects(advance_time)
self.mox.ReplayAll()
self.assertFalse(inst.wait(1))
self.mox.VerifyAll()
def test_wait_timed_out_with_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=1)
inst._started = True
self.mox.StubOutWithMock(inst._condition, 'wait')
self.mox.ReplayAll()
self.assertTrue(inst.wait(0))
self.mox.VerifyAll()
def test_wait_without_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=0)
inst._started = True
self.mox.StubOutWithMock(inst._condition, 'wait')
self.time = 0
self.mox.stubs.Set(time, 'time', lambda: self.time)
def advance_time(*unused_args):
self.time += 10
inst._condition.wait(1).WithSideEffects(advance_time)
self.mox.ReplayAll()
self.assertFalse(inst.wait(1))
self.mox.VerifyAll()
def test_wait_timed_out_without_capacity(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=0)
inst._started = True
self.mox.StubOutWithMock(inst._condition, 'wait')
self.mox.ReplayAll()
self.assertFalse(inst.wait(0))
self.mox.VerifyAll()
def test_wait_quit_while_starting(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start().WithSideEffects(inst.quit)
self.proxy.quit()
self.mox.ReplayAll()
inst.start()
self.mox.VerifyAll()
self.assertFalse(inst.can_accept_requests)
def test_wait_quit_while_waiting(self):
self.mox.stubs.Set(time, 'time', lambda: 0)
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=0)
self.mox.StubOutWithMock(inst._condition, 'wait')
inst._condition.wait(1).WithSideEffects(lambda *unused_args: inst.quit())
self.mox.ReplayAll()
self.assertFalse(inst.wait(1))
self.mox.VerifyAll()
def test_quit(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start()
self.proxy.quit()
inst._condition.notify_all()
self.mox.ReplayAll()
inst.start()
self.assertTrue(inst.can_accept_requests)
inst.quit()
self.mox.VerifyAll()
self.assertFalse(inst.can_accept_requests)
def test_quit_with_request(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
self.proxy.start()
self.mox.ReplayAll()
inst.start()
self.mox.VerifyAll()
inst._num_outstanding_requests = 1
self.assertRaises(instance.CannotQuitServingInstance,
inst.quit)
def test_quit_with_request_force(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
inst._num_outstanding_requests = 1
self.proxy.start()
self.proxy.quit()
inst._condition.notify_all()
self.mox.ReplayAll()
inst.start()
inst.quit(force=True)
self.mox.VerifyAll()
def test_quit_with_request_force_and_allow_async(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
inst._num_outstanding_requests = 1
self.proxy.start()
self.proxy.quit()
inst._condition.notify_all()
self.mox.ReplayAll()
inst.start()
inst.quit(force=True, allow_async=True)
self.mox.VerifyAll()
def test_quit_with_request_allow_async(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
inst._num_outstanding_requests = 1
self.proxy.start()
self.mox.ReplayAll()
inst.start()
inst.quit(allow_async=True)
self.mox.VerifyAll()
self.assertTrue(inst._quitting)
def test_quit_shutdown(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
self.mox.StubOutWithMock(inst._condition, 'notify_all')
inst._num_outstanding_requests = 1
self.proxy.start()
self.mox.ReplayAll()
inst.start()
inst.quit(expect_shutdown=True)
self.mox.VerifyAll()
self.assertTrue(inst._expecting_shutdown_request)
self.assertFalse(inst._quitting)
def test_get_latency_60s(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
now = time.time()
inst._request_history = [(now, now+1), (now+2, now+4)]
self.assertEqual(1.5, inst.get_latency_60s())
def test_get_qps_60s(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
now = time.time()
inst._request_history = [(now, now+1)] * 120
self.assertEqual(2.0, inst.get_qps_60s())
def test__trim_request_history_to_60s(self):
inst = instance.Instance(self.request_data, 'name', self.proxy,
max_concurrent_requests=5)
inst._request_history.append((0, 100))
inst._request_history.append((1.0, 101))
inst._request_history.append((1.2, 102))
inst._request_history.append((2.5, 103))
now = time.time()
inst._request_history.append((now, 42))
inst._request_history.append((now + 1, 43))
inst._request_history.append((now + 3, 44))
inst._request_history.append((now + 4, 45))
inst._trim_request_history_to_60s()
self.assertEqual([(now, 42), (now + 1, 43), (now + 3, 44), (now + 4, 45)],
list(inst._request_history))
if __name__ == '__main__':
unittest.main()