18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""Tests for google3.cloud.bigscience.apitools.base.py.batch."""
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport textwrap
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport mock
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom six.moves import http_client
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom six.moves.urllib import parse
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport unittest2
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom apitools.base.py import batch
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom apitools.base.py import exceptions
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom apitools.base.py import http_wrapper
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass FakeCredentials(object):
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self):
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.num_refreshes = 0
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def refresh(self, _):
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.num_refreshes += 1
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass FakeHttp(object):
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    class FakeRequest(object):
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def __init__(self, credentials=None):
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if credentials is not None:
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.credentials = credentials
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, credentials=None):
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.request = FakeHttp.FakeRequest(credentials=credentials)
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass FakeService(object):
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """A service for testing."""
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def GetMethodConfig(self, _):
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return {}
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def GetUploadConfig(self, _):
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return {}
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # pylint: disable=unused-argument
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def PrepareHttpRequest(
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self, method_config, request, global_params, upload_config):
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return global_params['desired_request']
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # pylint: enable=unused-argument
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def ProcessHttpResponse(self, _, http_response):
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return http_response
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass BatchTest(unittest2.TestCase):
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def assertUrlEqual(self, expected_url, provided_url):
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def parse_components(url):
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            parsed = parse.urlsplit(url)
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            query = parse.parse_qs(parsed.query)
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return parsed._replace(query=''), query
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        expected_parse, expected_query = parse_components(expected_url)
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        provided_parse, provided_query = parse_components(provided_url)
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(expected_parse, provided_parse)
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(expected_query, provided_query)
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __ConfigureMock(self, mock_request, expected_request, response):
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if isinstance(response, list):
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            response = list(response)
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def CheckRequest(_, request, **unused_kwds):
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertUrlEqual(expected_request.url, request.url)
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(expected_request.http_method, request.http_method)
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if isinstance(response, list):
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                return response.pop(0)
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                return response
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mock_request.side_effect = CheckRequest
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testRequestServiceUnavailable(self):
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mock_service = FakeService()
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_url = 'https://www.example.com'
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_api_request = batch.BatchApiRequest(batch_url=desired_url,
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                  retryable_codes=[])
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The request to be added. The actual request sent will be somewhat
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # larger, as this is added to a batch.
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_request = http_wrapper.Request(desired_url, 'POST', {
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'multipart/mixed; boundary="None"',
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length': 80,
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }, 'x' * 80)
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request(desired_url, 'POST', {
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 419,
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 419),
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Response({
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'status': '200',
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="boundary"',
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, textwrap.dedent("""\
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-type: text/plain
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-id: <id+0>
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                HTTP/1.1 503 SERVICE UNAVAILABLE
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                nope
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary--"""), None))
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_api_request.Add(
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_service, 'unused', None,
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                global_params={'desired_request': desired_request})
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            api_request_responses = batch_api_request.Execute(
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                FakeHttp(), sleep_between_polls=0)
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, len(api_request_responses))
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Make sure we didn't retry non-retryable code 503.
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, mock_request.call_count)
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertTrue(api_request_responses[0].is_error)
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsNone(api_request_responses[0].response)
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsInstance(api_request_responses[0].exception,
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                  exceptions.HttpError)
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testSingleRequestInBatch(self):
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mock_service = FakeService()
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_url = 'https://www.example.com'
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_api_request = batch.BatchApiRequest(batch_url=desired_url)
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The request to be added. The actual request sent will be somewhat
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # larger, as this is added to a batch.
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_request = http_wrapper.Request(desired_url, 'POST', {
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'multipart/mixed; boundary="None"',
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length': 80,
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }, 'x' * 80)
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request(desired_url, 'POST', {
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 419,
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 419),
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Response({
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'status': '200',
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="boundary"',
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, textwrap.dedent("""\
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-type: text/plain
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-id: <id+0>
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                HTTP/1.1 200 OK
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary--"""), None))
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_api_request.Add(mock_service, 'unused', None, {
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'desired_request': desired_request,
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            })
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            api_request_responses = batch_api_request.Execute(FakeHttp())
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, len(api_request_responses))
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, mock_request.call_count)
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertFalse(api_request_responses[0].is_error)
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            response = api_request_responses[0].response
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual({'status': '200'}, response.info)
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual('content', response.content)
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(desired_url, response.request_url)
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testRefreshOnAuthFailure(self):
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mock_service = FakeService()
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_url = 'https://www.example.com'
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_api_request = batch.BatchApiRequest(batch_url=desired_url)
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The request to be added. The actual request sent will be somewhat
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # larger, as this is added to a batch.
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_request = http_wrapper.Request(desired_url, 'POST', {
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'multipart/mixed; boundary="None"',
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length': 80,
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }, 'x' * 80)
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request(desired_url, 'POST', {
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 419,
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 419), [
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Response({
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        'status': '200',
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        'content-type': 'multipart/mixed; boundary="boundary"',
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    }, textwrap.dedent("""\
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    --boundary
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    content-type: text/plain
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    content-id: <id+0>
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    HTTP/1.1 401 UNAUTHORIZED
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    Invalid grant
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    --boundary--"""), None),
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Response({
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        'status': '200',
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        'content-type': 'multipart/mixed; boundary="boundary"',
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    }, textwrap.dedent("""\
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    --boundary
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    content-type: text/plain
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    content-id: <id+0>
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    HTTP/1.1 200 OK
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    content
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    --boundary--"""), None)
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                ])
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_api_request.Add(mock_service, 'unused', None, {
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'desired_request': desired_request,
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            })
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            credentials = FakeCredentials()
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            api_request_responses = batch_api_request.Execute(
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                FakeHttp(credentials=credentials), sleep_between_polls=0)
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, len(api_request_responses))
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(2, mock_request.call_count)
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(1, credentials.num_refreshes)
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertFalse(api_request_responses[0].is_error)
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            response = api_request_responses[0].response
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual({'status': '200'}, response.info)
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual('content', response.content)
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(desired_url, response.request_url)
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testNoAttempts(self):
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        desired_url = 'https://www.example.com'
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_api_request = batch.BatchApiRequest(batch_url=desired_url)
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_api_request.Add(FakeService(), 'unused', None, {
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'desired_request': http_wrapper.Request(desired_url, 'POST', {
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'content-type': 'multipart/mixed; boundary="None"',
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'content-length': 80,
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }, 'x' * 80),
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        })
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        api_request_responses = batch_api_request.Execute(None, max_retries=0)
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(1, len(api_request_responses))
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertIsNone(api_request_responses[0].response)
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertIsNone(api_request_responses[0].exception)
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _DoTestConvertIdToHeader(self, test_id, expected_result):
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            expected_result % batch_request._BatchHttpRequest__base_id,
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request._ConvertIdToHeader(test_id))
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testConvertIdSimple(self):
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertIdToHeader('blah', '<%s+blah>')
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testConvertIdThatNeedsEscaping(self):
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertIdToHeader('~tilde1', '<%s+%%7Etilde1>')
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _DoTestConvertHeaderToId(self, header, expected_id):
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(expected_id,
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         batch_request._ConvertHeaderToId(header))
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testConvertHeaderToIdSimple(self):
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertHeaderToId('<hello+blah>', 'blah')
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testConvertHeaderToIdWithLotsOfPlus(self):
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertHeaderToId('<a+++++plus>', 'plus')
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _DoTestConvertInvalidHeaderToId(self, invalid_header):
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertRaises(exceptions.BatchError,
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                          batch_request._ConvertHeaderToId, invalid_header)
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testHeaderWithoutAngleBrackets(self):
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertInvalidHeaderToId('1+1')
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testHeaderWithoutPlus(self):
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._DoTestConvertInvalidHeaderToId('<HEADER>')
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testSerializeRequest(self):
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        request = http_wrapper.Request(body='Hello World', headers={
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'protocol/version',
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        })
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        expected_serialized_request = '\n'.join([
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'GET  HTTP/1.1',
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Content-Type: protocol/version',
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'MIME-Version: 1.0',
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length: 11',
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Host: ',
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            '',
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Hello World',
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ])
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(expected_serialized_request,
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         batch_request._SerializeRequest(request))
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testSerializeRequestPreservesHeaders(self):
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Now confirm that if an additional, arbitrary header is added
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # that it is successfully serialized to the request. Merely
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # check that it is included, because the order of the headers
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # in the request is arbitrary.
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        request = http_wrapper.Request(body='Hello World', headers={
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'protocol/version',
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'key': 'value',
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        })
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertTrue(
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'key: value\n' in batch_request._SerializeRequest(request))
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testSerializeRequestNoBody(self):
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        request = http_wrapper.Request(body=None, headers={
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-type': 'protocol/version',
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        })
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        expected_serialized_request = '\n'.join([
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'GET  HTTP/1.1',
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Content-Type: protocol/version',
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'MIME-Version: 1.0',
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Host: ',
335cef7893435aa41160dd1255c43cb8498279738ccChris Craik            '',
336cef7893435aa41160dd1255c43cb8498279738ccChris Craik            '',
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ])
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(expected_serialized_request,
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         batch_request._SerializeRequest(request))
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testDeserializeRequest(self):
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        serialized_payload = '\n'.join([
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'GET  HTTP/1.1',
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Content-Type: protocol/version',
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'MIME-Version: 1.0',
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length: 11',
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'key: value',
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Host: ',
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            '',
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Hello World',
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ])
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        example_url = 'https://www.example.com'
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        expected_response = http_wrapper.Response({
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'content-length': str(len('Hello World')),
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Content-Type': 'protocol/version',
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'key': 'value',
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'MIME-Version': '1.0',
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'status': '',
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Host': ''
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }, 'Hello World', example_url)
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest(example_url)
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            expected_response,
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request._DeserializeResponse(serialized_payload))
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testNewId(self):
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for i in range(100):
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(str(i), batch_request._NewId())
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testAdd(self):
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest('https://www.example.com')
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for x in range(100):
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request.Add(http_wrapper.Request(body=str(x)))
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for key in batch_request._BatchHttpRequest__request_response_handlers:
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            value = batch_request._BatchHttpRequest__request_response_handlers[
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                key]
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(key, value.request.body)
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertFalse(value.request.url)
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual('GET', value.request.http_method)
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsNone(value.response)
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsNone(value.handler)
3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testInternalExecuteWithFailedRequest(self):
3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request('https://www.example.com', 'POST', {
3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
3968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 80,
3978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 80),
3988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Response({'status': '300'}, None, None))
3998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request = batch.BatchHttpRequest('https://www.example.com')
4018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertRaises(
4038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                exceptions.HttpError, batch_request._Execute, None)
4048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testInternalExecuteWithNonMultipartResponse(self):
4068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
4078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
4088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
4098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
4108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request('https://www.example.com', 'POST', {
4118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
4128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 80,
4138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 80),
4148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Response({
4158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'status': '200',
4168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'blah/blah'
4178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, '', None))
4188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request = batch.BatchHttpRequest('https://www.example.com')
4208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertRaises(
4228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                exceptions.BatchError, batch_request._Execute, None)
4238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testInternalExecute(self):
4258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(http_wrapper, 'MakeRequest',
4268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_request:
4278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.__ConfigureMock(
4288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                mock_request,
4298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Request('https://www.example.com', 'POST', {
4308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="None"',
4318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-length': 583,
4328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, 'x' * 583),
4338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                http_wrapper.Response({
4348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'status': '200',
4358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    'content-type': 'multipart/mixed; boundary="boundary"',
4368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                }, textwrap.dedent("""\
4378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary
4388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-type: text/plain
4398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-id: <id+2>
4408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                HTTP/1.1 200 OK
4428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                Second response
4438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary
4458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-type: text/plain
4468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                content-id: <id+1>
4478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                HTTP/1.1 401 UNAUTHORIZED
4498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                First response
4508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                --boundary--"""), None))
4528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            test_requests = {
4548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '1': batch.RequestResponseAndHandler(
4558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Request(body='first'), None, None),
4568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '2': batch.RequestResponseAndHandler(
4578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Request(body='second'), None, None),
4588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
4598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request = batch.BatchHttpRequest('https://www.example.com')
4618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request._BatchHttpRequest__request_response_handlers = (
4628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                test_requests)
4638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request._Execute(FakeHttp())
4658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            test_responses = (
4678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                batch_request._BatchHttpRequest__request_response_handlers)
4688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(http_client.UNAUTHORIZED,
4708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                             test_responses['1'].response.status_code)
4718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(http_client.OK,
4728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                             test_responses['2'].response.status_code)
4738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIn(
4758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'First response', test_responses['1'].response.content)
4768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIn(
4778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'Second response', test_responses['2'].response.content)
4788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def testPublicExecute(self):
4808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def LocalCallback(response, exception):
4828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual({'status': '418'}, response.info)
4838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual('Teapot', response.content)
4848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsNone(response.request_url)
4858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertIsInstance(exception, exceptions.HttpError)
4868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        global_callback = mock.Mock()
4888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        batch_request = batch.BatchHttpRequest(
4898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'https://www.example.com', global_callback)
4908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mock.patch.object(batch.BatchHttpRequest, '_Execute',
4928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               autospec=True) as mock_execute:
4938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            mock_execute.return_value = None
4948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            test_requests = {
4968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '0': batch.RequestResponseAndHandler(
4978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    None,
4988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Response({'status': '200'}, 'Hello!', None),
4998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    None),
5008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '1': batch.RequestResponseAndHandler(
5018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    None,
5028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    http_wrapper.Response({'status': '418'}, 'Teapot', None),
5038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    LocalCallback),
5048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
5058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request._BatchHttpRequest__request_response_handlers = (
5078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                test_requests)
5088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            batch_request.Execute(None)
5098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Global callback was called once per handler.
5118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(len(test_requests), global_callback.call_count)
512