summaryrefslogtreecommitdiff
path: root/gitlab/tests
diff options
context:
space:
mode:
authorGauvain Pocentek <gauvain@pocentek.net>2017-08-04 18:45:16 +0200
committerGauvain Pocentek <gauvain@pocentek.net>2017-08-04 18:45:16 +0200
commit3ccdec04525456c906f26ee2e931607a5d0dcd20 (patch)
tree48709c487d57c738eb881a2728a3300023c482e5 /gitlab/tests
parente87835fe02aeb174c1b0355a1733733d89b2e404 (diff)
parent2816c1ae51b01214012679b74aa14de1a6696eb5 (diff)
downloadgitlab-3ccdec04525456c906f26ee2e931607a5d0dcd20.tar.gz
Merge branch 'rework_api'
Diffstat (limited to 'gitlab/tests')
-rw-r--r--gitlab/tests/test_base.py129
-rw-r--r--gitlab/tests/test_cli.py37
-rw-r--r--gitlab/tests/test_gitlab.py271
-rw-r--r--gitlab/tests/test_gitlabobject.py1
-rw-r--r--gitlab/tests/test_mixins.py411
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, {})