# -*- 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")