From c761a572ae14368ad002a911d07d14c5c5c1b703 Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Wed, 14 Mar 2018 16:17:34 +0800 Subject: bugfix: TestAPI Cookie cannot be found Change-Id: Ibab60aba26e30669dddab74ce61ed00197dc86a8 Signed-off-by: SerenaFeng --- testapi/testapi-client/testapiclient/cli/auth.py | 14 -- testapi/testapi-client/testapiclient/cli/pods.py | 21 ++- .../testapi-client/testapiclient/cli/projects.py | 24 ++-- testapi/testapi-client/testapiclient/main.py | 25 +++- .../testapiclient/tests/unit/fakes.py | 72 ++++++++++ .../testapiclient/tests/unit/test_pods.py | 111 ++++----------- .../testapiclient/tests/unit/test_projects.py | 156 +++++---------------- .../testapiclient/tests/unit/utils.py | 20 ++- .../testapiclient/utils/clientmanager.py | 63 +++++++++ .../testapiclient/utils/http_client.py | 80 ----------- .../testapi-client/testapiclient/utils/identity.py | 38 ----- .../testapiclient/utils/url_parse.py | 40 ------ .../testapi-client/testapiclient/utils/urlparse.py | 40 ++++++ testapi/testapi-client/testapiclient/utils/user.py | 2 - 14 files changed, 292 insertions(+), 414 deletions(-) delete mode 100644 testapi/testapi-client/testapiclient/cli/auth.py create mode 100644 testapi/testapi-client/testapiclient/tests/unit/fakes.py create mode 100644 testapi/testapi-client/testapiclient/utils/clientmanager.py delete mode 100644 testapi/testapi-client/testapiclient/utils/http_client.py delete mode 100644 testapi/testapi-client/testapiclient/utils/identity.py delete mode 100644 testapi/testapi-client/testapiclient/utils/url_parse.py create mode 100644 testapi/testapi-client/testapiclient/utils/urlparse.py delete mode 100644 testapi/testapi-client/testapiclient/utils/user.py (limited to 'testapi/testapi-client/testapiclient') diff --git a/testapi/testapi-client/testapiclient/cli/auth.py b/testapi/testapi-client/testapiclient/cli/auth.py deleted file mode 100644 index 434c55a..0000000 --- a/testapi/testapi-client/testapiclient/cli/auth.py +++ /dev/null @@ -1,14 +0,0 @@ -from testapiclient.utils import command -from testapiclient.utils import identity - - -class Auth(command.Command): - "Handle Authentication for users" - - def get_parser(self, prog_name): - parser = super(Auth, self).get_parser(prog_name) - return parser - - @identity.authenticate - def take_action(self, parsed_args): - print "Authentication has been successful!" diff --git a/testapi/testapi-client/testapiclient/cli/pods.py b/testapi/testapi-client/testapiclient/cli/pods.py index 9cadee7..8d0970b 100644 --- a/testapi/testapi-client/testapiclient/cli/pods.py +++ b/testapi/testapi-client/testapiclient/cli/pods.py @@ -1,17 +1,15 @@ import json from testapiclient.utils import command -from testapiclient.utils import http_client as client -from testapiclient.utils import identity -from testapiclient.utils import url_parse as up +from testapiclient.utils import urlparse def pods_url(): - return up.resource_join('pods') + return urlparse.resource_join('pods') def pod_url(parsed_args): - return up.path_join(pods_url(), parsed_args.name) + return urlparse.path_join(pods_url(), parsed_args.name) class PodGet(command.Lister): @@ -34,7 +32,8 @@ class PodGet(command.Lister): "creation_date", ) - data = client.get(up.query_by(pods_url(), 'name', parsed_args)) + data = self.app.client_manager.get( + urlparse.query_by(pods_url(), 'name', parsed_args)) return self.format_output(columns, data.get('pods', [])) @@ -49,7 +48,8 @@ class PodGetOne(command.ShowOne): return parser def take_action(self, parsed_args): - return self.format_output(client.get(pod_url(parsed_args))) + return self.format_output( + self.app.client_manager.get(pod_url(parsed_args))) class PodCreate(command.ShowOne): @@ -66,9 +66,9 @@ class PodCreate(command.ShowOne): 'mode should be either "metal" or "virtual.') return parser - @identity.authenticate def take_action(self, parsed_args): - return self.format_output(client.post(pods_url(), parsed_args.pod)) + return self.format_output( + self.app.client_manager.post(pods_url(), parsed_args.pod)) class PodDelete(command.Command): @@ -81,6 +81,5 @@ class PodDelete(command.Command): help='Delete pods using name') return parser - @identity.authenticate def take_action(self, parsed_args): - return client.delete(pod_url(parsed_args)) + return self.app.client_manager.delete(pod_url(parsed_args)) diff --git a/testapi/testapi-client/testapiclient/cli/projects.py b/testapi/testapi-client/testapiclient/cli/projects.py index 718623a..510acc8 100644 --- a/testapi/testapi-client/testapiclient/cli/projects.py +++ b/testapi/testapi-client/testapiclient/cli/projects.py @@ -1,17 +1,15 @@ import json from testapiclient.utils import command -from testapiclient.utils import http_client as client -from testapiclient.utils import identity -from testapiclient.utils import url_parse as up +from testapiclient.utils import urlparse def projects_url(): - return up.resource_join('projects') + return urlparse.resource_join('projects') def project_url(parsed_args): - return up.path_join(projects_url(), parsed_args.name) + return urlparse.path_join(projects_url(), parsed_args.name) class ProjectGet(command.Lister): @@ -29,7 +27,8 @@ class ProjectGet(command.Lister): 'creator', 'creation_date' ) - data = client.get(up.query_by(projects_url(), 'name', parsed_args)) + data = self.app.client_manager.get( + urlparse.query_by(projects_url(), 'name', parsed_args)) return self.format_output(columns, data.get('projects', [])) @@ -42,7 +41,8 @@ class ProjectGetOne(command.ShowOne): return parser def take_action(self, parsed_args): - return self.format_output(client.get(project_url(parsed_args))) + return self.format_output( + self.app.client_manager.get(project_url(parsed_args))) class ProjectCreate(command.ShowOne): @@ -56,10 +56,9 @@ class ProjectCreate(command.ShowOne): '"description": (optional)""}') return parser - @identity.authenticate def take_action(self, parsed_args): return self.format_output( - client.post(projects_url(), parsed_args.project)) + self.app.client_manager.post(projects_url(), parsed_args.project)) class ProjectDelete(command.Command): @@ -71,9 +70,8 @@ class ProjectDelete(command.Command): help='Delete project by name') return parser - @identity.authenticate def take_action(self, parsed_args): - return client.delete(project_url(parsed_args)) + return self.app.client_manager.delete(project_url(parsed_args)) class ProjectPut(command.ShowOne): @@ -90,7 +88,7 @@ class ProjectPut(command.ShowOne): '"description": (optional)""}') return parser - @identity.authenticate def take_action(self, parsed_args): return self.format_output( - client.put(project_url(parsed_args), parsed_args.project)) + self.app.client_manager.put( + project_url(parsed_args), parsed_args.project)) diff --git a/testapi/testapi-client/testapiclient/main.py b/testapi/testapi-client/testapiclient/main.py index dfa6284..22a8fbd 100644 --- a/testapi/testapi-client/testapiclient/main.py +++ b/testapi/testapi-client/testapiclient/main.py @@ -2,9 +2,8 @@ import sys from cliff import app from cliff import commandmanager -import requests -from testapiclient.utils import user +from testapiclient.utils import clientmanager class TestAPIClient(app.App): @@ -16,13 +15,29 @@ class TestAPIClient(app.App): command_manager=commandmanager.CommandManager('testapi'), deferred_help=True, ) - user.User.session = requests.Session() + + def build_option_parser(self, description, version, argparse_kwargs=None): + self.LOG.debug('build_option_parser') + parser = super(TestAPIClient, self).build_option_parser( + description, + version, + argparse_kwargs) + parser.add_argument('-u', + type=str, + help='Username for authentication') + parser.add_argument('-p', + type=str, + help='Password for authentication') + return parser def initialize_app(self, argv): self.LOG.debug('initialize_app') + self.client_manager = clientmanager.ClientManager(self.options) def prepare_to_run_command(self, cmd): self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__) + if self.options.u: + self.client_manager.auth() def clean_up(self, cmd, result, err): self.LOG.debug('clean_up %s', cmd.__class__.__name__) @@ -31,8 +46,8 @@ class TestAPIClient(app.App): def main(argv=sys.argv[1:]): - myapp = TestAPIClient() - return myapp.run(argv) + client = TestAPIClient() + return client.run(argv) if __name__ == '__main__': diff --git a/testapi/testapi-client/testapiclient/tests/unit/fakes.py b/testapi/testapi-client/testapiclient/tests/unit/fakes.py new file mode 100644 index 0000000..8424745 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/fakes.py @@ -0,0 +1,72 @@ +import json +import sys + +import requests +import six +import httplib + + +class FakeResponse(requests.Response): + + def __init__(self, headers=None, status_code=httplib.OK, + data=None, encoding=None): + super(FakeResponse, self).__init__() + + headers = headers or {} + + self.status_code = status_code + + self.headers.update(headers) + if status_code != httplib.OK: + self.reason = data + + self._content = json.dumps(data) + if not isinstance(self._content, six.binary_type): + self._content = self._content.encode() + + +class FakeApp(object): + + def __init__(self, _stdout, _log): + self.stdout = _stdout + self.client_manager = None + self.stdin = sys.stdin + self.stdout = _stdout or sys.stdout + self.stderr = sys.stderr + self.log = _log + + +class FakeLog(object): + + def __init__(self): + self.messages = {} + + def debug(self, msg): + self.messages['debug'] = msg + + def info(self, msg): + self.messages['info'] = msg + + def warning(self, msg): + self.messages['warning'] = msg + + def error(self, msg): + self.messages['error'] = msg + + def critical(self, msg): + self.messages['critical'] = msg + + +class FakeStdout(object): + + def __init__(self): + self.content = [] + + def write(self, text): + self.content.append(text) + + def make_string(self): + result = '' + for line in self.content: + result = result + line + return result diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_pods.py b/testapi/testapi-client/testapiclient/tests/unit/test_pods.py index f531f9f..5d44d4c 100644 --- a/testapi/testapi-client/testapiclient/tests/unit/test_pods.py +++ b/testapi/testapi-client/testapiclient/tests/unit/test_pods.py @@ -1,22 +1,18 @@ -import StringIO -import httplib import json from mock import mock -import requests from six.moves.urllib import parse import testtools from testapiclient.cli import pods +from testapiclient.tests.unit import fakes from testapiclient.tests.unit import utils -from testapiclient.utils import http_client -from testapiclient.utils import user +from testapiclient.utils import clientmanager class PodTest(utils.TestCommand): def setUp(self): super(PodTest, self).setUp() - user.User.session = requests.session() self.base_url = parse.urljoin(self.api_url, 'pods') self.pod_json = { 'role': 'community-ci', @@ -31,47 +27,53 @@ class PodGetTest(PodTest): def setUp(self): super(PodGetTest, self).setUp() - self.get_mock = mock.patch('requests.get').start() - self.get_mock.return_value.status_code = httplib.OK + self.pods_rsp = {'pods': [self.pod_json]} def test_get(self): - pod_get = pods.PodGet(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp) + pod_get = pods.PodGet(self.app, mock.Mock()) args = ['-name', 'dfs'] verifies = [('name', 'dfs')] parsed_args = self.check_parser(pod_get, args, verifies) pod_get.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url + '?name=dfs') + self.base_url + '?name=dfs', + headers=clientmanager.ClientManager.headers) def test_get_all(self): - pod_get = pods.PodGet(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp) + pod_get = pods.PodGet(self.app, mock.Mock()) args = [] verifies = [] parsed_args = self.check_parser(pod_get, args, verifies) pod_get.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url) + self.base_url, + headers=clientmanager.ClientManager.headers) def test_get_one(self): - pod_get_one = pods.PodGetOne(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.pod_json) + pod_get_one = pods.PodGetOne(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(pod_get_one, args, verifies) pod_get_one.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url + '/def') + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) class PodCreateTest(PodTest): def setUp(self): super(PodCreateTest, self).setUp() - self.post_mock = mock.patch( - 'testapiclient.utils.user.User.session.post').start() - self.post_mock.return_value.status_code = httplib.OK + self.succ_rsp = { + 'href': '{}/{}'.format(self.base_url, self.pod_json.get('name')) + } def test_create_success(self): - pod_create = pods.PodCreate(mock.Mock(), mock.Mock()) + self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp) + pod_create = pods.PodCreate(self.app, mock.Mock()) args = [self.pod_string] verifies = [('pod', self.pod_json)] parsed_args = self.check_parser(pod_create, args, verifies) @@ -80,93 +82,36 @@ class PodCreateTest(PodTest): def test_create_failure(self): with testtools.ExpectedException(Exception, 'Create failed: Error'): - pod_create = pods.PodCreate(mock.Mock(), mock.Mock()) - self.post_mock.return_value.status_code = httplib.BAD_REQUEST - self.post_mock.return_value.reason = "Error" + self.post_mock.return_value = utils.FAKE_FAILURE + pod_create = pods.PodCreate(self.app, mock.Mock()) args = [self.pod_string] verifies = [('pod', self.pod_json)] parsed_args = self.check_parser(pod_create, args, verifies) pod_create.take_action(parsed_args) - def test_create_unauthorized(self): - self.mock_unautherized() - with mock.patch('sys.stdout', new=StringIO.StringIO()) as mock_stdout: - with mock.patch('requests.Session') as mock_sessions: - mock_sessions().post.return_value.text = "login" - pod_create = pods.PodCreate(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', self.pod_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('pod', self.pod_json)] - parsed_args = self.check_parser(pod_create, args, verifies) - pod_create.take_action(parsed_args) - self.assertEqual(mock_stdout.getvalue(), - "Authentication has failed.\n") - - def test_create_authorized(self): - pod_create = pods.PodCreate(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', self.pod_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('pod', self.pod_json) - ] - parsed_args = self.check_parser(pod_create, args, verifies) - pod_create.take_action(parsed_args) - self.post_mock.assert_called_once() - class PodDeleteTest(PodTest): def setUp(self): super(PodDeleteTest, self).setUp() - self.delete_mock = mock.patch( - 'testapiclient.utils.user.User.session.delete').start() - self.delete_mock.return_value.status_code = httplib.OK def test_delete_success(self): - pod_delete = pods.PodDelete(mock.Mock(), mock.Mock()) + self.delete_mock.return_value = fakes.FakeResponse() + pod_delete = pods.PodDelete(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(pod_delete, args, verifies) pod_delete.take_action(parsed_args) self.delete_mock.assert_called_once_with( self.base_url + '/def', - data='null', - headers=http_client.HTTPClient.headers) + data=None, + headers=clientmanager.ClientManager.headers) def test_delete_failure(self): with testtools.ExpectedException(Exception, 'Delete failed: Error'): - pod_delete = pods.PodDelete(mock.Mock(), mock.Mock()) - self.delete_mock.return_value.status_code = httplib.FORBIDDEN - self.delete_mock.return_value.reason = "Error" + self.delete_mock.return_value = utils.FAKE_FAILURE + pod_delete = pods.PodDelete(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(pod_delete, args, verifies) pod_delete.take_action(parsed_args) - - def test_delete_authorized(self): - pod_delete = pods.PodDelete(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def'] - verifies = [('u', 'user'), ('p', 'password'), ('name', 'def')] - - parsed_args = self.check_parser(pod_delete, args, verifies) - pod_delete.take_action(parsed_args) - self.delete_mock.assert_called_once_with( - self.base_url + '/def', - data='null', - headers=http_client.HTTPClient.headers) - - def test_create_unauthorized(self): - self.mock_unautherized() - with mock.patch('sys.stdout', new=StringIO.StringIO()) as mock_stdout: - with mock.patch('requests.Session') as mock_sessions: - mock_sessions().post.return_value.text = "login" - pod_delete = pods.PodDelete(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def'] - verifies = [('u', 'user'), ('p', 'password'), ('name', 'def')] - parsed_args = self.check_parser(pod_delete, args, verifies) - pod_delete.take_action(parsed_args) - self.assertEqual(mock_stdout.getvalue(), - "Authentication has failed.\n") diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_projects.py b/testapi/testapi-client/testapiclient/tests/unit/test_projects.py index 6e11329..86486ce 100644 --- a/testapi/testapi-client/testapiclient/tests/unit/test_projects.py +++ b/testapi/testapi-client/testapiclient/tests/unit/test_projects.py @@ -1,22 +1,18 @@ -import StringIO -import httplib import json from mock import mock -import requests from six.moves.urllib import parse import testtools from testapiclient.cli import projects +from testapiclient.tests.unit import fakes from testapiclient.tests.unit import utils -from testapiclient.utils import http_client -from testapiclient.utils import user +from testapiclient.utils import clientmanager class ProjectTest(utils.TestCommand): def setUp(self): super(ProjectTest, self).setUp() - user.User.session = requests.session() self.base_url = parse.urljoin(self.api_url, 'projects') self.project_json = { 'name': 'test_project', @@ -29,47 +25,54 @@ class ProjectGetTest(ProjectTest): def setUp(self): super(ProjectGetTest, self).setUp() - self.get_mock = mock.patch('requests.get').start() - self.get_mock.return_value.status_code = httplib.OK + self.projects_rsp = {'projects': [self.project_json]} def test_get(self): - project_get = projects.ProjectGet(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.projects_rsp) + project_get = projects.ProjectGet(self.app, mock.Mock()) args = ['-name', 'dfs'] verifies = [('name', 'dfs')] parsed_args = self.check_parser(project_get, args, verifies) project_get.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url + '?name=dfs') + self.base_url + '?name=dfs', + headers=clientmanager.ClientManager.headers) def test_get_all(self): - project_get = projects.ProjectGet(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.projects_rsp) + project_get = projects.ProjectGet(self.app, mock.Mock()) args = [] verifies = [] parsed_args = self.check_parser(project_get, args, verifies) project_get.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url) + self.base_url, + headers=clientmanager.ClientManager.headers) def test_get_one(self): - project_get_one = projects.ProjectGetOne(mock.Mock(), mock.Mock()) + self.get_mock.return_value = fakes.FakeResponse(data=self.project_json) + project_get_one = projects.ProjectGetOne(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(project_get_one, args, verifies) project_get_one.take_action(parsed_args) self.get_mock.assert_called_once_with( - self.base_url + '/def') + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) class ProjectCreateTest(ProjectTest): def setUp(self): super(ProjectCreateTest, self).setUp() - self.post_mock = mock.patch( - 'testapiclient.utils.user.User.session.post').start() - self.post_mock.return_value.status_code = httplib.OK def test_create_success(self): - project_create = projects.ProjectCreate(mock.Mock(), mock.Mock()) + succ_rsp = { + 'href': '{}/{}'.format(self.base_url, + self.project_json.get('name')) + } + self.post_mock.return_value = fakes.FakeResponse(data=succ_rsp) + project_create = projects.ProjectCreate(self.app, mock.Mock()) args = [self.project_string] verifies = [('project', self.project_json)] parsed_args = self.check_parser(project_create, args, verifies) @@ -78,110 +81,49 @@ class ProjectCreateTest(ProjectTest): def test_create_failure(self): with testtools.ExpectedException(Exception, 'Create failed: Error'): - project_create = projects.ProjectCreate(mock.Mock(), mock.Mock()) - self.post_mock.return_value.status_code = httplib.BAD_REQUEST - self.post_mock.return_value.reason = "Error" + self.post_mock.return_value = utils.FAKE_FAILURE + project_create = projects.ProjectCreate(self.app, mock.Mock()) args = [self.project_string] verifies = [('project', self.project_json)] parsed_args = self.check_parser(project_create, args, verifies) project_create.take_action(parsed_args) - def test_create_unauthorized(self): - self.mock_unautherized() - with mock.patch('sys.stdout', new=StringIO.StringIO()) as mock_stdout: - with mock.patch('requests.Session') as mock_sessions: - mock_sessions().post.return_value.text = "login" - project_create = projects.ProjectCreate( - mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', self.project_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('project', self.project_json)] - parsed_args = self.check_parser(project_create, args, verifies) - project_create.take_action(parsed_args) - self.assertEqual(mock_stdout.getvalue(), - "Authentication has failed.\n") - - def test_create_authorized(self): - project_create = projects.ProjectCreate(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', self.project_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('project', self.project_json) - ] - parsed_args = self.check_parser(project_create, args, verifies) - project_create.take_action(parsed_args) - self.post_mock.assert_called_once() - class ProjectDeleteTest(ProjectTest): def setUp(self): super(ProjectDeleteTest, self).setUp() - self.delete_mock = mock.patch( - 'testapiclient.utils.user.User.session.delete').start() - self.delete_mock.return_value.status_code = httplib.OK def test_delete_success(self): - project_delete = projects.ProjectDelete(mock.Mock(), mock.Mock()) + self.delete_mock.return_value = fakes.FakeResponse() + project_delete = projects.ProjectDelete(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(project_delete, args, verifies) project_delete.take_action(parsed_args) self.delete_mock.assert_called_once_with( self.base_url + '/def', - data='null', - headers=http_client.HTTPClient.headers) + data=None, + headers=clientmanager.ClientManager.headers) def test_delete_failure(self): with testtools.ExpectedException(Exception, 'Delete failed: Error'): - project_delete = projects.ProjectDelete(mock.Mock(), mock.Mock()) - self.delete_mock.return_value.status_code = httplib.FORBIDDEN - self.delete_mock.return_value.reason = "Error" + self.delete_mock.return_value = utils.FAKE_FAILURE + project_delete = projects.ProjectDelete(self.app, mock.Mock()) args = ['def'] verifies = [('name', 'def')] parsed_args = self.check_parser(project_delete, args, verifies) project_delete.take_action(parsed_args) - def test_delete_authorized(self): - project_delete = projects.ProjectDelete(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def'] - verifies = [('u', 'user'), ('p', 'password'), ('name', 'def')] - - parsed_args = self.check_parser(project_delete, args, verifies) - project_delete.take_action(parsed_args) - self.delete_mock.assert_called_once_with( - self.base_url + '/def', - data='null', - headers=http_client.HTTPClient.headers) - - def test_delete_unauthorized(self): - self.mock_unautherized() - with mock.patch('sys.stdout', new=StringIO.StringIO()) as mock_stdout: - with mock.patch('requests.Session') as mock_sessions: - mock_sessions().post.return_value.text = "login" - project_delete = projects.ProjectDelete( - mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def'] - verifies = [('u', 'user'), ('p', 'password'), ('name', 'def')] - parsed_args = self.check_parser(project_delete, args, verifies) - project_delete.take_action(parsed_args) - self.assertEqual(mock_stdout.getvalue(), - "Authentication has failed.\n") - class ProjectPutTest(ProjectTest): def setUp(self): super(ProjectPutTest, self).setUp() - self.put_mock = mock.patch( - 'testapiclient.utils.user.User.session.put').start() - self.put_mock.return_value.status_code = httplib.OK def test_put_success(self): - project_put = projects.ProjectPut(mock.Mock(), mock.Mock()) + self.put_mock.return_value = fakes.FakeResponse(data=self.project_json) + project_put = projects.ProjectPut(self.app, mock.Mock()) args = ['def', self.project_string] verifies = [('name', 'def'), ('project', self.project_json)] parsed_args = self.check_parser(project_put, args, verifies) @@ -190,41 +132,9 @@ class ProjectPutTest(ProjectTest): def test_put_failure(self): with testtools.ExpectedException(Exception, 'Update failed: Error'): - project_put = projects.ProjectPut(mock.Mock(), mock.Mock()) - self.put_mock.return_value.status_code = httplib.BAD_REQUEST - self.put_mock.return_value.reason = "Error" + self.put_mock.return_value = utils.FAKE_FAILURE + project_put = projects.ProjectPut(self.app, mock.Mock()) args = ['def', self.project_string] verifies = [('name', 'def'), ('project', self.project_json)] parsed_args = self.check_parser(project_put, args, verifies) project_put.take_action(parsed_args) - - def test_put_unauthorized(self): - self.mock_unautherized() - with mock.patch('sys.stdout', new=StringIO.StringIO()) as mock_stdout: - with mock.patch('requests.Session') as mock_sessions: - mock_sessions().post.return_value.text = "login" - project_put = projects.ProjectPut(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def', - self.project_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('name', 'def'), - ('project', self.project_json)] - parsed_args = self.check_parser(project_put, args, verifies) - project_put.take_action(parsed_args) - self.assertEqual(mock_stdout.getvalue(), - "Authentication has failed.\n") - - def test_create_authorized(self): - project_put = projects.ProjectPut(mock.Mock(), mock.Mock()) - args = ['-u', 'user', '-p', 'password', 'def', self.project_string] - verifies = [ - ('u', 'user'), - ('p', 'password'), - ('name', 'def'), - ('project', self.project_json) - ] - parsed_args = self.check_parser(project_put, args, verifies) - project_put.take_action(parsed_args) - self.put_mock.assert_called_once() diff --git a/testapi/testapi-client/testapiclient/tests/unit/utils.py b/testapi/testapi-client/testapiclient/tests/unit/utils.py index 596b7e4..20f9a47 100644 --- a/testapi/testapi-client/testapiclient/tests/unit/utils.py +++ b/testapi/testapi-client/testapiclient/tests/unit/utils.py @@ -1,7 +1,12 @@ -import testtools +import httplib + from mock import mock +import testtools -from testapiclient.utils.user import User +from testapiclient.tests.unit import fakes +from testapiclient.utils import clientmanager + +FAKE_FAILURE = fakes.FakeResponse(status_code=httplib.FORBIDDEN, data='Error') class ParserException(Exception): @@ -24,6 +29,14 @@ class TestCommand(testtools.TestCase): } self.config_mock = mock.patch.dict( 'os.environ', env_variables).start() + self.fake_stdout = fakes.FakeStdout() + self.fake_log = fakes.FakeLog() + self.app = fakes.FakeApp(self.fake_stdout, self.fake_log) + self.app.client_manager = clientmanager.ClientManager() + self.get_mock = mock.patch('requests.Session.get').start() + self.post_mock = mock.patch('requests.Session.post').start() + self.delete_mock = mock.patch('requests.Session.delete').start() + self.put_mock = mock.patch('requests.Session.put').start() def check_parser(self, cmd, args, verify_args): cmd_parser = cmd.get_parser('check_parser') @@ -37,6 +50,3 @@ class TestCommand(testtools.TestCase): self.assertIn(attr, parsed_args) self.assertEqual(value, getattr(parsed_args, attr)) return parsed_args - - def mock_unautherized(self): - User.session = None diff --git a/testapi/testapi-client/testapiclient/utils/clientmanager.py b/testapi/testapi-client/testapiclient/utils/clientmanager.py new file mode 100644 index 0000000..7e4e630 --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/clientmanager.py @@ -0,0 +1,63 @@ +import httplib +import json +import os +import urllib + +import requests + + +class ClientManager(object): + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + + def __init__(self, cli_options=None): + self.cli_options = cli_options + self.session = requests.Session() + + def auth(self): + hostname = '{}{}{}'.format(os.environ.get('testapi_cas_auth_url'), + urllib.quote(os.environ.get('testapi_url')), + os.environ.get('testapi_cas_signin_return')) + data = { + 'name': self.cli_options.u, + 'pass': self.cli_options.p, + 'form_id': 'user_login' + } + response = self.session.post(hostname, data) + if "login" in response.text: + raise Exception('Authenticate failed') + + def get(self, url): + return self._parse_response('Get', + self._request('get', url, + headers=self.headers)) + + def post(self, url, data): + return self._parse_response('Create', + self._request('post', url, + data=json.dumps(data), + headers=self.headers)) + + def put(self, url, data): + return self._parse_response('Update', + self._request('put', url, + data=json.dumps(data), + headers=self.headers)) + + def delete(self, url, *args): + data = json.dumps(args[0]) if len(args) > 0 else None + return self._parse_response('Delete', + self._request('delete', url, + data=data, + headers=self.headers)) + + def _request(self, method, *args, **kwargs): + return getattr(self.session, method)(*args, **kwargs) + + def _raise_failure(self, op, response): + raise Exception('{} failed: {}'.format(op, response.reason)) + + def _parse_response(self, op, response): + if response.status_code == httplib.OK: + return response.json() if op != 'Delete' else None + else: + self._raise_failure(op, response) diff --git a/testapi/testapi-client/testapiclient/utils/http_client.py b/testapi/testapi-client/testapiclient/utils/http_client.py deleted file mode 100644 index 359dd14..0000000 --- a/testapi/testapi-client/testapiclient/utils/http_client.py +++ /dev/null @@ -1,80 +0,0 @@ -import httplib -import json - -import requests - -from testapiclient.utils import user - - -class HTTPClient(object): - - __instance = None - headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - - @staticmethod - def get_Instance(): - """ Static access method. """ - if HTTPClient.__instance is None: - HTTPClient() - return HTTPClient.__instance - - def __init__(self): - """ Virtually private constructor. """ - if HTTPClient.__instance is not None: - raise Exception("This class is a singleton!") - else: - HTTPClient.__instance = self - - def get(self, url): - return self._parse_response('Get', requests.get(url)) - - def post(self, url, data): - return self._parse_response('Create', - self._request('post', url, - data=json.dumps(data), - headers=self.headers)) - - def put(self, url, data): - return self._parse_response('Update', - self._request('put', url, - data=json.dumps(data), - headers=self.headers)) - - def delete(self, url, *args): - data = json.dumps(args[0]) if len(args) > 0 else None - return self._parse_response('Delete', - self._request('delete', url, - data=data, - headers=self.headers)) - - def _request(self, method, *args, **kwargs): - return getattr(user.User.session, method)(*args, **kwargs) - - def _raise_failure(self, op, response): - raise Exception('{} failed: {}'.format(op, response.reason)) - - def _parse_response(self, op, response): - if response.status_code == httplib.OK: - return response.json() if op != 'Delete' else None - else: - self._raise_failure(op, response) - - -def _request(method, *args, **kwargs): - return getattr(HTTPClient.get_Instance(), method)(*args, **kwargs) - - -def get(url): - return _request('get', url) - - -def post(url, data): - return _request('post', url, data) - - -def put(url, data): - return _request('put', url, data) - - -def delete(url, data=None): - return _request('delete', url, data) diff --git a/testapi/testapi-client/testapiclient/utils/identity.py b/testapi/testapi-client/testapiclient/utils/identity.py deleted file mode 100644 index a00dd87..0000000 --- a/testapi/testapi-client/testapiclient/utils/identity.py +++ /dev/null @@ -1,38 +0,0 @@ -import functools -import os -import urllib - -import requests - -from testapiclient.utils import user - - -def _authenticate(username, password): - session = requests.Session() - hostname = '{}{}{}'.format(os.environ.get('testapi_cas_auth_url'), - urllib.quote(os.environ.get('testapi_url')), - os.environ.get('testapi_cas_signin_return')) - data = { - 'name': username, - 'pass': password, - 'form_id': 'user_login' - } - response = session.post(hostname, data) - if "login" not in response.text: - user.User.session = session - return response - - -def authenticate(xstep): - @functools.wraps(xstep) - def wrapper(self, parsed_args): - if(user.User.session is None): - username = parsed_args.u - password = parsed_args.p - if(username and password): - response = _authenticate(username, password) - if "login" in response.text: - print "Authentication has failed." - return - return xstep(self, parsed_args) - return wrapper diff --git a/testapi/testapi-client/testapiclient/utils/url_parse.py b/testapi/testapi-client/testapiclient/utils/url_parse.py deleted file mode 100644 index 9f99a46..0000000 --- a/testapi/testapi-client/testapiclient/utils/url_parse.py +++ /dev/null @@ -1,40 +0,0 @@ -import os - -from six.moves.urllib import parse - - -def path_join(base, *urls): - def _path_join(base, url): - if not base.endswith('/'): - base += '/' - return parse.urljoin(base, url) - - urls = (base,) + urls - return reduce(_path_join, urls) - - -def query_join(base, **queries): - return base + '?' + parse.urlencode(queries) - - -def resource_join(url): - testapi_url = os.environ.get('testapi_url') - return path_join(testapi_url, url) - - -def get_queries(queries, parsed_args): - if not isinstance(queries, list): - queries = [queries] - - return {query: getattr(parsed_args, query) - for query in queries - if hasattr(parsed_args, query) and getattr(parsed_args, query)} - - -def query_by(base, queries, parsed_args): - qs = get_queries(queries, parsed_args) - return query_join(base, **qs) if qs else base - - -def url_format(base, parsed_args): - return base.format(**(parsed_args.__dict__)) diff --git a/testapi/testapi-client/testapiclient/utils/urlparse.py b/testapi/testapi-client/testapiclient/utils/urlparse.py new file mode 100644 index 0000000..9f99a46 --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/urlparse.py @@ -0,0 +1,40 @@ +import os + +from six.moves.urllib import parse + + +def path_join(base, *urls): + def _path_join(base, url): + if not base.endswith('/'): + base += '/' + return parse.urljoin(base, url) + + urls = (base,) + urls + return reduce(_path_join, urls) + + +def query_join(base, **queries): + return base + '?' + parse.urlencode(queries) + + +def resource_join(url): + testapi_url = os.environ.get('testapi_url') + return path_join(testapi_url, url) + + +def get_queries(queries, parsed_args): + if not isinstance(queries, list): + queries = [queries] + + return {query: getattr(parsed_args, query) + for query in queries + if hasattr(parsed_args, query) and getattr(parsed_args, query)} + + +def query_by(base, queries, parsed_args): + qs = get_queries(queries, parsed_args) + return query_join(base, **qs) if qs else base + + +def url_format(base, parsed_args): + return base.format(**(parsed_args.__dict__)) diff --git a/testapi/testapi-client/testapiclient/utils/user.py b/testapi/testapi-client/testapiclient/utils/user.py deleted file mode 100644 index 7e72163..0000000 --- a/testapi/testapi-client/testapiclient/utils/user.py +++ /dev/null @@ -1,2 +0,0 @@ -class User(): - session = None -- cgit 1.2.3-korg