# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Mika Mäenpää ,
# 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 .
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"))
def test_set_mixin(self):
class O(SetMixin):
pass
obj = O()
self.assertTrue(hasattr(obj, "set"))
def test_user_agent_detail_mixin(self):
class O(UserAgentDetailMixin):
pass
obj = O()
self.assertTrue(hasattr(obj, "user_agent_detail"))
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_refresh_mixin(self):
class O(RefreshMixin, FakeObject):
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 = FakeManager(self.gl)
obj = O(mgr, {"id": 42})
res = obj.refresh()
self.assertIsNone(res)
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_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, {})
def test_set_mixin(self):
class M(SetMixin, FakeManager):
pass
@urlmatch(
scheme="http", netloc="localhost", path="/api/v4/tests/foo", method="put"
)
def resp_cont(url, request):
headers = {"Content-Type": "application/json"}
content = '{"key": "foo", "value": "bar"}'
return response(200, content, headers, None, 5, request)
with HTTMock(resp_cont):
mgr = M(self.gl)
obj = mgr.set("foo", "bar")
self.assertIsInstance(obj, FakeObject)
self.assertEqual(obj.key, "foo")
self.assertEqual(obj.value, "bar")