Merge "Fix object storage bulk middleware client return value"
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index e765414..7c538e8 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -58,9 +58,9 @@
         # upload an archived file
         with open(filepath) as fh:
             mydata = fh.read()
-            resp, body = self.bulk_client.upload_archive(
+            resp = self.bulk_client.upload_archive(
                 upload_path='', data=mydata, archive_file_format='tar')
-        return resp, body
+        return resp
 
     def _check_contents_deleted(self, container_name):
         param = {'format': 'txt'}
@@ -73,21 +73,20 @@
     def test_extract_archive(self):
         # Test bulk operation of file upload with an archived file
         filepath, container_name, object_name = self._create_archive()
-        resp, _ = self._upload_archive(filepath)
-
+        resp = self._upload_archive(filepath)
         self.containers.append(container_name)
 
         # When uploading an archived file with the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
         # therefore the existence of response headers is checked without
         # custom matcher.
-        self.assertIn('transfer-encoding', resp)
-        self.assertIn('content-type', resp)
-        self.assertIn('x-trans-id', resp)
-        self.assertIn('date', resp)
+        self.assertIn('transfer-encoding', resp.response)
+        self.assertIn('content-type', resp.response)
+        self.assertIn('x-trans-id', resp.response)
+        self.assertIn('date', resp.response)
 
         # Check only the format of common headers with custom matcher
-        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+        self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
 
         param = {'format': 'json'}
         resp, body = self.account_client.list_account_containers(param)
@@ -112,19 +111,19 @@
         self._upload_archive(filepath)
 
         data = '%s/%s\n%s' % (container_name, object_name, container_name)
-        resp, _ = self.bulk_client.delete_bulk_data(data=data)
+        resp = self.bulk_client.delete_bulk_data(data=data)
 
         # When deleting multiple files using the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
         # therefore the existence of response headers is checked without
         # custom matcher.
-        self.assertIn('transfer-encoding', resp)
-        self.assertIn('content-type', resp)
-        self.assertIn('x-trans-id', resp)
-        self.assertIn('date', resp)
+        self.assertIn('transfer-encoding', resp.response)
+        self.assertIn('content-type', resp.response)
+        self.assertIn('x-trans-id', resp.response)
+        self.assertIn('date', resp.response)
 
         # Check only the format of common headers with custom matcher
-        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+        self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
 
         # Check if uploaded contents are completely deleted
         self._check_contents_deleted(container_name)
@@ -138,19 +137,19 @@
 
         data = '%s/%s\n%s' % (container_name, object_name, container_name)
 
-        resp, _ = self.bulk_client.delete_bulk_data_with_post(data=data)
+        resp = self.bulk_client.delete_bulk_data_with_post(data=data)
 
         # When deleting multiple files using the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
         # therefore the existence of response headers is checked without
         # custom matcher.
-        self.assertIn('transfer-encoding', resp)
-        self.assertIn('content-type', resp)
-        self.assertIn('x-trans-id', resp)
-        self.assertIn('date', resp)
+        self.assertIn('transfer-encoding', resp.response)
+        self.assertIn('content-type', resp.response)
+        self.assertIn('x-trans-id', resp.response)
+        self.assertIn('date', resp.response)
 
         # Check only the format of common headers with custom matcher
-        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+        self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
 
         # Check if uploaded contents are completely deleted
         self._check_contents_deleted(container_name)
diff --git a/tempest/services/object_storage/bulk_middleware_client.py b/tempest/services/object_storage/bulk_middleware_client.py
index 83d2d80..c11a105 100644
--- a/tempest/services/object_storage/bulk_middleware_client.py
+++ b/tempest/services/object_storage/bulk_middleware_client.py
@@ -31,7 +31,7 @@
             headers = {}
         resp, body = self.put(url, data, headers)
         self.expected_success(200, resp.status)
-        return resp, body
+        return rest_client.ResponseBodyData(resp, body)
 
     def delete_bulk_data(self, data=None, headers=None):
         """Delete multiple objects or containers from their account.
@@ -43,9 +43,9 @@
 
         if headers is None:
             headers = {}
-        resp, body = self.delete(url, headers=headers, body=data)
+        resp, body = self.delete(url, headers, data)
         self.expected_success(200, resp.status)
-        return resp, body
+        return rest_client.ResponseBodyData(resp, body)
 
     def delete_bulk_data_with_post(self, data=None, headers=None):
         """Delete multiple objects or containers with POST request.
@@ -57,6 +57,6 @@
 
         if headers is None:
             headers = {}
-        resp, body = self.post(url, headers=headers, body=data)
+        resp, body = self.post(url, data, headers)
         self.expected_success([200, 204], resp.status)
-        return resp, body
+        return rest_client.ResponseBodyData(resp, body)
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 778c966..924f9f2 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -32,6 +32,7 @@
     def check_service_client_function(self, function, function2mock,
                                       body, to_utf=False, status=200,
                                       headers=None, mock_args=None,
+                                      resp_as_string=False,
                                       **kwargs):
         """Mock a service client function for unit testing.
 
@@ -53,6 +54,9 @@
                  ``assert_called_once_with(foo='bar')`` is called.
                * If mock_args='foo' then ``assert_called_once_with('foo')``
                  is called.
+        :param resp_as_string: Whether response body is retruned as string.
+               This is for service client methods which return ResponseBodyData
+               object.
         :param kwargs: kwargs that are passed to function.
         """
         mocked_response = self.create_response(body, to_utf, status, headers)
@@ -62,8 +66,9 @@
             resp = function(**kwargs)
         else:
             resp = function()
+        if resp_as_string:
+            resp = resp.data
         self.assertEqual(body, resp)
-
         if isinstance(mock_args, list):
             fixture.mock.assert_called_once_with(*mock_args)
         elif isinstance(mock_args, dict):
diff --git a/tempest/tests/services/object_storage/test_bulk_middleware_client.py b/tempest/tests/services/object_storage/test_bulk_middleware_client.py
new file mode 100644
index 0000000..163b48e
--- /dev/null
+++ b/tempest/tests/services/object_storage/test_bulk_middleware_client.py
@@ -0,0 +1,66 @@
+# Copyright 2017 NEC Corporation.  All rights reserved.
+#
+#    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.
+
+from tempest.services.object_storage import bulk_middleware_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestBulkMiddlewareClient(base.BaseServiceTest):
+
+    def setUp(self):
+        super(TestBulkMiddlewareClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = bulk_middleware_client.BulkMiddlewareClient(
+            fake_auth, 'object-storage', 'regionOne')
+
+    def test_upload_archive(self):
+        url = 'test_path?extract-archive=tar'
+        data = 'test_data'
+        self.check_service_client_function(
+            self.client.upload_archive,
+            'tempest.lib.common.rest_client.RestClient.put',
+            {},
+            mock_args=[url, data, {}],
+            resp_as_string=True,
+            upload_path='test_path', data=data, archive_file_format='tar')
+
+    def test_delete_bulk_data(self):
+        url = '?bulk-delete'
+        data = 'test_data'
+        self.check_service_client_function(
+            self.client.delete_bulk_data,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            mock_args=[url, {}, data],
+            resp_as_string=True,
+            data=data)
+
+    def _test_delete_bulk_data_with_post(self, status):
+        url = '?bulk-delete'
+        data = 'test_data'
+        self.check_service_client_function(
+            self.client.delete_bulk_data_with_post,
+            'tempest.lib.common.rest_client.RestClient.post',
+            {},
+            mock_args=[url, data, {}],
+            resp_as_string=True,
+            status=status,
+            data=data)
+
+    def test_delete_bulk_data_with_post_200(self):
+        self._test_delete_bulk_data_with_post(200)
+
+    def test_delete_bulk_data_with_post_204(self):
+        self._test_delete_bulk_data_with_post(204)