From d09ef0da62b64067b04a980c643f77526a9078ac Mon Sep 17 00:00:00 2001 From: Alistair Coles Date: Wed, 6 Apr 2016 15:40:42 +0100 Subject: [PATCH] Assert that ChunkWriteTimouts are not raised Follow up for change Ibbc89449e7878fc4215e47e3f7dfe4ae58a2d638 to add a test assertion that the ChunkWriteTimeout contexts are exited without raising the timeout exception in iter_bytes_from_response_part(). Change-Id: I6d323cb26779e457fb5940093a81b349b333a0af --- test/unit/proxy/test_server.py | 59 +++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 631551d337..dbbd7cbf5c 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -22,6 +22,7 @@ import math import os import pickle import sys +import traceback import unittest from contextlib import closing, contextmanager from gzip import GzipFile @@ -65,7 +66,7 @@ from swift.obj import server as object_server from swift.common.middleware import proxy_logging, versioned_writes from swift.common.middleware.acl import parse_acl, format_acl from swift.common.exceptions import ChunkReadTimeout, DiskFileNotExist, \ - APIVersionError + APIVersionError, ChunkWriteTimeout from swift.common import utils, constraints from swift.common.ring import RingData from swift.common.utils import mkdirs, normalize_timestamp, NullLogger @@ -5827,30 +5828,52 @@ class TestObjectController(unittest.TestCase): exp = 'HTTP/1.1 201' self.assertEqual(headers[:len(exp)], exp) - with mock.patch.object(_test_servers[0], 'client_timeout', new=5): - # get object - fd.write('GET /v1/a/ec-discon/test HTTP/1.1\r\n' - 'Host: localhost\r\n' - 'Connection: close\r\n' - 'X-Storage-Token: t\r\n' - '\r\n') - fd.flush() - headers = readuntil2crlfs(fd) - exp = 'HTTP/1.1 200' - self.assertEqual(headers[:len(exp)], exp) + class WrappedTimeout(ChunkWriteTimeout): + def __enter__(self): + timeouts[self] = traceback.extract_stack() + return super(WrappedTimeout, self).__enter__() - # read most of the object, and disconnect - fd.read(10) - sock.fd._sock.close() - condition = \ - lambda: _test_servers[0].logger.get_lines_for_level('warning') - self._sleep_enough(condition) + def __exit__(self, typ, value, tb): + timeouts[self] = None + return super(WrappedTimeout, self).__exit__(typ, value, tb) + + timeouts = {} + with mock.patch('swift.proxy.controllers.base.ChunkWriteTimeout', + WrappedTimeout): + with mock.patch.object(_test_servers[0], 'client_timeout', new=5): + # get object + fd.write('GET /v1/a/ec-discon/test HTTP/1.1\r\n' + 'Host: localhost\r\n' + 'Connection: close\r\n' + 'X-Storage-Token: t\r\n' + '\r\n') + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 200' + self.assertEqual(headers[:len(exp)], exp) + + # read most of the object, and disconnect + fd.read(10) + sock.fd._sock.close() + self._sleep_enough( + lambda: + _test_servers[0].logger.get_lines_for_level('warning')) # check for disconnect message! expected = ['Client disconnected on read'] * 2 self.assertEqual( _test_servers[0].logger.get_lines_for_level('warning'), expected) + # check that no coro was left waiting to write + self.assertTrue(timeouts) # sanity - WrappedTimeout did get called + missing_exits = filter(lambda tb: tb is not None, timeouts.values()) + self.assertFalse( + missing_exits, 'Failed to exit all ChunkWriteTimeouts.\n' + + ''.join(['No exit from ChunkWriteTimeout entered at:\n' + + ''.join(traceback.format_list(tb)[:-1]) + for tb in missing_exits])) + # and check that the ChunkWriteTimeouts did not raise Exceptions + self.assertFalse(_test_servers[0].logger.get_lines_for_level('error')) @unpatch_policies def test_ec_client_put_disconnect(self):