diff --git a/swiftclient/service.py b/swiftclient/service.py index 281947ea..1b591d31 100644 --- a/swiftclient/service.py +++ b/swiftclient/service.py @@ -594,44 +594,31 @@ class SwiftService(object): 'error': err, 'response_dict': response_dict }) - return res - else: - if not objects: - res["action"] = "post_container" - response_dict = {} - headers = split_headers( - options['meta'], 'X-Container-Meta-') - headers.update( - split_headers(options['header'], '')) - if options['read_acl'] is not None: - headers['X-Container-Read'] = options['read_acl'] - if options['write_acl'] is not None: - headers['X-Container-Write'] = options['write_acl'] - if options['sync_to'] is not None: - headers['X-Container-Sync-To'] = options['sync_to'] - if options['sync_key'] is not None: - headers['X-Container-Sync-Key'] = options['sync_key'] - res['headers'] = headers - try: - post = self.thread_manager.container_pool.submit( - self._post_container_job, container, - headers, response_dict - ) - get_future_result(post) - except ClientException as err: - if err.http_status != 404: - res.update({ - 'action': 'post_container', - 'success': False, - 'error': err, - 'response_dict': response_dict - }) - return res - raise SwiftError( - "Container '%s' not found" % container, - container=container - ) - except Exception as err: + return res + if not objects: + res["action"] = "post_container" + response_dict = {} + headers = split_headers( + options['meta'], 'X-Container-Meta-') + headers.update( + split_headers(options['header'], '')) + if options['read_acl'] is not None: + headers['X-Container-Read'] = options['read_acl'] + if options['write_acl'] is not None: + headers['X-Container-Write'] = options['write_acl'] + if options['sync_to'] is not None: + headers['X-Container-Sync-To'] = options['sync_to'] + if options['sync_key'] is not None: + headers['X-Container-Sync-Key'] = options['sync_key'] + res['headers'] = headers + try: + post = self.thread_manager.container_pool.submit( + self._post_container_job, container, + headers, response_dict + ) + get_future_result(post) + except ClientException as err: + if err.http_status != 404: res.update({ 'action': 'post_container', 'success': False, @@ -639,37 +626,49 @@ class SwiftService(object): 'response_dict': response_dict }) return res - else: - post_futures = [] - post_objects = self._make_post_objects(objects) - for post_object in post_objects: - obj = post_object.object_name - obj_options = post_object.options - response_dict = {} - headers = split_headers( - options['meta'], 'X-Object-Meta-') - # add header options to the headers object for the request. - headers.update( - split_headers(options['header'], '')) - if obj_options is not None: - if 'meta' in obj_options: - headers.update( - split_headers( - obj_options['meta'], 'X-Object-Meta' - ) - ) - if 'headers' in obj_options: - headers.update( - split_headers(obj_options['header'], '') + raise SwiftError( + "Container '%s' not found" % container, + container=container + ) + except Exception as err: + res.update({ + 'action': 'post_container', + 'success': False, + 'error': err, + 'response_dict': response_dict + }) + return res + else: + post_futures = [] + post_objects = self._make_post_objects(objects) + for post_object in post_objects: + obj = post_object.object_name + obj_options = post_object.options + response_dict = {} + headers = split_headers( + options['meta'], 'X-Object-Meta-') + # add header options to the headers object for the request. + headers.update( + split_headers(options['header'], '')) + if obj_options is not None: + if 'meta' in obj_options: + headers.update( + split_headers( + obj_options['meta'], 'X-Object-Meta' ) + ) + if 'headers' in obj_options: + headers.update( + split_headers(obj_options['header'], '') + ) - post = self.thread_manager.object_uu_pool.submit( - self._post_object_job, container, obj, - headers, response_dict - ) - post_futures.append(post) + post = self.thread_manager.object_uu_pool.submit( + self._post_object_job, container, obj, + headers, response_dict + ) + post_futures.append(post) - return ResultsIterator(post_futures) + return ResultsIterator(post_futures) @staticmethod def _make_post_objects(objects): diff --git a/swiftclient/shell.py b/swiftclient/shell.py index 015c9d9f..2c627ad9 100755 --- a/swiftclient/shell.py +++ b/swiftclient/shell.py @@ -547,8 +547,7 @@ If the container is not found, it will be created automatically. Positional arguments: [container] Name of container to post to. - [object] Name of object to post. Specify multiple times - for multiple objects. + [object] Name of object to post. Optional arguments: --read-acl <acl> Read ACL for containers. Quick summary of ACL syntax: @@ -600,7 +599,7 @@ def st_post(parser, args, output_manager): with SwiftService(options=_opts) as swift: try: if not args: - swift.post() + result = swift.post() else: container = args[0] if '/' in container: @@ -616,15 +615,16 @@ def st_post(parser, args, output_manager): results_iterator = swift.post( container=container, objects=objects ) - for result in results_iterator: # only 1 result - if not result["success"]: - raise(result["error"]) + result = next(results_iterator) else: output_manager.error( 'Usage: %s post %s\n%s', BASENAME, st_post_options, st_post_help) + return else: - swift.post(container=container) + result = swift.post(container=container) + if not result["success"]: + raise(result["error"]) except SwiftError as e: output_manager.error(e.value) diff --git a/tests/unit/test_shell.py b/tests/unit/test_shell.py index 29d74729..bdba1939 100644 --- a/tests/unit/test_shell.py +++ b/tests/unit/test_shell.py @@ -390,26 +390,68 @@ class TestShell(unittest.TestCase): @mock.patch('swiftclient.service.Connection') def test_post_account(self, connection): argv = ["", "post"] - connection.return_value.head_object.return_value = {} swiftclient.shell.main(argv) connection.return_value.post_account.assert_called_with( headers={}, response_dict={}) + @mock.patch('swiftclient.shell.OutputManager.error') + @mock.patch('swiftclient.service.Connection') + def test_post_account_bad_auth(self, connection, error): + argv = ["", "post"] + connection.return_value.post_account.side_effect = \ + swiftclient.ClientException('bad auth') + swiftclient.shell.main(argv) + error.assert_called_with('bad auth') + + @mock.patch('swiftclient.shell.OutputManager.error') + @mock.patch('swiftclient.service.Connection') + def test_post_account_not_found(self, connection, error): + argv = ["", "post"] + connection.return_value.post_account.side_effect = \ + swiftclient.ClientException('test', http_status=404) + swiftclient.shell.main(argv) + error.assert_called_with('Account not found') + + @mock.patch('swiftclient.service.Connection') + def test_post_container(self, connection): argv = ["", "post", "container"] - connection.return_value.head_object.return_value = {} swiftclient.shell.main(argv) connection.return_value.post_container.assert_called_with( 'container', headers={}, response_dict={}) + @mock.patch('swiftclient.shell.OutputManager.error') @mock.patch('swiftclient.service.Connection') - def test_post_container(self, connection): + def test_post_container_bad_auth(self, connection, error): + argv = ["", "post", "container"] + connection.return_value.post_container.side_effect = \ + swiftclient.ClientException('bad auth') + swiftclient.shell.main(argv) + error.assert_called_with('bad auth') + + @mock.patch('swiftclient.service.Connection') + def test_post_container_not_found_causes_put(self, connection): + argv = ["", "post", "container"] + connection.return_value.post_container.side_effect = \ + swiftclient.ClientException('test', http_status=404) + swiftclient.shell.main(argv) + self.assertEqual('container', + connection.return_value.put_container.call_args[0][0]) + + @mock.patch('swiftclient.shell.OutputManager.error') + def test_post_container_with_bad_name(self, error): + argv = ["", "post", "conta/iner"] + swiftclient.shell.main(argv) + self.assertTrue(error.called) + self.assertTrue(error.call_args[0][0].startswith('WARNING: / in')) + + @mock.patch('swiftclient.service.Connection') + def test_post_container_with_options(self, connection): argv = ["", "post", "container", "--read-acl", "test2:tester2", "--write-acl", "test3:tester3 test4", "--sync-to", "othersite", "--sync-key", "secret", ] - connection.return_value.head_object.return_value = {} swiftclient.shell.main(argv) connection.return_value.post_container.assert_called_with( 'container', headers={ @@ -424,13 +466,28 @@ class TestShell(unittest.TestCase): "--meta", "Color:Blue", "--header", "content-type:text/plain" ] - connection.return_value.head_object.return_value = {} swiftclient.shell.main(argv) connection.return_value.post_object.assert_called_with( 'container', 'object', headers={ 'Content-Type': 'text/plain', 'X-Object-Meta-Color': 'Blue'}, response_dict={}) + @mock.patch('swiftclient.shell.OutputManager.error') + @mock.patch('swiftclient.service.Connection') + def test_post_object_bad_auth(self, connection, error): + argv = ["", "post", "container", "object"] + connection.return_value.post_object.side_effect = \ + swiftclient.ClientException("bad auth") + swiftclient.shell.main(argv) + error.assert_called_with('bad auth') + + @mock.patch('swiftclient.shell.OutputManager.error') + def test_post_object_too_many_args(self, error): + argv = ["", "post", "container", "object", "bad_arg"] + swiftclient.shell.main(argv) + self.assertTrue(error.called) + self.assertTrue(error.call_args[0][0].startswith('Usage')) + @mock.patch('swiftclient.shell.generate_temp_url') def test_temp_url(self, temp_url): argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/o",