diff options
| author | Gauvain Pocentek <gauvain@pocentek.net> | 2017-08-04 18:45:16 +0200 |
|---|---|---|
| committer | Gauvain Pocentek <gauvain@pocentek.net> | 2017-08-04 18:45:16 +0200 |
| commit | 3ccdec04525456c906f26ee2e931607a5d0dcd20 (patch) | |
| tree | 48709c487d57c738eb881a2728a3300023c482e5 /gitlab/tests | |
| parent | e87835fe02aeb174c1b0355a1733733d89b2e404 (diff) | |
| parent | 2816c1ae51b01214012679b74aa14de1a6696eb5 (diff) | |
| download | gitlab-3ccdec04525456c906f26ee2e931607a5d0dcd20.tar.gz | |
Merge branch 'rework_api'
Diffstat (limited to 'gitlab/tests')
| -rw-r--r-- | gitlab/tests/test_base.py | 129 | ||||
| -rw-r--r-- | gitlab/tests/test_cli.py | 37 | ||||
| -rw-r--r-- | gitlab/tests/test_gitlab.py | 271 | ||||
| -rw-r--r-- | gitlab/tests/test_gitlabobject.py | 1 | ||||
| -rw-r--r-- | gitlab/tests/test_mixins.py | 411 |
5 files changed, 833 insertions, 16 deletions
diff --git a/gitlab/tests/test_base.py b/gitlab/tests/test_base.py new file mode 100644 index 0000000..c55f000 --- /dev/null +++ b/gitlab/tests/test_base.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2017 Gauvain Pocentek <gauvain@pocentek.net> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +try: + import unittest +except ImportError: + import unittest2 as unittest + +from gitlab import base + + +class FakeGitlab(object): + pass + + +class FakeObject(base.RESTObject): + pass + + +class FakeManager(base.RESTManager): + _obj_cls = FakeObject + _path = '/tests' + + +class TestRESTManager(unittest.TestCase): + def test_computed_path_simple(self): + class MGR(base.RESTManager): + _path = '/tests' + _obj_cls = object + + mgr = MGR(FakeGitlab()) + self.assertEqual(mgr._computed_path, '/tests') + + def test_computed_path_with_parent(self): + class MGR(base.RESTManager): + _path = '/tests/%(test_id)s/cases' + _obj_cls = object + _from_parent_attrs = {'test_id': 'id'} + + class Parent(object): + id = 42 + + class BrokenParent(object): + no_id = 0 + + mgr = MGR(FakeGitlab(), parent=Parent()) + self.assertEqual(mgr._computed_path, '/tests/42/cases') + + self.assertRaises(AttributeError, MGR, FakeGitlab(), + parent=BrokenParent()) + + def test_path_property(self): + class MGR(base.RESTManager): + _path = '/tests' + _obj_cls = object + + mgr = MGR(FakeGitlab()) + self.assertEqual(mgr.path, '/tests') + + +class TestRESTObject(unittest.TestCase): + def setUp(self): + self.gitlab = FakeGitlab() + self.manager = FakeManager(self.gitlab) + + def test_instanciate(self): + obj = FakeObject(self.manager, {'foo': 'bar'}) + + self.assertDictEqual({'foo': 'bar'}, obj._attrs) + self.assertDictEqual({}, obj._updated_attrs) + self.assertEqual(None, obj._create_managers()) + self.assertEqual(self.manager, obj.manager) + self.assertEqual(self.gitlab, obj.manager.gitlab) + + def test_attrs(self): + obj = FakeObject(self.manager, {'foo': 'bar'}) + + self.assertEqual('bar', obj.foo) + self.assertRaises(AttributeError, getattr, obj, 'bar') + + obj.bar = 'baz' + self.assertEqual('baz', obj.bar) + self.assertDictEqual({'foo': 'bar'}, obj._attrs) + self.assertDictEqual({'bar': 'baz'}, obj._updated_attrs) + + def test_get_id(self): + obj = FakeObject(self.manager, {'foo': 'bar'}) + obj.id = 42 + self.assertEqual(42, obj.get_id()) + + obj.id = None + self.assertEqual(None, obj.get_id()) + + def test_custom_id_attr(self): + class OtherFakeObject(FakeObject): + _id_attr = 'foo' + + obj = OtherFakeObject(self.manager, {'foo': 'bar'}) + self.assertEqual('bar', obj.get_id()) + + def test_update_attrs(self): + obj = FakeObject(self.manager, {'foo': 'bar'}) + obj.bar = 'baz' + obj._update_attrs({'foo': 'foo', 'bar': 'bar'}) + self.assertDictEqual({'foo': 'foo', 'bar': 'bar'}, obj._attrs) + self.assertDictEqual({}, obj._updated_attrs) + + def test_create_managers(self): + class ObjectWithManager(FakeObject): + _managers = (('fakes', 'FakeManager'), ) + + obj = ObjectWithManager(self.manager, {'foo': 'bar'}) + self.assertIsInstance(obj.fakes, FakeManager) + self.assertEqual(obj.fakes.gitlab, self.gitlab) + self.assertEqual(obj.fakes._parent, obj) diff --git a/gitlab/tests/test_cli.py b/gitlab/tests/test_cli.py index 701655d..e6e290a 100644 --- a/gitlab/tests/test_cli.py +++ b/gitlab/tests/test_cli.py @@ -28,12 +28,13 @@ except ImportError: import unittest2 as unittest from gitlab import cli +import gitlab.v3.cli class TestCLI(unittest.TestCase): def test_what_to_cls(self): - self.assertEqual("Foo", cli._what_to_cls("foo")) - self.assertEqual("FooBar", cli._what_to_cls("foo-bar")) + self.assertEqual("Foo", cli.what_to_cls("foo")) + self.assertEqual("FooBar", cli.what_to_cls("foo-bar")) def test_cls_to_what(self): class Class(object): @@ -42,32 +43,33 @@ class TestCLI(unittest.TestCase): class TestClass(object): pass - self.assertEqual("test-class", cli._cls_to_what(TestClass)) - self.assertEqual("class", cli._cls_to_what(Class)) + self.assertEqual("test-class", cli.cls_to_what(TestClass)) + self.assertEqual("class", cli.cls_to_what(Class)) def test_die(self): with self.assertRaises(SystemExit) as test: - cli._die("foobar") + cli.die("foobar") self.assertEqual(test.exception.code, 1) - def test_extra_actions(self): - for cls, data in six.iteritems(cli.EXTRA_ACTIONS): - for key in data: - self.assertIsInstance(data[key], dict) - - def test_parsing(self): - args = cli._parse_args(['-v', '-g', 'gl_id', - '-c', 'foo.cfg', '-c', 'bar.cfg', - 'project', 'list']) + def test_base_parser(self): + parser = cli._get_base_parser() + args = parser.parse_args(['-v', '-g', 'gl_id', + '-c', 'foo.cfg', '-c', 'bar.cfg']) self.assertTrue(args.verbose) self.assertEqual(args.gitlab, 'gl_id') self.assertEqual(args.config_file, ['foo.cfg', 'bar.cfg']) + + +class TestV3CLI(unittest.TestCase): + def test_parse_args(self): + parser = cli._get_parser(gitlab.v3.cli) + args = parser.parse_args(['project', 'list']) self.assertEqual(args.what, 'project') self.assertEqual(args.action, 'list') def test_parser(self): - parser = cli._build_parser() + parser = cli._get_parser(gitlab.v3.cli) subparsers = None for action in parser._actions: if type(action) == argparse._SubParsersAction: @@ -93,3 +95,8 @@ class TestCLI(unittest.TestCase): actions = user_subparsers.choices['create']._option_string_actions self.assertFalse(actions['--twitter'].required) self.assertTrue(actions['--username'].required) + + def test_extra_actions(self): + for cls, data in six.iteritems(gitlab.v3.cli.EXTRA_ACTIONS): + for key in data: + self.assertIsInstance(data[key], dict) diff --git a/gitlab/tests/test_gitlab.py b/gitlab/tests/test_gitlab.py index c2cd19b..6bc427d 100644 --- a/gitlab/tests/test_gitlab.py +++ b/gitlab/tests/test_gitlab.py @@ -171,6 +171,277 @@ class TestGitlabRawMethods(unittest.TestCase): self.assertEqual(resp.status_code, 404) +class TestGitlabList(unittest.TestCase): + def setUp(self): + self.gl = Gitlab("http://localhost", private_token="private_token", + api_version=4) + + def test_build_list(self): + @urlmatch(scheme='http', netloc="localhost", path="/api/v4/tests", + method="get") + def resp_1(url, request): + headers = {'content-type': 'application/json', + 'X-Page': 1, + 'X-Next-Page': 2, + 'X-Per-Page': 1, + 'X-Total-Pages': 2, + 'X-Total': 2, + 'Link': ( + '<http://localhost/api/v4/tests?per_page=1&page=2>;' + ' rel="next"')} + content = '[{"a": "b"}]' + return response(200, content, headers, None, 5, request) + + @urlmatch(scheme='http', netloc="localhost", path="/api/v4/tests", + method='get', query=r'.*page=2') + def resp_2(url, request): + headers = {'content-type': 'application/json', + 'X-Page': 2, + 'X-Next-Page': 2, + 'X-Per-Page': 1, + 'X-Total-Pages': 2, + 'X-Total': 2} + content = '[{"c": "d"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_1): + obj = self.gl.http_list('/tests', as_list=False) + self.assertEqual(len(obj), 2) + self.assertEqual(obj._next_url, + 'http://localhost/api/v4/tests?per_page=1&page=2') + + with HTTMock(resp_2): + l = list(obj) + self.assertEqual(len(l), 2) + self.assertEqual(l[0]['a'], 'b') + self.assertEqual(l[1]['c'], 'd') + + +class TestGitlabHttpMethods(unittest.TestCase): + def setUp(self): + self.gl = Gitlab("http://localhost", private_token="private_token", + api_version=4) + + def test_build_url(self): + r = self.gl._build_url('http://localhost/api/v4') + self.assertEqual(r, 'http://localhost/api/v4') + r = self.gl._build_url('https://localhost/api/v4') + self.assertEqual(r, 'https://localhost/api/v4') + r = self.gl._build_url('/projects') + self.assertEqual(r, 'http://localhost/api/v4/projects') + + def test_http_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '[{"name": "project1"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + http_r = self.gl.http_request('get', '/projects') + http_r.json() + self.assertEqual(http_r.status_code, 200) + + def test_http_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="get") + def resp_cont(url, request): + content = {'Here is wh it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, + self.gl.http_request, + 'get', '/not_there') + + def test_get_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '{"name": "project1"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_get('/projects') + self.assertIsInstance(result, dict) + self.assertEqual(result['name'], 'project1') + + def test_get_request_raw(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/octet-stream'} + content = 'content' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_get('/projects') + self.assertEqual(result.content.decode('utf-8'), 'content') + + def test_get_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="get") + def resp_cont(url, request): + content = {'Here is wh it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, self.gl.http_get, '/not_there') + + def test_get_request_invalid_data(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '["name": "project1"]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabParsingError, self.gl.http_get, + '/projects') + + def test_list_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/json', 'X-Total': 1} + content = '[{"name": "project1"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_list('/projects', as_list=True) + self.assertIsInstance(result, list) + self.assertEqual(len(result), 1) + + with HTTMock(resp_cont): + result = self.gl.http_list('/projects', as_list=False) + self.assertIsInstance(result, GitlabList) + self.assertEqual(len(result), 1) + + with HTTMock(resp_cont): + result = self.gl.http_list('/projects', all=True) + self.assertIsInstance(result, list) + self.assertEqual(len(result), 1) + + def test_list_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="get") + def resp_cont(url, request): + content = {'Here is why it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, self.gl.http_list, '/not_there') + + def test_list_request_invalid_data(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="get") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '["name": "project1"]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabParsingError, self.gl.http_list, + '/projects') + + def test_post_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="post") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '{"name": "project1"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_post('/projects') + self.assertIsInstance(result, dict) + self.assertEqual(result['name'], 'project1') + + def test_post_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="post") + def resp_cont(url, request): + content = {'Here is wh it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, self.gl.http_post, '/not_there') + + def test_post_request_invalid_data(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="post") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '["name": "project1"]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabParsingError, self.gl.http_post, + '/projects') + + def test_put_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="put") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '{"name": "project1"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_put('/projects') + self.assertIsInstance(result, dict) + self.assertEqual(result['name'], 'project1') + + def test_put_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="put") + def resp_cont(url, request): + content = {'Here is wh it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, self.gl.http_put, '/not_there') + + def test_put_request_invalid_data(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="put") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = '["name": "project1"]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabParsingError, self.gl.http_put, + '/projects') + + def test_delete_request(self): + @urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects", + method="delete") + def resp_cont(url, request): + headers = {'content-type': 'application/json'} + content = 'true' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + result = self.gl.http_delete('/projects') + self.assertIsInstance(result, requests.Response) + self.assertEqual(result.json(), True) + + def test_delete_request_404(self): + @urlmatch(scheme="http", netloc="localhost", + path="/api/v4/not_there", method="delete") + def resp_cont(url, request): + content = {'Here is wh it failed'} + return response(404, content, {}, None, 5, request) + + with HTTMock(resp_cont): + self.assertRaises(GitlabHttpError, self.gl.http_delete, + '/not_there') + + class TestGitlabMethods(unittest.TestCase): def setUp(self): self.gl = Gitlab("http://localhost", private_token="private_token", diff --git a/gitlab/tests/test_gitlabobject.py b/gitlab/tests/test_gitlabobject.py index 3bffb82..695f900 100644 --- a/gitlab/tests/test_gitlabobject.py +++ b/gitlab/tests/test_gitlabobject.py @@ -18,7 +18,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function -from __future__ import division from __future__ import absolute_import import json diff --git a/gitlab/tests/test_mixins.py b/gitlab/tests/test_mixins.py new file mode 100644 index 0000000..812a118 --- /dev/null +++ b/gitlab/tests/test_mixins.py @@ -0,0 +1,411 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 Mika Mäenpää <mika.j.maenpaa@tut.fi>, +# Tampere University of Technology +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +try: + import unittest +except ImportError: + import unittest2 as unittest + +from httmock import HTTMock # noqa +from httmock import response # noqa +from httmock import urlmatch # noqa + +from gitlab import * # noqa +from gitlab.base import * # noqa +from gitlab.mixins import * # noqa + + +class TestObjectMixinsAttributes(unittest.TestCase): + def test_access_request_mixin(self): + class O(AccessRequestMixin): + pass + + obj = O() + self.assertTrue(hasattr(obj, 'approve')) + + def test_subscribable_mixin(self): + class O(SubscribableMixin): + pass + + obj = O() + self.assertTrue(hasattr(obj, 'subscribe')) + self.assertTrue(hasattr(obj, 'unsubscribe')) + + def test_todo_mixin(self): + class O(TodoMixin): + pass + + obj = O() + self.assertTrue(hasattr(obj, 'todo')) + + def test_time_tracking_mixin(self): + class O(TimeTrackingMixin): + pass + + obj = O() + self.assertTrue(hasattr(obj, 'time_stats')) + self.assertTrue(hasattr(obj, 'time_estimate')) + self.assertTrue(hasattr(obj, 'reset_time_estimate')) + self.assertTrue(hasattr(obj, 'add_spent_time')) + self.assertTrue(hasattr(obj, 'reset_spent_time')) + + +class TestMetaMixins(unittest.TestCase): + def test_retrieve_mixin(self): + class M(RetrieveMixin): + pass + + obj = M() + self.assertTrue(hasattr(obj, 'list')) + self.assertTrue(hasattr(obj, 'get')) + self.assertFalse(hasattr(obj, 'create')) + self.assertFalse(hasattr(obj, 'update')) + self.assertFalse(hasattr(obj, 'delete')) + self.assertIsInstance(obj, ListMixin) + self.assertIsInstance(obj, GetMixin) + + def test_crud_mixin(self): + class M(CRUDMixin): + pass + + obj = M() + self.assertTrue(hasattr(obj, 'get')) + self.assertTrue(hasattr(obj, 'list')) + self.assertTrue(hasattr(obj, 'create')) + self.assertTrue(hasattr(obj, 'update')) + self.assertTrue(hasattr(obj, 'delete')) + self.assertIsInstance(obj, ListMixin) + self.assertIsInstance(obj, GetMixin) + self.assertIsInstance(obj, CreateMixin) + self.assertIsInstance(obj, UpdateMixin) + self.assertIsInstance(obj, DeleteMixin) + + def test_no_update_mixin(self): + class M(NoUpdateMixin): + pass + + obj = M() + self.assertTrue(hasattr(obj, 'get')) + self.assertTrue(hasattr(obj, 'list')) + self.assertTrue(hasattr(obj, 'create')) + self.assertFalse(hasattr(obj, 'update')) + self.assertTrue(hasattr(obj, 'delete')) + self.assertIsInstance(obj, ListMixin) + self.assertIsInstance(obj, GetMixin) + self.assertIsInstance(obj, CreateMixin) + self.assertNotIsInstance(obj, UpdateMixin) + self.assertIsInstance(obj, DeleteMixin) + + +class FakeObject(base.RESTObject): + pass + + +class FakeManager(base.RESTManager): + _path = '/tests' + _obj_cls = FakeObject + + +class TestMixinMethods(unittest.TestCase): + def setUp(self): + self.gl = Gitlab("http://localhost", private_token="private_token", + api_version=4) + + def test_get_mixin(self): + class M(GetMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests/42', + method="get") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"id": 42, "foo": "bar"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = mgr.get(42) + self.assertIsInstance(obj, FakeObject) + self.assertEqual(obj.foo, 'bar') + self.assertEqual(obj.id, 42) + + def test_get_without_id_mixin(self): + class M(GetWithoutIdMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests', + method="get") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"foo": "bar"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = mgr.get() + self.assertIsInstance(obj, FakeObject) + self.assertEqual(obj.foo, 'bar') + self.assertFalse(hasattr(obj, 'id')) + + def test_list_mixin(self): + class M(ListMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests', + method="get") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '[{"id": 42, "foo": "bar"},{"id": 43, "foo": "baz"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + # test RESTObjectList + mgr = M(self.gl) + obj_list = mgr.list(as_list=False) + self.assertIsInstance(obj_list, base.RESTObjectList) + for obj in obj_list: + self.assertIsInstance(obj, FakeObject) + self.assertIn(obj.id, (42, 43)) + + # test list() + obj_list = mgr.list(all=True) + self.assertIsInstance(obj_list, list) + self.assertEqual(obj_list[0].id, 42) + self.assertEqual(obj_list[1].id, 43) + self.assertIsInstance(obj_list[0], FakeObject) + self.assertEqual(len(obj_list), 2) + + def test_list_other_url(self): + class M(ListMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/others', + method="get") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '[{"id": 42, "foo": "bar"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj_list = mgr.list(path='/others', as_list=False) + self.assertIsInstance(obj_list, base.RESTObjectList) + obj = obj_list.next() + self.assertEqual(obj.id, 42) + self.assertEqual(obj.foo, 'bar') + self.assertRaises(StopIteration, obj_list.next) + + def test_get_from_list_mixin(self): + class M(GetFromListMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests', + method="get") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '[{"id": 42, "foo": "bar"},{"id": 43, "foo": "baz"}]' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = mgr.get(42) + self.assertIsInstance(obj, FakeObject) + self.assertEqual(obj.foo, 'bar') + self.assertEqual(obj.id, 42) + + self.assertRaises(GitlabGetError, mgr.get, 44) + + def test_create_mixin_get_attrs(self): + class M1(CreateMixin, FakeManager): + pass + + class M2(CreateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + mgr = M1(self.gl) + required, optional = mgr.get_create_attrs() + self.assertEqual(len(required), 0) + self.assertEqual(len(optional), 0) + + mgr = M2(self.gl) + required, optional = mgr.get_create_attrs() + self.assertIn('foo', required) + self.assertIn('bar', optional) + self.assertIn('baz', optional) + self.assertNotIn('bam', optional) + + def test_create_mixin_missing_attrs(self): + class M(CreateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + + mgr = M(self.gl) + data = {'foo': 'bar', 'baz': 'blah'} + mgr._check_missing_create_attrs(data) + + data = {'baz': 'blah'} + with self.assertRaises(AttributeError) as error: + mgr._check_missing_create_attrs(data) + self.assertIn('foo', str(error.exception)) + + def test_create_mixin(self): + class M(CreateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests', + method="post") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"id": 42, "foo": "bar"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = mgr.create({'foo': 'bar'}) + self.assertIsInstance(obj, FakeObject) + self.assertEqual(obj.id, 42) + self.assertEqual(obj.foo, 'bar') + + def test_create_mixin_custom_path(self): + class M(CreateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/others', + method="post") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"id": 42, "foo": "bar"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = mgr.create({'foo': 'bar'}, path='/others') + self.assertIsInstance(obj, FakeObject) + self.assertEqual(obj.id, 42) + self.assertEqual(obj.foo, 'bar') + + def test_update_mixin_get_attrs(self): + class M1(UpdateMixin, FakeManager): + pass + + class M2(UpdateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + mgr = M1(self.gl) + required, optional = mgr.get_update_attrs() + self.assertEqual(len(required), 0) + self.assertEqual(len(optional), 0) + + mgr = M2(self.gl) + required, optional = mgr.get_update_attrs() + self.assertIn('foo', required) + self.assertIn('bam', optional) + self.assertNotIn('bar', optional) + self.assertNotIn('baz', optional) + + def test_update_mixin_missing_attrs(self): + class M(UpdateMixin, FakeManager): + _update_attrs = (('foo',), ('bar', 'baz')) + + mgr = M(self.gl) + data = {'foo': 'bar', 'baz': 'blah'} + mgr._check_missing_update_attrs(data) + + data = {'baz': 'blah'} + with self.assertRaises(AttributeError) as error: + mgr._check_missing_update_attrs(data) + self.assertIn('foo', str(error.exception)) + + def test_update_mixin(self): + class M(UpdateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests/42', + method="put") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"id": 42, "foo": "baz"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + server_data = mgr.update(42, {'foo': 'baz'}) + self.assertIsInstance(server_data, dict) + self.assertEqual(server_data['id'], 42) + self.assertEqual(server_data['foo'], 'baz') + + def test_update_mixin_no_id(self): + class M(UpdateMixin, FakeManager): + _create_attrs = (('foo',), ('bar', 'baz')) + _update_attrs = (('foo',), ('bam', )) + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests', + method="put") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"foo": "baz"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + server_data = mgr.update(new_data={'foo': 'baz'}) + self.assertIsInstance(server_data, dict) + self.assertEqual(server_data['foo'], 'baz') + + def test_delete_mixin(self): + class M(DeleteMixin, FakeManager): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests/42', + method="delete") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + mgr.delete(42) + + def test_save_mixin(self): + class M(UpdateMixin, FakeManager): + pass + + class O(SaveMixin, RESTObject): + pass + + @urlmatch(scheme="http", netloc="localhost", path='/api/v4/tests/42', + method="put") + def resp_cont(url, request): + headers = {'Content-Type': 'application/json'} + content = '{"id": 42, "foo": "baz"}' + return response(200, content, headers, None, 5, request) + + with HTTMock(resp_cont): + mgr = M(self.gl) + obj = O(mgr, {'id': 42, 'foo': 'bar'}) + obj.foo = 'baz' + obj.save() + self.assertEqual(obj._attrs['foo'], 'baz') + self.assertDictEqual(obj._updated_attrs, {}) |
