From cc8f918eb44169c5ac79ddabeb52caa5baa2817f Mon Sep 17 00:00:00 2001 From: SharUpOff Date: Fri, 11 Oct 2024 13:35:00 +0400 Subject: [PATCH] feat: Add support for Team APIs (#42) --- CHANGELOG.md | 4 + README.md | 157 ++++++++++++++++++ VERSION.txt | 2 +- moira_client/models/contact.py | 1 + moira_client/models/subscription.py | 134 +++++++++------ moira_client/models/team/__init__.py | 8 + moira_client/models/team/_managers.py | 96 +++++++++++ moira_client/models/team/_models.py | 19 +++ moira_client/models/team/contact/__init__.py | 5 + moira_client/models/team/contact/_managers.py | 24 +++ moira_client/models/team/settings/__init__.py | 7 + .../models/team/settings/_managers.py | 23 +++ moira_client/models/team/settings/_models.py | 11 ++ .../models/team/subscription/__init__.py | 5 + .../models/team/subscription/_managers.py | 30 ++++ moira_client/models/team/user/__init__.py | 7 + moira_client/models/team/user/_managers.py | 43 +++++ moira_client/models/team/user/_models.py | 6 + moira_client/moira.py | 11 ++ tests/models/team/__init__.py | 0 tests/models/team/_mock.py | 11 ++ tests/models/team/contact/__init__.py | 0 tests/models/team/contact/test_managers.py | 61 +++++++ tests/models/team/settings/__init__.py | 0 tests/models/team/settings/test_managers.py | 115 +++++++++++++ tests/models/team/subscription/__init__.py | 0 .../models/team/subscription/test_managers.py | 87 ++++++++++ tests/models/team/subscription/test_models.py | 83 +++++++++ tests/models/team/test_managers.py | 121 ++++++++++++++ tests/models/team/user/__init__.py | 0 tests/models/team/user/test_managers.py | 88 ++++++++++ 31 files changed, 1106 insertions(+), 53 deletions(-) create mode 100644 moira_client/models/team/__init__.py create mode 100644 moira_client/models/team/_managers.py create mode 100644 moira_client/models/team/_models.py create mode 100644 moira_client/models/team/contact/__init__.py create mode 100644 moira_client/models/team/contact/_managers.py create mode 100644 moira_client/models/team/settings/__init__.py create mode 100644 moira_client/models/team/settings/_managers.py create mode 100644 moira_client/models/team/settings/_models.py create mode 100644 moira_client/models/team/subscription/__init__.py create mode 100644 moira_client/models/team/subscription/_managers.py create mode 100644 moira_client/models/team/user/__init__.py create mode 100644 moira_client/models/team/user/_managers.py create mode 100644 moira_client/models/team/user/_models.py create mode 100644 tests/models/team/__init__.py create mode 100644 tests/models/team/_mock.py create mode 100644 tests/models/team/contact/__init__.py create mode 100644 tests/models/team/contact/test_managers.py create mode 100644 tests/models/team/settings/__init__.py create mode 100644 tests/models/team/settings/test_managers.py create mode 100644 tests/models/team/subscription/__init__.py create mode 100644 tests/models/team/subscription/test_managers.py create mode 100644 tests/models/team/subscription/test_models.py create mode 100644 tests/models/team/test_managers.py create mode 100644 tests/models/team/user/__init__.py create mode 100644 tests/models/team/user/test_managers.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c8462..27d6ad0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 4.3.0 + +Add support for Team APIs + # 4.2.1 Add support for name field in contacts diff --git a/README.md b/README.md index 3ee5559..e3573b4 100644 --- a/README.md +++ b/README.md @@ -126,3 +126,160 @@ for contact in contacts: contact_id = moira.contact.get_id(type='slack', value='#err') print(contact_id) ``` + +## Team + +### Get all teams +```python +teams = moira.team.get_all() +``` + +### Create a new team +```python +from moira_client.models.team import TeamModel + +team = TeamModel( + description="Team that holds all members of infrastructure division", + name="Infrastructure Team", +) + +saved_team = moira.team.create(team) +``` + +### Delete a team +```python +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" + +deleted_team = moira.team.delete(team_id) +``` + +### Get a team by ID +```python +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" + +team = moira.team.get(team_id) +``` + +### Update existing team +```python +from moira_client.models.team import TeamModel + +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +team = TeamModel( + description="Team that holds all members of infrastructure division", + name="Infrastructure Team", +) + +updated_team = moira.team.update(team_id, team) +``` + +### Team Settings + +#### Get team settings +```python +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" + +settings = moira.team.settings.get(team_id) +``` + +### Team User + +#### Get users of a team + +```python +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" + +users = moira.team.user.get(team_id) +``` + +#### Add users to a team + +```python +from moira_client.models.team.user import TeamMembers + +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +users_to_add = TeamMembers(usernames=["anonymous", ]) + +users = moira.team.user.add(team_id, users_to_add) +``` + +#### Set users of a team + +```python +from moira_client.models.team.user import TeamMembers + +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +users_to_set = TeamMembers(usernames=["anonymous", ]) + +users = moira.team.user.set(team_id, users_to_set) +``` + +#### Delete a user from a team + +```python +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +team_user_id = "anonymous" + +users = moira.team.user.delete(team_id, team_user_id) +``` + +### Team Subscription + +#### Create a new team subscription + +```python +from moira_client.models.subscription import SubscriptionModel + +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +subscription_to_create = SubscriptionModel( + any_tags=False, + contacts=[ + "acd2db98-1659-4a2f-b227-52d71f6e3ba1" + ], + enabled=True, + ignore_recoverings=False, + ignore_warnings=False, + plotting={ + "enabled": True, + "theme": "dark" + }, + sched={ + "days": [ + { + "enabled": True, + "name": "Mon" + } + ], + "endOffset": 1439, + "startOffset": 0, + "tzOffset": -60 + }, + tags=[ + "server", + "cpu" + ], + throttling=False, + user="", +) + +subscription = moira.team.subscription.create(team_id, subscription_to_create) +``` + +### Team Contact + +#### Create a new team contact + +```python +from moira_client.models.contact import Contact + +team_id = "d5d98eb3-ee18-4f75-9364-244f67e23b54" +contact_to_create = Contact( + name="Mail Alerts", + team_id=team_id, + type="mail", + user="", + value="devops@example.com", +) + +contact = moira.team.contact.create(team_id, contact_to_create) +``` diff --git a/VERSION.txt b/VERSION.txt index d87edbf..8191138 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -4.2.1 \ No newline at end of file +4.3.0 \ No newline at end of file diff --git a/moira_client/models/contact.py b/moira_client/models/contact.py index a737ffc..7f6a99d 100644 --- a/moira_client/models/contact.py +++ b/moira_client/models/contact.py @@ -23,6 +23,7 @@ def __init__(self, value='', type='', **kwargs): self.user = kwargs.get('user', None) self.name = kwargs.get('name', None) self._id = kwargs.get('id', None) + self.team_id = kwargs.get('team_id', None) class ContactManager: diff --git a/moira_client/models/subscription.py b/moira_client/models/subscription.py index a26c9d8..73d121d 100644 --- a/moira_client/models/subscription.py +++ b/moira_client/models/subscription.py @@ -2,12 +2,10 @@ from ..client import ResponseStructureError from .base import Base -class Subscription(Base): - def __init__(self, client, tags, contacts=None, enabled=None, throttling=None, sched=None, +class SubscriptionModel(Base): + def __init__(self, tags, contacts=None, enabled=None, throttling=None, sched=None, ignore_warnings=False, ignore_recoverings=False, plotting=None, any_tags=False, **kwargs): """ - - :param client: api client :param tags: list of str tags :param contacts: list of contact id's :param enabled: bool is enabled @@ -19,8 +17,6 @@ def __init__(self, client, tags, contacts=None, enabled=None, throttling=None, s :param any_tags: bool any tags :param kwargs: additional parameters """ - self._client = client - self._id = kwargs.get('id', None) self.tags = tags if not any_tags else [] if not contacts: @@ -38,32 +34,7 @@ def __init__(self, client, tags, contacts=None, enabled=None, throttling=None, s if not plotting: plotting = {'enabled': False, 'theme': 'light'} self.plotting = plotting - - def _send_request(self, subscription_id=None): - data = { - 'contacts': self.contacts, - 'tags': self.tags, - 'enabled': self.enabled, - 'any_tags': self.any_tags, - 'throttling': self.throttling, - 'sched': self.sched, - 'ignore_warnings': self.ignore_warnings, - 'ignore_recoverings': self.ignore_recoverings, - 'plotting': self.plotting - } - - if subscription_id: - data['id'] = subscription_id - - if subscription_id: - result = self._client.put('subscription/{id}'.format(id=subscription_id), json=data) - else: - result = self._client.put('subscription', json=data) - if 'id' not in result: - raise ResponseStructureError("id doesn't exist in response", result) - - self._id = result['id'] - return self._id + self.team_id = kwargs.get('team_id', None) def disable_day(self, day): """ @@ -124,26 +95,6 @@ def disable_plotting(self): 'theme': 'light' } - def save(self): - """ - Save subscription - - :return: subscription id - """ - if self._id: - return self.update() - self._send_request() - - def update(self): - """ - Update subscription - - :return: subscription id - """ - if not self._id: - return self.save() - self._send_request(self._id) - def set_start_hour(self, hour): """ Set start hour @@ -185,6 +136,85 @@ def set_end_minute(self, minute): self._end_minute = minute +class Subscription(SubscriptionModel): + def __init__(self, client, tags, contacts=None, enabled=None, throttling=None, sched=None, + ignore_warnings=False, ignore_recoverings=False, plotting=None, any_tags=False, **kwargs): + """ + :param client: api client + :param tags: list of str tags + :param contacts: list of contact id's + :param enabled: bool is enabled + :param throttling: bool throttling + :param sched: dict schedule + :param ignore_warnings: bool ignore warnings + :param ignore_recoverings: bool ignore recoverings + :param plotting: dict plotting settings + :param any_tags: bool any tags + :param kwargs: additional parameters + """ + self._client = client + + super().__init__( + tags=tags, + contacts=contacts, + enabled=enabled, + throttling=throttling, + sched=sched, + ignore_warnings=ignore_warnings, + ignore_recoverings=ignore_recoverings, + plotting=plotting, + any_tags=any_tags, + **kwargs, + ) + + def _send_request(self, subscription_id=None): + data = { + 'contacts': self.contacts, + 'tags': self.tags, + 'enabled': self.enabled, + 'any_tags': self.any_tags, + 'throttling': self.throttling, + 'sched': self.sched, + 'ignore_warnings': self.ignore_warnings, + 'ignore_recoverings': self.ignore_recoverings, + 'plotting': self.plotting, + 'team_id': self.team_id, + } + + if subscription_id: + data['id'] = subscription_id + + if subscription_id: + result = self._client.put('subscription/{id}'.format(id=subscription_id), json=data) + else: + result = self._client.put('subscription', json=data) + if 'id' not in result: + raise ResponseStructureError("id doesn't exist in response", result) + + self._id = result['id'] + return self._id + + def save(self): + """ + Save subscription + + :return: subscription id + """ + if self._id: + return self.update() + self._send_request() + + def update(self): + """ + Update subscription + + :return: subscription id + """ + if not self._id: + return self.save() + self._send_request(self._id) + + class SubscriptionManager: def __init__(self, client): self._client = client diff --git a/moira_client/models/team/__init__.py b/moira_client/models/team/__init__.py new file mode 100644 index 0000000..eab2cff --- /dev/null +++ b/moira_client/models/team/__init__.py @@ -0,0 +1,8 @@ +from ._managers import TeamManager +from ._models import TeamModel + + +__all__ = [ + "TeamManager", + "TeamModel", +] diff --git a/moira_client/models/team/_managers.py b/moira_client/models/team/_managers.py new file mode 100644 index 0000000..4ac0ff3 --- /dev/null +++ b/moira_client/models/team/_managers.py @@ -0,0 +1,96 @@ +from typing import Optional + +from ._models import TeamModel, UserTeams, SaveTeamResponse +from .contact import TeamContactManager +from .settings import TeamSettingsManager +from .subscription import TeamSubscriptionManager +from .user import TeamUserManager +from ...client import Client + + +class TeamManager: + def __init__(self, client: Client) -> None: + self._client = client + self._user = None # type: Optional[TeamUserManager] + self._settings = None # type: Optional[TeamSettingsManager] + self._subscription = None # type: Optional[TeamSubscriptionManager] + self._contact = None # type: Optional[TeamContactManager] + + def get_all(self) -> UserTeams: + """Get all teams""" + response = self._client.get(self._full_path()) + + return UserTeams(teams=[TeamModel(**team) for team in response["teams"]]) + + def create(self, team: TeamModel) -> SaveTeamResponse: + """Create a new team""" + payload = { + "name": team.name, + "description": team.description, + } + + response = self._client.post(self._full_path(), json=payload) + + return SaveTeamResponse(**response) + + def delete(self, team_id: str) -> SaveTeamResponse: + """Delete a team""" + response = self._client.delete(self._full_path(team_id)) + + return SaveTeamResponse(**response) + + def get(self, team_id: str) -> TeamModel: + """Get a team by ID""" + response = self._client.get(self._full_path(team_id)) + + return TeamModel(**response) + + def update(self, team_id: str, team: TeamModel) -> SaveTeamResponse: + """Update existing team""" + payload = { + "name": team.name, + "description": team.description, + } + + response = self._client.put(self._full_path(team_id), json=payload) + + return SaveTeamResponse(**response) + + @property + def user(self) -> TeamUserManager: + """Get team user manager""" + if self._user is None: + self._user = TeamUserManager(self._client) + + return self._user + + @property + def settings(self) -> TeamSettingsManager: + """Get team settings manager""" + if self._settings is None: + self._settings = TeamSettingsManager(self._client) + + return self._settings + + @property + def subscription(self) -> TeamSubscriptionManager: + """Get team subscription manager""" + if self._subscription is None: + self._subscription = TeamSubscriptionManager(self._client) + + return self._subscription + + @property + def contact(self) -> TeamContactManager: + """Get team contact manager""" + if self._contact is None: + self._contact = TeamContactManager(self._client) + + return self._contact + + @staticmethod + def _full_path(team_id: Optional[str] = None) -> str: + if team_id is None: + return "teams" + + return "teams/{team_id}".format(team_id=team_id) diff --git a/moira_client/models/team/_models.py b/moira_client/models/team/_models.py new file mode 100644 index 0000000..ad4c82c --- /dev/null +++ b/moira_client/models/team/_models.py @@ -0,0 +1,19 @@ +from ..base import Base +from typing import List + + +class TeamModel(Base): + def __init__(self, description: str, name: str, **kwargs): + self.description = description + self.name = name + self._id = kwargs.get("id", None) + + +class UserTeams: + def __init__(self, teams: List[TeamModel]): + self.teams = teams + + +class SaveTeamResponse(Base): + def __init__(self, **kwargs): + self._id = kwargs.get("id") diff --git a/moira_client/models/team/contact/__init__.py b/moira_client/models/team/contact/__init__.py new file mode 100644 index 0000000..9f380fd --- /dev/null +++ b/moira_client/models/team/contact/__init__.py @@ -0,0 +1,5 @@ +from ._managers import TeamContactManager + +__all__ = [ + "TeamContactManager", +] diff --git a/moira_client/models/team/contact/_managers.py b/moira_client/models/team/contact/_managers.py new file mode 100644 index 0000000..ef890d8 --- /dev/null +++ b/moira_client/models/team/contact/_managers.py @@ -0,0 +1,24 @@ +from ...contact import Contact +from ....client import Client + + +class TeamContactManager: + def __init__(self, client: Client) -> None: + self._client = client + + def create(self, team_id: str, contact: Contact) -> Contact: + """Create a new team contact""" + payload = { + "team_id": team_id, + "name": contact.name, + "type": contact.type, + "value": contact.value, + } + + response = self._client.post(self._full_path(team_id), json=payload) + + return Contact(**response) + + @staticmethod + def _full_path(team_id: str) -> str: + return "teams/{team_id}/contacts".format(team_id=team_id) diff --git a/moira_client/models/team/settings/__init__.py b/moira_client/models/team/settings/__init__.py new file mode 100644 index 0000000..4488e84 --- /dev/null +++ b/moira_client/models/team/settings/__init__.py @@ -0,0 +1,7 @@ +from ._managers import TeamSettingsManager +from ._models import TeamSettings + +__all__ = [ + "TeamSettings", + "TeamSettingsManager", +] diff --git a/moira_client/models/team/settings/_managers.py b/moira_client/models/team/settings/_managers.py new file mode 100644 index 0000000..e9843aa --- /dev/null +++ b/moira_client/models/team/settings/_managers.py @@ -0,0 +1,23 @@ +from ._models import TeamSettings +from ...contact import Contact +from ...subscription import Subscription +from ....client import Client + + +class TeamSettingsManager: + def __init__(self, client: Client) -> None: + self._client = client + + def get(self, team_id: str) -> TeamSettings: + """Get team settings""" + response = self._client.get(self._full_path(team_id)) + + return TeamSettings( + contacts=[Contact(**contact) for contact in response["contacts"]], + subscriptions=[Subscription(self._client, **subscription) for subscription in response["subscriptions"]], + team_id=response["team_id"], + ) + + @staticmethod + def _full_path(team_id: str) -> str: + return "teams/{team_id}/settings".format(team_id=team_id) diff --git a/moira_client/models/team/settings/_models.py b/moira_client/models/team/settings/_models.py new file mode 100644 index 0000000..57dd898 --- /dev/null +++ b/moira_client/models/team/settings/_models.py @@ -0,0 +1,11 @@ +from typing import List + +from ...contact import Contact +from ...subscription import Subscription + + +class TeamSettings: + def __init__(self, contacts: List[Contact], subscriptions: List[Subscription], team_id: str) -> None: + self.contacts = contacts + self.subscriptions = subscriptions + self.team_id = team_id diff --git a/moira_client/models/team/subscription/__init__.py b/moira_client/models/team/subscription/__init__.py new file mode 100644 index 0000000..b398aa1 --- /dev/null +++ b/moira_client/models/team/subscription/__init__.py @@ -0,0 +1,5 @@ +from ._managers import TeamSubscriptionManager + +__all__ = [ + "TeamSubscriptionManager", +] diff --git a/moira_client/models/team/subscription/_managers.py b/moira_client/models/team/subscription/_managers.py new file mode 100644 index 0000000..a3a8eff --- /dev/null +++ b/moira_client/models/team/subscription/_managers.py @@ -0,0 +1,30 @@ +from ...subscription import SubscriptionModel, Subscription +from ....client import Client + + +class TeamSubscriptionManager: + def __init__(self, client: Client) -> None: + self._client = client + + def create(self, team_id: str, subscription: SubscriptionModel) -> Subscription: + """Create a new team subscription""" + payload = { + "team_id": team_id, + "contacts": subscription.contacts, + "tags": subscription.tags, + "enabled": subscription.enabled, + "any_tags": subscription.any_tags, + "throttling": subscription.throttling, + "sched": subscription.sched, + "ignore_warnings": subscription.ignore_warnings, + "ignore_recoverings": subscription.ignore_recoverings, + "plotting": subscription.plotting, + } + + response = self._client.post(self._full_path(team_id), json=payload) + + return Subscription(self._client, **response) + + @staticmethod + def _full_path(team_id: str) -> str: + return "teams/{team_id}/subscriptions".format(team_id=team_id) diff --git a/moira_client/models/team/user/__init__.py b/moira_client/models/team/user/__init__.py new file mode 100644 index 0000000..fd89c8e --- /dev/null +++ b/moira_client/models/team/user/__init__.py @@ -0,0 +1,7 @@ +from ._managers import TeamUserManager +from ._models import TeamMembers + +__all__ = [ + "TeamMembers", + "TeamUserManager", +] diff --git a/moira_client/models/team/user/_managers.py b/moira_client/models/team/user/_managers.py new file mode 100644 index 0000000..3fc5133 --- /dev/null +++ b/moira_client/models/team/user/_managers.py @@ -0,0 +1,43 @@ +from ._models import TeamMembers +from ....client import Client +from typing import Optional + + +class TeamUserManager: + def __init__(self, client: Client) -> None: + self._client = client + + def get(self, team_id: str) -> TeamMembers: + """Get users of a team""" + response = self._client.get(self._full_path(team_id)) + + return TeamMembers(**response) + + def add(self, team_id: str, members: TeamMembers) -> TeamMembers: + """Add users to a team""" + payload = {"usernames": members.usernames} + + response = self._client.post(self._full_path(team_id), json=payload) + + return TeamMembers(**response) + + def set(self, team_id: str, members: TeamMembers) -> TeamMembers: + """Set users of a team""" + payload = {"usernames": members.usernames} + + response = self._client.put(self._full_path(team_id), json=payload) + + return TeamMembers(**response) + + def delete(self, team_id: str, team_user_id: str) -> TeamMembers: + """Delete a user from a team""" + response = self._client.delete(self._full_path(team_id, team_user_id)) + + return TeamMembers(**response) + + @staticmethod + def _full_path(team_id: str, team_user_id: Optional[str] = None) -> str: + if team_user_id is None: + return "teams/{team_id}/users".format(team_id=team_id) + + return "teams/{team_id}/users/{team_user_id}".format(team_id=team_id, team_user_id=team_user_id) diff --git a/moira_client/models/team/user/_models.py b/moira_client/models/team/user/_models.py new file mode 100644 index 0000000..be7baaa --- /dev/null +++ b/moira_client/models/team/user/_models.py @@ -0,0 +1,6 @@ +from typing import List + + +class TeamMembers: + def __init__(self, usernames: List[str]) -> None: + self.usernames = usernames diff --git a/moira_client/moira.py b/moira_client/moira.py index 8c18c9f..8c2f150 100644 --- a/moira_client/moira.py +++ b/moira_client/moira.py @@ -9,6 +9,7 @@ from .models.health import HealthManager from .models.config import ConfigManager from .models.user import UserManager +from .models.team import TeamManager class Moira: @@ -34,6 +35,7 @@ def __init__(self, api_url, auth_custom=None, self._health = None self._config = None self._user = None + self._team = None @property def trigger(self): @@ -145,3 +147,12 @@ def user(self): if not self._user: self._user = UserManager(self._client) return self._user + + @property + def team(self) -> TeamManager: + """Get team manager + """ + if not self._team: + self._team = TeamManager(self._client) + + return self._team diff --git a/tests/models/team/__init__.py b/tests/models/team/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/models/team/_mock.py b/tests/models/team/_mock.py new file mode 100644 index 0000000..ff50876 --- /dev/null +++ b/tests/models/team/_mock.py @@ -0,0 +1,11 @@ +try: + from unittest.mock import patch, Mock + +except ImportError: + from mock import patch, Mock + + +__all__ = [ + "patch", + "Mock", +] diff --git a/tests/models/team/contact/__init__.py b/tests/models/team/contact/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/models/team/contact/test_managers.py b/tests/models/team/contact/test_managers.py new file mode 100644 index 0000000..b6510e7 --- /dev/null +++ b/tests/models/team/contact/test_managers.py @@ -0,0 +1,61 @@ +from moira_client.client import Client +from moira_client.models.contact import Contact +from moira_client.models.team.contact import TeamContactManager +from .._mock import patch, Mock +from ...test_model import ModelTest + + +class TestTeamContactManager(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + self._manager = TeamContactManager(self._client) + super().__init__(*args, **kwargs) + + @property + def _request_data(self) -> dict: + return { + "name": "Mail Alerts", + "team_id": "string", + "type": "mail", + "value": "devops@example.com", + } + + @property + def _response_data(self) -> dict: + return { + "id": "1dd38765-c5be-418d-81fa-7a5f879c2315", + "name": "Mail Alerts", + "team_id": "string", + "type": "mail", + "user": "", + "value": "devops@example.com", + } + + @property + def _contact(self) -> Contact: + return Contact(**self._request_data) + + def _assert_is_resource_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}/contacts".format(team_id=self._contact.team_id) + + def _assert_is_request_data_sent(self, request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 1 + assert kwargs["json"] == self._request_data + + def test_create(self) -> None: + with patch.object(self._client, "post", return_value=self._response_data) as request: + response = self._manager.create(self._contact.team_id, self._contact) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + assert response.id == self._response_data["id"] + assert response.name == self._response_data["name"] + assert response.team_id == self._response_data["team_id"] + assert response.type == self._response_data["type"] + assert response.user == self._response_data["user"] + assert response.value == self._response_data["value"] diff --git a/tests/models/team/settings/__init__.py b/tests/models/team/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/models/team/settings/test_managers.py b/tests/models/team/settings/test_managers.py new file mode 100644 index 0000000..93339a4 --- /dev/null +++ b/tests/models/team/settings/test_managers.py @@ -0,0 +1,115 @@ +from moira_client.client import Client +from moira_client.models.team.settings import TeamSettingsManager +from .._mock import patch, Mock +from ...test_model import ModelTest + + +class TestTeamSettingsManager(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + self._manager = TeamSettingsManager(self._client) + super().__init__(*args, **kwargs) + + @property + def _response_data_contact(self) -> dict: + return { + "id": "1dd38765-c5be-418d-81fa-7a5f879c2315", + "name": "Mail Alerts", + "team_id": "string", + "type": "mail", + "user": "", + "value": "devops@example.com", + } + + @property + def _response_data_subscription(self) -> dict: + return { + "any_tags": False, + "contacts": [ + "acd2db98-1659-4a2f-b227-52d71f6e3ba1", + ], + "enabled": True, + "id": "292516ed-4924-4154-a62c-ebe312431fce", + "ignore_recoverings": False, + "ignore_warnings": False, + "plotting": { + "enabled": True, + "theme": "dark", + }, + "sched": { + "days": [ + { + "enabled": True, + "name": "Mon", + } + ], + "endOffset": 1439, + "startOffset": 0, + "tzOffset": -60, + }, + "tags": [ + "server", + "cpu", + ], + "team_id": "324516ed-4924-4154-a62c-eb124234fce", + "throttling": False, + "user": "", + } + + @property + def _team_id(self) -> str: + return "d5d98eb3-ee18-4f75-9364-244f67e23b54" + + @property + def _response_data(self) -> dict: + return { + "contacts": [ + self._response_data_contact, + ], + "subscriptions": [ + self._response_data_subscription, + ], + "team_id": self._team_id, + } + + def _assert_is_resource_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}/settings".format(team_id=self._team_id) + + @staticmethod + def _assert_is_no_data_sent(request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 0 + + def test_get_all(self) -> None: + with patch.object(self._client, "get", return_value=self._response_data) as request: + response = self._manager.get(self._team_id) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_no_data_sent(request) + + assert response.team_id == self._team_id + + assert len(response.contacts) == 1 + + assert response.contacts[0].id == self._response_data_contact["id"] + assert response.contacts[0].name == self._response_data_contact["name"] + assert response.contacts[0].team_id == self._response_data_contact["team_id"] + assert response.contacts[0].type == self._response_data_contact["type"] + assert response.contacts[0].user == self._response_data_contact["user"] + assert response.contacts[0].value == self._response_data_contact["value"] + + assert len(response.subscriptions) == 1 + + assert response.subscriptions[0].team_id == self._response_data_subscription["team_id"] + assert response.subscriptions[0].contacts == self._response_data_subscription["contacts"] + assert response.subscriptions[0].tags == self._response_data_subscription["tags"] + assert response.subscriptions[0].enabled == self._response_data_subscription["enabled"] + assert response.subscriptions[0].any_tags == self._response_data_subscription["any_tags"] + assert response.subscriptions[0].throttling == self._response_data_subscription["throttling"] + assert response.subscriptions[0].sched == self._response_data_subscription["sched"] + assert response.subscriptions[0].ignore_warnings == self._response_data_subscription["ignore_warnings"] + assert response.subscriptions[0].ignore_recoverings == self._response_data_subscription["ignore_recoverings"] + assert response.subscriptions[0].plotting == self._response_data_subscription["plotting"] diff --git a/tests/models/team/subscription/__init__.py b/tests/models/team/subscription/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/models/team/subscription/test_managers.py b/tests/models/team/subscription/test_managers.py new file mode 100644 index 0000000..e3e8ea8 --- /dev/null +++ b/tests/models/team/subscription/test_managers.py @@ -0,0 +1,87 @@ +from moira_client.client import Client +from moira_client.models.subscription import SubscriptionModel +from moira_client.models.team.subscription import TeamSubscriptionManager +from .._mock import patch, Mock +from ...test_model import ModelTest + + +class TestTeamSubscriptionManager(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + self._manager = TeamSubscriptionManager(self._client) + super().__init__(*args, **kwargs) + + @property + def _request_data(self) -> dict: + return { + "team_id": "324516ed-4924-4154-a62c-eb124234fce", + "contacts": [ + "acd2db98-1659-4a2f-b227-52d71f6e3ba1", + ], + "tags": [ + "server", + "cpu", + ], + "enabled": True, + "any_tags": False, + "throttling": False, + "sched": { + "days": [ + { + "enabled": True, + "name": "Mon", + }, + ], + "endOffset": 1439, + "startOffset": 0, + "tzOffset": -60, + }, + "ignore_warnings": False, + "ignore_recoverings": False, + "plotting": { + "enabled": True, + "theme": "dark", + }, + } + + @property + def _response_data(self) -> dict: + return { + "id": "292516ed-4924-4154-a62c-ebe312431fce", + **self._request_data, + } + + @property + def _subscription(self) -> SubscriptionModel: + return SubscriptionModel(**self._request_data) + + def _assert_is_resource_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}/subscriptions".format( + team_id=self._subscription.team_id, + ) + + def _assert_is_request_data_sent(self, request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 1 + assert kwargs["json"] == self._request_data + + def test_create(self) -> None: + with patch.object(self._client, "post", return_value=self._response_data) as request: + response = self._manager.create(self._subscription.team_id, self._subscription) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + assert response.team_id == self._response_data["team_id"] + assert response.contacts == self._response_data["contacts"] + assert response.tags == self._response_data["tags"] + assert response.enabled == self._response_data["enabled"] + assert response.any_tags == self._response_data["any_tags"] + assert response.throttling == self._response_data["throttling"] + assert response.sched == self._response_data["sched"] + assert response.ignore_warnings == self._response_data["ignore_warnings"] + assert response.ignore_recoverings == self._response_data["ignore_recoverings"] + assert response.plotting == self._response_data["plotting"] diff --git a/tests/models/team/subscription/test_models.py b/tests/models/team/subscription/test_models.py new file mode 100644 index 0000000..e4c84fe --- /dev/null +++ b/tests/models/team/subscription/test_models.py @@ -0,0 +1,83 @@ +from moira_client.client import Client +from moira_client.models.subscription import Subscription +from .._mock import patch, Mock +from ...test_model import ModelTest + + +class TestSubscription(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + super().__init__(*args, **kwargs) + + @property + def _request_data(self) -> dict: + return { + "team_id": "324516ed-4924-4154-a62c-eb124234fce", + "contacts": [ + "acd2db98-1659-4a2f-b227-52d71f6e3ba1", + ], + "tags": [ + "server", + "cpu", + ], + "enabled": True, + "any_tags": False, + "throttling": False, + "sched": { + "days": [ + { + "enabled": True, + "name": "Mon", + }, + ], + "endOffset": 1439, + "startOffset": 0, + "tzOffset": -60, + }, + "ignore_warnings": False, + "ignore_recoverings": False, + "plotting": { + "enabled": True, + "theme": "dark", + }, + } + + @property + def _response_data(self) -> dict: + return { + "id": "292516ed-4924-4154-a62c-ebe312431fce", + **self._request_data, + } + + @staticmethod + def _assert_is_resource_request(request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "subscription" + + def _assert_is_request_data_sent(self, request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 1 + assert kwargs["json"] == self._request_data + + def test_save(self) -> None: + subscription = Subscription(self._client, **self._request_data) + + with patch.object(self._client, "put", return_value=self._response_data) as request: + subscription.save() + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + assert subscription.id == self._response_data["id"] + assert subscription.team_id == self._response_data["team_id"] + assert subscription.contacts == self._response_data["contacts"] + assert subscription.tags == self._response_data["tags"] + assert subscription.enabled == self._response_data["enabled"] + assert subscription.any_tags == self._response_data["any_tags"] + assert subscription.throttling == self._response_data["throttling"] + assert subscription.sched == self._response_data["sched"] + assert subscription.ignore_warnings == self._response_data["ignore_warnings"] + assert subscription.ignore_recoverings == self._response_data["ignore_recoverings"] + assert subscription.plotting == self._response_data["plotting"] diff --git a/tests/models/team/test_managers.py b/tests/models/team/test_managers.py new file mode 100644 index 0000000..25d7860 --- /dev/null +++ b/tests/models/team/test_managers.py @@ -0,0 +1,121 @@ +from moira_client.client import Client +from moira_client.models.team import TeamManager, TeamModel +from ._mock import patch, Mock +from ..test_model import ModelTest + + +class TestTeamManager(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + self._manager = TeamManager(self._client) + super().__init__(*args, **kwargs) + + @property + def _request_data(self) -> dict: + return { + "name": "Infrastructure Team", + "description": "Team that holds all members of infrastructure division", + } + + @property + def _single_response_data(self) -> dict: + return { + "id": "d5d98eb3-ee18-4f75-9364-244f67e23b54", + } + + @property + def _response_data(self) -> dict: + return { + **self._single_response_data, + **self._request_data, + } + + @property + def _team(self) -> TeamModel: + return TeamModel( + id="d5d98eb3-ee18-4f75-9364-244f67e23b54", + name="Infrastructure Team", + description="Team that holds all members of infrastructure division", + ) + + @staticmethod + def _assert_is_resource_request(request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams" + + def _assert_is_object_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}".format(team_id=self._team.id) + + def _assert_is_request_data_sent(self, request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 1 + assert kwargs["json"] == self._request_data + + @staticmethod + def _assert_is_no_data_sent(request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 0 + + def test_get_all(self) -> None: + return_value = { + "teams": [ + self._response_data, + ], + } + + with patch.object(self._client, "get", return_value=return_value) as request: + response = self._manager.get_all() + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_no_data_sent(request) + + assert len(response.teams) == 1 + assert response.teams[0].id == self._response_data["id"] + assert response.teams[0].name == self._response_data["name"] + assert response.teams[0].description == self._response_data["description"] + + def test_create(self): + with patch.object(self._client, "post", return_value=self._single_response_data) as request: + response = self._manager.create(self._team) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + assert response.id == self._single_response_data["id"] + + def test_delete(self): + with patch.object(self._client, "delete", return_value=self._single_response_data) as request: + response = self._manager.delete(self._team.id) + + assert len(request.mock_calls) == 1 + self._assert_is_object_request(request) + self._assert_is_no_data_sent(request) + + assert response.id == self._single_response_data["id"] + + def test_get(self): + with patch.object(self._client, "get", return_value=self._response_data) as request: + response = self._manager.get(self._team.id) + + assert len(request.mock_calls) == 1 + self._assert_is_object_request(request) + self._assert_is_no_data_sent(request) + + assert response.id == self._response_data["id"] + assert response.name == self._response_data["name"] + assert response.description == self._response_data["description"] + + def test_update(self): + with patch.object(self._client, "put", return_value=self._single_response_data) as request: + response = self._manager.update(self._team.id, self._team) + + assert len(request.mock_calls) == 1 + self._assert_is_object_request(request) + self._assert_is_request_data_sent(request) + + assert response.id == self._single_response_data["id"] diff --git a/tests/models/team/user/__init__.py b/tests/models/team/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/models/team/user/test_managers.py b/tests/models/team/user/test_managers.py new file mode 100644 index 0000000..c9e37dd --- /dev/null +++ b/tests/models/team/user/test_managers.py @@ -0,0 +1,88 @@ +from moira_client.client import Client +from moira_client.models.team.user import TeamUserManager, TeamMembers +from .._mock import patch, Mock +from ...test_model import ModelTest + + +class TestTeamUserManager(ModelTest): + def __init__(self, *args, **kwargs) -> None: + self._client = Client(self.api_url) + self._manager = TeamUserManager(self._client) + super().__init__(*args, **kwargs) + + @property + def _request_data(self) -> dict: + return { + "usernames": ["anonymous"], + } + + @property + def _response_data(self) -> dict: + return self._request_data + + @property + def _users(self) -> TeamMembers: + return TeamMembers(**self._request_data) + + @property + def _team_id(self) -> str: + return "d5d98eb3-ee18-4f75-9364-244f67e23b54" + + def _assert_is_resource_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}/users".format(team_id=self._team_id) + + def _assert_is_object_request(self, request: Mock) -> None: + args = request.call_args[0] + assert len(args) == 1 + assert args[0] == "teams/{team_id}/users/{team_user_id}".format( + team_id=self._team_id, + team_user_id=self._users.usernames[0], + ) + + def _assert_is_request_data_sent(self, request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 1 + assert kwargs["json"] == self._request_data + + @staticmethod + def _assert_is_no_data_sent(request: Mock) -> None: + kwargs = request.call_args[1] + assert len(kwargs) == 0 + + def _assert_response(self, response) -> None: + assert len(response.usernames) == 1 + assert response.usernames[0] == self._response_data["usernames"][0] + + def test_get(self) -> None: + with patch.object(self._client, "get", return_value=self._response_data) as request: + self._assert_response(self._manager.get(self._team_id)) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_no_data_sent(request) + + def test_add(self) -> None: + with patch.object(self._client, "post", return_value=self._response_data) as request: + self._assert_response(self._manager.add(self._team_id, self._users)) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + def test_set(self) -> None: + with patch.object(self._client, "put", return_value=self._response_data) as request: + self._assert_response(self._manager.set(self._team_id, self._users)) + + assert len(request.mock_calls) == 1 + self._assert_is_resource_request(request) + self._assert_is_request_data_sent(request) + + def test_delete(self) -> None: + with patch.object(self._client, "delete", return_value=self._response_data) as request: + self._assert_response(self._manager.delete(self._team_id, self._users.usernames[0])) + + assert len(request.mock_calls) == 1 + self._assert_is_object_request(request) + self._assert_is_no_data_sent(request)