From b55b41bc7c67be81bbeb5b795e0a3eb683cf1e2f Mon Sep 17 00:00:00 2001 From: Nikita Konovalov Date: Tue, 20 Jan 2015 14:05:47 +0300 Subject: [PATCH] Stories and Tasks support Change-Id: I155750cfbe3711fa7e97615a62ca145bc056024a --- storyboardclient/tests/v1/test_stories.py | 75 +++++++++++++++++++++++ storyboardclient/tests/v1/test_tasks.py | 63 +++++++++++++++++++ storyboardclient/v1/client.py | 4 ++ storyboardclient/v1/stories.py | 32 ++++++++++ storyboardclient/v1/tasks.py | 42 +++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 storyboardclient/tests/v1/test_stories.py create mode 100644 storyboardclient/tests/v1/test_tasks.py create mode 100644 storyboardclient/v1/stories.py create mode 100644 storyboardclient/v1/tasks.py diff --git a/storyboardclient/tests/v1/test_stories.py b/storyboardclient/tests/v1/test_stories.py new file mode 100644 index 0000000..9edd275 --- /dev/null +++ b/storyboardclient/tests/v1/test_stories.py @@ -0,0 +1,75 @@ +# Copyright (c) 2015 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock + +from storyboardclient.tests import base as test_base +from storyboardclient.v1 import stories + + +class StoriesTestCase(test_base.TestCase): + + @mock.patch("storyboardclient.v1.stories.StoriesManager._list") + def test_stories_list(self, mock_private_list): + mock_private_list.return_value = [ + stories.Story(mock.MagicMock(), + info={"name": "test_story"}), + stories.Story(mock.MagicMock(), + info={"name": "test_story_2"})] + stories_list = stories.StoriesManager(mock.MagicMock()).list() + + self.assertEqual(2, len(stories_list)) + + @mock.patch("storyboardclient.v1.stories.StoriesManager._post") + def test_stories_create(self, mock_private_post): + stories.StoriesManager(mock.MagicMock()).create( + name="test_pg") + + mock_private_post.assert_called_once_with("/stories", + {"name": "test_pg"}) + + @mock.patch("storyboardclient.v1.stories.StoriesManager._put") + def test_stories_update(self, mock_private_put): + stories.StoriesManager(mock.MagicMock()).update( + id="story_id", + name="test_story_updated") + + mock_private_put.assert_called_once_with( + "/stories/story_id", + {"name": "test_story_updated"}) + + @mock.patch("storyboardclient.v1.tasks.TasksNestedManager._list") + def test_stories_list_tasks(self, mock_private_list): + test_story = stories.Story(mock.MagicMock(), + info={"id": "test_story_id"}) + + test_story.tasks.list() + + # A strange None here stands for the collection_key which is supposed + # to be there but is not required for StoryBoard + mock_private_list.assert_called_once_with( + "/stories/test_story_id/tasks", None) + + @mock.patch("storyboardclient.v1.tasks.TasksNestedManager._post") + def test_stories_create_task(self, mock_private_post): + test_story = stories.Story(mock.MagicMock(), + info={"id": "test_story_id"}) + + test_story.tasks.create(title="test_task") + + mock_private_post.assert_called_once_with( + "/stories/test_story_id/tasks", + {"title": "test_task", + "story_id": "test_story_id"}) diff --git a/storyboardclient/tests/v1/test_tasks.py b/storyboardclient/tests/v1/test_tasks.py new file mode 100644 index 0000000..f102f30 --- /dev/null +++ b/storyboardclient/tests/v1/test_tasks.py @@ -0,0 +1,63 @@ +# Copyright (c) 2015 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock + +from storyboardclient.tests import base as test_base +from storyboardclient.v1 import tasks + + +class TasksTestCase(test_base.TestCase): + + @mock.patch("storyboardclient.v1.tasks.TasksManager._list") + def test_tasks_list(self, mock_private_list): + mock_private_list.return_value = [ + tasks.Task(mock.MagicMock(), + info={"title": "test_task"}), + tasks.Task(mock.MagicMock(), + info={"title": "test_task_2"})] + + teams_list = tasks.TasksManager(mock.MagicMock()).list() + + self.assertEqual(2, len(teams_list)) + + @mock.patch("storyboardclient.v1.tasks.TasksManager._post") + def test_tasks_create(self, mock_private_post): + tasks.TasksManager(mock.MagicMock()).create( + title="test_task", + story_id="test_story_id", + project_id="test_project_id") + + mock_private_post.assert_called_once_with( + "/tasks", + {"title": "test_task", + "story_id": "test_story_id", + "project_id": "test_project_id"}) + + @mock.patch("storyboardclient.v1.tasks.TasksManager._put") + def test_tasks_update(self, mock_private_put): + tasks.TasksManager(mock.MagicMock()).update( + id="task_id", + title="test_task_updated") + + mock_private_put.assert_called_once_with( + "/tasks/task_id", + {"title": "test_task_updated"}) + + @mock.patch("storyboardclient.v1.tasks.TasksManager._delete") + def test_tasks_delete(self, mock_private_delete): + tasks.TasksManager(mock.MagicMock()).delete(id="task_id") + + mock_private_delete.assert_called_once_with("/tasks/task_id") diff --git a/storyboardclient/v1/client.py b/storyboardclient/v1/client.py index 1390a05..31985e4 100644 --- a/storyboardclient/v1/client.py +++ b/storyboardclient/v1/client.py @@ -16,6 +16,8 @@ from storyboardclient import base from storyboardclient.v1 import project_groups from storyboardclient.v1 import projects +from storyboardclient.v1 import stories +from storyboardclient.v1 import tasks from storyboardclient.v1 import teams from storyboardclient.v1 import users @@ -44,7 +46,9 @@ class Client(base.BaseClient): super(Client, self).__init__(api_url=api_url, access_token=access_token) + self.tasks = tasks.TasksManager(self) self.teams = teams.TeamsManager(self) self.projects = projects.ProjectsManager(self) self.project_groups = project_groups.ProjectGroupsManager(self) + self.stories = stories.StoriesManager(self) self.users = users.UsersManager(self) diff --git a/storyboardclient/v1/stories.py b/storyboardclient/v1/stories.py new file mode 100644 index 0000000..fb5ee2c --- /dev/null +++ b/storyboardclient/v1/stories.py @@ -0,0 +1,32 @@ +# Copyright (c) 2015 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from storyboardclient import base +from storyboardclient.v1 import tasks + + +class Story(base.BaseObject): + title = None + description = None + is_bug = None + creator_id = None + status = None + + tasks = tasks.TasksNestedManager + + +class StoriesManager(base.BaseManager): + url_key = "stories" + resource_class = Story \ No newline at end of file diff --git a/storyboardclient/v1/tasks.py b/storyboardclient/v1/tasks.py new file mode 100644 index 0000000..d27ea3d --- /dev/null +++ b/storyboardclient/v1/tasks.py @@ -0,0 +1,42 @@ +# Copyright (c) 2015 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from storyboardclient import base + + +class Task(base.BaseObject): + title = None + status = None + is_active = None + creator_id = None + story_id = None + project_id = None + assignee_id = None + priority = None + + +class TasksManager(base.BaseManager): + url_key = "tasks" + resource_class = Task + + +class TasksNestedManager(base.BaseNestedManager): + parent_url_key = "stories" + url_key = "tasks" + resource_class = Task + + def create(self, **kwargs): + kwargs["story_id"] = self.parent_id + return super(TasksNestedManager, self).create(**kwargs)