Beispiel #1
0
def create_test_team(tid: str,
                     team_name: str,
                     display_name: str) -> Team:
    """
    Create a test team with team name, and with all other attributes the same.

    ==========  =============================
    Property    Preset
    ==========  =============================
    Github      ``tid``
    Name slug   ``team_name``
    Display     ``display_name``
    Platform    slack
    Members     ['abc_123']
    ==========  =============================

    :param tid: The github ID associated with the team
    :param team_name: The github team name slug
    :param display_name: The github team name
    :return: a filled-in team model (no empty strings)
    """
    t = Team(tid, team_name, display_name)
    t.platform = 'slack'
    t.add_member('abc_123')
    return t
Beispiel #2
0
class TestGCPUtils(TestCase):
    def setUp(self):
        self.u0 = User('U93758')
        self.u0.github_id = '22343'
        self.u0.github_username = '******'
        self.u0.email = '*****@*****.**'

        self.t0 = Team('465884', 'team-plasma', 'Team Plasma')
        self.t0.add_member(self.u0.github_id)
        self.t0.folder = 'oieasotbokneawsoieomieaomiewrsdoie'

        self.t1 = Team('394783', 'team-rocket', 'Team Rocket')
        self.t1.add_member(self.u0.github_id)

        self.db = MemoryDB(users=[self.u0], teams=[self.t0, self.t1])

        self.gcp = mock.MagicMock(GCPInterface)

    def test_sync_user_email_perms(self):
        sync_user_email_perms(self.gcp, self.db, self.u0)

        self.gcp.ensure_drive_permissions.assert_called_once_with(
            self.t0.github_team_name, self.t0.folder, [self.u0.email]
        )

    def test_sync_team_email_perms_bad_email(self):
        self.u0.email = 'bad@[email protected]'
        sync_team_email_perms(self.gcp, self.db, self.t0)

        self.gcp.ensure_drive_permissions.assert_not_called()
Beispiel #3
0
    def handle_added(self,
                     github_id: str,
                     github_username: str,
                     organization: str) -> ResponseTuple:
        """Help organization function if payload action is added."""
        logging.info(f"user {github_username} added to {organization}")
        all_name = self._conf.github_team_all

        try:
            # Try to add the user to the 'all' team if it exists
            team_all = get_team_by_name(self._facade, all_name)
            self._gh.add_team_member(github_username, team_all.github_team_id)
            team_all.add_member(github_id)
            self._facade.store(team_all)
        except LookupError:
            # If that team doesn't exist, make it exist
            t_id = str(self._gh.org_create_team(self._conf.github_team_all))
            self._gh.add_team_member(github_username, t_id)
            logging.info(f'team {all_name} created for {organization}')
            team = Team(t_id, all_name, all_name)
            team.add_member(github_id)
            self._facade.store(team)
        except RuntimeError as e:
            # If there are any other kinds of errors, we log it
            logging.error(e)
            return '', 200

        logging.info(f'user {github_username} added to team {all_name}')
        return f"user {github_username} added to {organization}", 200
Beispiel #4
0
def test_is_member():
    """Test the Team class method is_member(github_id)."""
    team = Team("1", "brussel-sprouts", "Brussel Sprouts")
    new_github_id = "U0G9QF9C6"
    assert team.has_member(new_github_id) is False
    team.add_member(new_github_id)
    assert team.has_member(new_github_id)
Beispiel #5
0
def test_discard_member():
    """Test the Team class method discard_member(github_id)."""
    team = Team("1", "brussel-sprouts", "Brussel Sprouts")
    new_github_id = "U0G9QF9C6"
    team.add_member(new_github_id)
    team.discard_member(new_github_id)
    assert team.members == set()
 def test_check_credentials_not_lead(self):
     """Test checking to see if user is lead for certain team."""
     user = User("USFAS689")
     user.github_id = "IDGithub"
     team = Team("brussels", "team", "id")
     team.add_member(user.github_id)
     user.permissions_level = Permissions.team_lead
     self.assertFalse(util.check_permissions(user, team))
Beispiel #7
0
def test_update_team(ddb):
    """Test to see if we can update a team."""
    t = Team('1', 'brussel-sprouts', 'Brussel Sprouts')
    ddb.store(t)

    t = ddb.retrieve(Team, '1')
    t.add_member('abc_123')
    t.add_member('123_abc')
    ddb.store(t)

    assert len(ddb.retrieve(Team, '1').members) == 2
Beispiel #8
0
 def test_create_with_lead(self) -> None:
     """Test create team command API with lead."""
     self.mock_github.org_create_team.return_value = "team_gh_id"
     created = self.testapi.team_create(
         "admin", "team_name", lead_id="lead")
     self.assertTrue(created)
     stored_team = Team("team_gh_id", "team_name", "")
     stored_team.add_member(self.admin_user.github_id)
     stored_team.add_member(self.lead_user.github_id)
     stored_team.add_team_lead(self.lead_user.github_id)
     self.mock_facade.store.assert_called_once_with(stored_team)
Beispiel #9
0
    def test_update_team(self):
        """Test to see if we can update a team."""
        t = Team('1', 'brussel-sprouts', 'Brussel Sprouts')
        self.assertTrue(self.ddb.store(t))

        t = self.ddb.retrieve(Team, '1')
        t.add_member('abc_123')
        t.add_member('123_abc')
        self.assertTrue(self.ddb.store(t))

        self.assertEqual(len(self.ddb.retrieve(Team, '1').members), 2)
Beispiel #10
0
 def test_create_with_display_name(self) -> None:
     """Test create team command API with display name."""
     self.mock_github.org_create_team.return_value = "team_gh_id"
     created = self.testapi.team_create("lead",
                                        "team_name",
                                        display_name="display_name")
     self.assertTrue(created)
     stored_team = Team("team_gh_id", "team_name", "display_name")
     stored_team.add_member(self.lead_user.github_id)
     stored_team.add_team_lead(self.lead_user.github_id)
     self.mock_facade.store.assert_called_with(stored_team)
Beispiel #11
0
 def test_create_store_fail(self) -> None:
     """Test create team command API with failing store."""
     self.mock_facade.store.return_value = False
     self.mock_github.org_create_team.return_value = "team_gh_id"
     created = self.testapi.team_create("lead", "team_name")
     self.assertFalse(created)
     stored_team = Team("team_gh_id", "team_name", "")
     stored_team.add_member(self.lead_user.github_id)
     stored_team.add_team_lead(self.lead_user.github_id)
     self.mock_github.add_team_member.assert_called_once_with(
         self.lead_user.github_username, "team_gh_id")
     self.mock_facade.store.assert_called_once_with(stored_team)
Beispiel #12
0
def test_print():
    """Test print team class."""
    team = Team("1", "brussel-sprouts", "Brussel Sprouts")
    new_slack_id = "U0G9QF9C6"
    team.add_member(new_slack_id)
    team.add_team_lead(new_slack_id)
    team.platform = "web"
    assert str(team) == "{'github_team_id': '1'," \
                        " 'github_team_name': 'brussel-sprouts'," \
                        " 'display_name': 'Brussel Sprouts'," \
                        " 'platform': 'web'," \
                        " 'team_leads': {'U0G9QF9C6'}," \
                        " 'members': {'U0G9QF9C6'}}"
Beispiel #13
0
 def test_create_add_channel_members(self) -> None:
     """Test create team command API with specified channel."""
     self.mock_slack.get_channel_users.return_value = \
         {self.regular_user.slack_id: self.regular_user}
     self.mock_facade.bulk_retrieve.return_value = [self.regular_user]
     self.mock_github.org_create_team.return_value = "team_gh_id"
     created = self.testapi.team_create(
         "lead", "team_name", channel="channel")
     self.assertTrue(created)
     stored_team = Team("team_gh_id", "team_name", "")
     stored_team.add_member(self.regular_user.github_id)
     stored_team.add_team_lead(self.lead_user.github_id)
     self.mock_github.add_team_member.assert_called_with(
         self.regular_user.github_username, "team_gh_id")
     self.mock_facade.store.assert_called_once_with(stored_team)
Beispiel #14
0
def test_handle_mem_event_add_member(mock_logging, mem_add_payload):
    """Test that instances when members are added to the mem are logged."""
    mock_facade = mock.MagicMock(DBFacade)
    return_user = User("SLACKID")
    return_team = Team("2723476", "rocket", "rocket")
    return_team.add_member("SLACKID")
    mock_facade.query.return_value = [return_user]
    mock_facade.retrieve.return_value = return_team
    webhook_handler = MembershipEventHandler(mock_facade)
    rsp, code = webhook_handler.handle(mem_add_payload)
    mock_facade.store.assert_called_once_with(return_team)
    mock_logging.info.assert_called_once_with(("user Codertocat added "
                                               "to rocket"))
    assert rsp == "added slack ID SLACKID"
    assert code == 200
Beispiel #15
0
 def test_refresh_github_changed_success(self) -> None:
     """Test refresh team command API to edit teams."""
     new_team1 = Team("1", "newgh1", "name1")
     new_team1.add_member(self.regular_user.github_id)
     self.mock_github.org_get_teams.return_value = [
         new_team1,
         self.team2,
         self.team3,
         self.team3_dup,
     ]
     refreshed = self.testapi.team_refresh("admin")
     self.assertTrue(refreshed)
     self.team1.github_team_name = "newgh1"
     self.team1.add_member(self.regular_user.github_id)
     self.mock_facade.store.assert_called_once_with(self.team1)
Beispiel #16
0
 def mem_added(self, github_id: str, selected_team: Team, team_name: str,
               github_username: str) -> ResponseTuple:
     """Help membership function if payload action is added."""
     member_list = self._facade.query(User, [('github_user_id', github_id)])
     slack_ids_string = ""
     if len(member_list) > 0:
         selected_team.add_member(github_id)
         self._facade.store(selected_team)
         for member in member_list:
             slack_id = member.slack_id
             logging.info(f"user {github_username} added to {team_name}")
             slack_ids_string += f" {slack_id}"
         return f"added slack ID{slack_ids_string}", 200
     else:
         logging.error(f"could not find user {github_id}")
         return f"could not find user {github_username}", 404
Beispiel #17
0
def test_handle_mem_event_rm_single_member(mock_logging, mem_rm_payload):
    """Test that members removed from the mem are deleted from rocket's db."""
    mock_facade = mock.MagicMock(DBFacade)
    return_user = User("SLACKID")
    return_team = Team("2723476", "rocket", "rocket")
    return_team.add_member("21031067")
    mock_facade.query.return_value = [return_user]
    mock_facade.retrieve.return_value = return_team
    webhook_handler = MembershipEventHandler(mock_facade)
    (rsp, code) = webhook_handler.handle(mem_rm_payload)
    mock_facade.query\
        .assert_called_once_with(User, [('github_user_id', "21031067")])
    mock_facade.retrieve \
        .assert_called_once_with(Team, "2723476")
    mock_facade.store.assert_called_once_with(return_team)
    mock_logging.info.assert_called_once_with("deleted slack user SLACKID"
                                              " from rocket")
    assert not return_team.has_member("21031067")
    assert rsp == "deleted slack ID SLACKID from rocket"
    assert code == 200
Beispiel #18
0
    def test_handle_refresh_changed(self):
        """Test team command refresh parser if team edited in github."""
        team = Team('TeamID', 'TeamName', 'android')
        team_update = Team('TeamID', 'new team name', 'android')
        team_update.add_member(self.admin.github_id)
        team2 = Team('OTEAM', 'other team2', 'ios')

        self.db.teams = {}
        self.db.teams['TeamID'] = team
        self.db.teams['OTEAM'] = team2

        self.gh.org_get_teams.return_value = [team_update, team2]
        attach = team_update.get_attachment()

        status = '1 teams changed, 0 added, 0 deleted. Wonderful.'
        with self.app.app_context():
            resp, code = self.testcommand.handle('team refresh',
                                                 self.admin.slack_id)
            expect = {'attachments': [attach], 'text': status}
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
            self.assertEqual(team, team_update)
Beispiel #19
0
class TestDbUtils(TestCase):
    def setUp(self):
        self.u0 = User('U395474')
        self.u0.github_id = '321132'
        self.u1 = User('U85739')
        self.u1.github_id = '000584'
        self.u2 = User('U3048485')
        self.u2.github_id = '11121'
        self.t0 = Team('305738', 'some-team', 'Some Team')
        self.t0.add_member(self.u0.github_id)
        self.t0.add_member(self.u1.github_id)
        self.t1 = Team('305849', 'some-team', 'Some Team')
        self.db = MemoryDB(users=[self.u0, self.u1, self.u2], teams=[self.t0])

    def test_get_users_by_ghid_empty_list(self):
        self.assertEqual(get_users_by_ghid(self.db, []), [])

    def test_get_team_members(self):
        self.assertCountEqual(get_team_members(self.db, self.t0),
                              [self.u0, self.u1])

    def test_get_team_by_name_lots_of_teams_same_name(self):
        db = MemoryDB(teams=[self.t0, self.t1])
        with self.assertRaises(RuntimeError):
            get_team_by_name(db, 'some-team')

    def test_get_team_by_name_no_team_name(self):
        with self.assertRaises(LookupError):
            get_team_by_name(self.db, 'random-team')

    def test_get_users_by_ghid(self):
        self.assertCountEqual(
            get_users_by_ghid(
                self.db,
                [self.u0.github_id, self.u1.github_id, self.u2.github_id]),
            [self.u0, self.u1, self.u2])
Beispiel #20
0
    def refresh_all_team(self):
        """
        Refresh the 'all' team - this team is used to track all members.

        Should only be called after the teams have all synced, or bugs will
        probably occur. See https://github.com/orgs/ubclaunchpad/teams/all
        """
        all_name = self.config.github_team_all
        team_all = None
        if len(all_name) == 0:
            logging.info('no "all" team configured, skipping refresh')
            return

        logging.info(f'refreshing all team {all_name}')
        try:
            team_all = get_team_by_name(self.facade, all_name)
        except LookupError:
            t_id = str(self.gh.org_create_team(all_name))
            logging.info(f'team {all_name} created')
            team_all = Team(t_id, all_name, all_name)

        if team_all is not None:
            all_members = self.facade.query(User)
            for m in all_members:
                if len(m.github_id) > 0 and\
                        not team_all.has_member(m.github_id):
                    # The only way for this to be true is if both locally and
                    # remotely the member (who is part of launchpad) is not
                    # part of the 'all' team.
                    self.gh.add_team_member(m.github_username,
                                            team_all.github_team_id)
                    team_all.add_member(m.github_id)

            self.facade.store(team_all)
        else:
            logging.error(f'Could not create {all_name}. Aborting.')
Beispiel #21
0
class TestUserCommand(TestCase):
    def setUp(self):
        self.app = Flask(__name__)

        self.u0 = User('U0G9QF9C6')
        self.u1 = User('Utheomadude')
        self.t0 = Team("BRS", "brs", "web")
        self.t1 = Team("OTEAM", "other team", "android")
        self.admin = create_test_admin('Uadmin')
        self.db = MemoryDB(users=[self.u0, self.u1, self.admin],
                           teams=[self.t0, self.t1])

        self.mock_github = mock.MagicMock(GithubInterface)
        self.testcommand = UserCommand(self.db, self.mock_github, None)
        self.maxDiff = None

    def test_get_help(self):
        """Test user command get_help method."""
        subcommands = list(self.testcommand.subparser.choices.keys())
        help_message = self.testcommand.get_help()
        self.assertEqual(len(subcommands) + 1, help_message.count("\n"))

    def test_get_subcommand_help(self):
        """Test user command get_help method for specific subcommands."""
        subcommands = list(self.testcommand.subparser.choices.keys())
        for subcommand in subcommands:
            help_message = self.testcommand.get_help(subcommand=subcommand)
            self.assertEqual(1, help_message.count("usage"))

    def test_get_invalid_subcommand_help(self):
        """Test user command get_help method for invalid subcommands."""
        self.assertEqual(self.testcommand.get_help(),
                         self.testcommand.get_help(subcommand="foo"))

    def test_handle_nosubs(self):
        """Test user with no sub-parsers."""
        self.assertEqual(self.testcommand.handle('user',
                                                 self.u0.slack_id),
                         (self.testcommand.get_help(), 200))

    def test_handle_bad_args(self):
        """Test user with invalid arguments."""
        self.assertEqual(self.testcommand.handle('user geese',
                                                 self.u0.slack_id),
                         (self.testcommand.get_help(), 200))

    def test_handle_add(self):
        """Test user command add method."""
        user_id = "U0G9QF9C7"
        user = User(user_id)
        self.assertTupleEqual(self.testcommand.handle('user add', user_id),
                              ('User added!', 200))
        retr = self.db.retrieve(User, user_id)
        self.assertEqual(user, retr)

    def test_handle_add_no_overwriting(self):
        """Test user command add method when user exists in db."""
        user = User(self.u0.slack_id)
        err_msg = 'User already exists; to overwrite user, add `-f`'
        resp = self.testcommand.handle('user add', user.slack_id)
        self.assertTupleEqual(resp, (err_msg, 200))

    def test_handle_add_with_force(self):
        ret = self.testcommand.handle('user add -f', self.u0.slack_id)
        self.assertEqual(ret, ('User added!', 200))

    def test_handle_view(self):
        user_attaches = [self.u0.get_attachment()]
        with self.app.app_context():
            # jsonify requires translating the byte-string
            resp, _ = self.testcommand.handle('user view',
                                              self.u0.slack_id)
            expect = {'attachments': user_attaches}
            self.assertDictEqual(resp, expect)

    def test_handle_view_other_user_by_slack(self):
        user = User("ABCDE8FA9")
        self.db.store(user)
        command = 'user view --username ' + user.slack_id
        user_attaches = [user.get_attachment()]
        with self.app.app_context():
            # jsonify requires translating the byte-string
            resp, _ = self.testcommand.handle(command, self.u0.slack_id)
            expect = {'attachments': user_attaches}
            self.assertDictEqual(resp, expect)

    def test_handle_view_other_user_by_github(self):
        user = User("ABCDE8FA9")
        user.github_username = '******'
        self.db.store(user)
        command = 'user view --github ' + user.github_username
        user_attaches = [user.get_attachment()]
        with self.app.app_context():
            # jsonify requires translating the byte-string
            resp, _ = self.testcommand.handle(command, self.u0.slack_id)
            expect = {'attachments': user_attaches}
            self.assertDictEqual(resp, expect)

    def test_handle_view_other_user_by_email(self):
        user = User("ABCDE8FA9")
        user.email = '*****@*****.**'
        self.db.store(user)
        command = 'user view --email ' + user.email
        user_attaches = [user.get_attachment()]
        with self.app.app_context():
            # jsonify requires translating the byte-string
            resp, _ = self.testcommand.handle(command, self.u0.slack_id)
            expect = {'attachments': user_attaches}
            self.assertDictEqual(resp, expect)

    def test_handle_view_multiple_users(self):
        user = User("ABCDE8FA9")
        user.email = '*****@*****.**'
        self.db.store(user)
        user2 = User("ABCDE8FA0")
        user2.email = '*****@*****.**'
        self.db.store(user2)
        command = 'user view --email ' + user.email
        user_attaches = [user.get_attachment(), user2.get_attachment()]
        with self.app.app_context():
            # jsonify requires translating the byte-string
            resp, _ = self.testcommand.handle(command, self.u0.slack_id)
            expect = {
                'text': 'Warning - multiple users found!',
                'attachments': user_attaches,
            }
            self.assertDictEqual(resp, expect)

    def test_handle_view_lookup_error(self):
        command = 'user view --username ABCDE8FA9'
        self.assertTupleEqual(self.testcommand.handle(command,
                                                      self.u0.slack_id),
                              (UserCommand.lookup_error, 200))

    def test_handle_help(self):
        self.assertEqual(self.testcommand.handle('user help',
                                                 self.u0.slack_id),
                         (self.testcommand.get_help(), 200))

    def test_handle_delete(self):
        message = f'Deleted user with Slack ID: {self.u0.slack_id}'
        cmd = f'user delete {self.u0.slack_id}'
        self.assertEqual(self.testcommand.handle(cmd, self.admin.slack_id),
                         (message, 200))
        with self.assertRaises(LookupError):
            self.db.retrieve(User, self.u0.slack_id)

    def test_handle_delete_not_admin(self):
        cmd = f'user delete {self.u1.slack_id}'
        self.assertEqual(self.testcommand.handle(cmd, self.u0.slack_id),
                         (UserCommand.permission_error, 200))

    def test_handle_delete_callinguser_lookup_error(self):
        cmd = f'user delete {self.u1.slack_id}'
        self.assertEqual(self.testcommand.handle(cmd, 'rando.id'),
                         (UserCommand.lookup_error, 200))

    def test_handle_edit_name(self):
        with self.app.app_context():
            resp, _ = self.testcommand.handle('user edit --name rob',
                                              self.u0.slack_id)
            expect = {'title': 'Name', 'value': 'rob', 'short': True}
            self.assertIn(expect, resp['attachments'][0]['fields'])

    def test_handle_edit_github(self):
        """Test that editing github username sends request to interface."""
        self.mock_github.org_add_member.return_value = "123"
        with self.app.app_context():
            resp, _ = self.testcommand.handle("user edit --github rob",
                                              self.u0.slack_id)
            expect0 = {'title': 'Github Username',
                       'value': 'rob',
                       'short': True}
            expect1 = {'title': 'Github ID', 'value': '123', 'short': True}
            self.assertIn(expect0, resp['attachments'][0]['fields'])
            self.assertIn(expect1, resp['attachments'][0]['fields'])
        self.mock_github.org_add_member.assert_called_once_with("rob")

    def test_handle_edit_github_error(self):
        self.mock_github.org_add_member.side_effect = GithubAPIException("")

        with self.app.app_context():
            resp, _ = self.testcommand.handle('user edit --github rob',
                                              self.u0.slack_id)
            expect = {
                'attachments': [self.u0.get_attachment()],
                'text': '\nError adding user rob to GitHub organization'
            }

            self.assertDictEqual(resp, expect)

    def test_handle_edit_all_fields(self):
        user = User(self.u0.slack_id)
        user.name = 'rob'
        user.email = '*****@*****.**'
        user.position = 'dev'
        user.github_username = '******'
        user.github_id = '123'
        user.major = 'Computer Science'
        user.biography = 'Im a human lol'
        user.permissions_level = Permissions.member
        expect = {'attachments': [user.get_attachment()]}
        self.mock_github.org_add_member.return_value = "123"
        with self.app.app_context():
            resp, _ = self.testcommand.handle(
                "user edit "
                "--name rob "
                "--email <mailto:[email protected]|[email protected]> --pos dev --github"
                " rob --major 'Computer Science'"
                " --bio 'Im a human lol'",
                self.u0.slack_id)
            self.assertDictEqual(resp, expect)

    def test_handle_edit_not_admin(self):
        """Test user command with editor user that is not admin."""
        self.assertEqual(self.testcommand.handle(
            'user edit --username ' + self.u1.slack_id + ' '
            '--name rob '
            '--email <mailto:[email protected]|[email protected]> --pos dev --github'
            ' [email protected] --major \'Computer Science\''
            ' --bio \'Im a human\'',
            self.u0.slack_id),
            (UserCommand.permission_error, 200))

    def test_handle_edit_make_admin(self):
        with self.app.app_context():
            resp, _ = self.testcommand.handle(
                f"user edit --username {self.u0.slack_id} "
                "--permission admin",
                self.admin.slack_id)
            expect = {'title': 'Permissions Level',
                      'value': 'admin',
                      'short': True}
            self.assertIn(expect, resp['attachments'][0]['fields'])

    def test_handle_edit_make_self_admin_no_perms(self):
        with self.app.app_context():
            resp, _ = self.testcommand.handle(
                "user edit --permission admin", self.u0.slack_id)
            expect = {
                'attachments': [self.u0.get_attachment()],
                'text': "\nCannot change own permission: user isn't admin."
            }
            self.assertDictEqual(resp, expect)

    def test_handle_edit_lookup_error_editee(self):
        self.assertEqual(self.testcommand.handle(
            "user edit --username random.something "
            "--name rob "
            "--email <mailto:[email protected]|[email protected]> --pos dev --github"
            " [email protected] --major 'Computer Science'"
            " --bio 'Im a human'",
            self.admin.slack_id),
            (UserCommand.lookup_error, 200))

    def test_handle_edit_lookup_error(self):
        """Test user command where user is not in database."""
        self.assertEqual(self.testcommand.handle('user edit --name rob',
                                                 'rando'),
                         (UserCommand.lookup_error, 200))

    def test_handle_command_help(self):
        ret, _ = self.testcommand.handle('user help', self.u0.slack_id)
        self.assertEqual(ret, self.testcommand.get_help())

    def test_handle_multiple_subcommands(self):
        """Test handling multiple observed subcommands."""
        ret, _ = self.testcommand.handle('user edit view', self.u0.slack_id)
        self.assertEqual(ret, self.testcommand.get_help())

    def test_handle_subcommand_help(self):
        subcommands = list(self.testcommand.subparser.choices.keys())
        for subcommand in subcommands:
            cmd_args = ['--help', '-h', '--invalid argument']
            for arg in cmd_args:
                command = f'user {subcommand} {arg}'
                ret, _ = self.testcommand.handle(command, self.u0.slack_id)
                self.assertEqual(1, ret.count("usage"))
                self.assertIn(subcommand, ret)

    def test_handle_view_inspect(self):
        self.u0.name = 'John Peters'
        self.u0.email = '*****@*****.**'
        self.u0.github_id = '328593'
        self.u0.github_username = '******'
        self.t0.add_member(self.u0.github_id)
        self.t1.add_team_lead(self.u0.github_id)
        team_names = '\n'.join(
            ['- ' + t.github_team_name for t in [self.t0, self.t1]]
        )

        ret, _ = self.testcommand.handle(
            'user view --inspect --username U0G9QF9C6',
            self.u1.slack_id)
        ret = ret['attachments'][1]['text']
        self.assertIn(f'*Membership in:*\n{team_names}', ret)
        self.assertIn(f'*Leading teams:*\n- {self.t1.github_team_name}', ret)

    def test_handle_view_inspect_with_ghusername(self):
        self.u0.name = 'John Peters'
        self.u0.email = '*****@*****.**'
        self.u0.github_id = '328593'
        self.u0.github_username = '******'
        self.t0.add_member(self.u0.github_id)
        self.t1.add_team_lead(self.u0.github_id)
        team_names = '\n'.join(
            ['- ' + t.github_team_name for t in [self.t0, self.t1]]
        )

        ret, _ = self.testcommand.handle(
            'user view --inspect --github some_user',
            self.u1.slack_id)
        ret = ret['attachments'][1]['text']
        self.assertIn(f'*Membership in:*\n{team_names}', ret)
        self.assertIn(f'*Leading teams:*\n- {self.t1.github_team_name}', ret)

    def test_handle_view_inspect_user_no_exists(self):
        ret, _ = self.testcommand.handle(
            'user view --inspect --username UXXXXXXXX',
            self.u1.slack_id)
        self.assertEqual(UserCommand.lookup_error, ret)

    def test_handle_view_inspect_no_ghid(self):
        self.u0.name = 'John Peters'
        self.u0.email = '*****@*****.**'

        ret, _ = self.testcommand.handle(
            'user view --inspect --username U0G9QF9C6',
            self.u1.slack_id)
        ret = ret['attachments'][1]['text']
        self.assertIn(UserCommand.viewinspect_noghid, ret)
Beispiel #22
0
class TestTeamCommand(TestCase):
    def setUp(self):
        self.app = Flask(__name__)
        self.config = mock.MagicMock()
        self.gh = mock.MagicMock()

        self.u0 = User('U123456789')
        self.u1 = User('U234567891')
        self.admin = create_test_admin('Uadmin')
        self.t0 = Team("BRS", "brs", "web")
        self.t1 = Team("OTEAM", "other team", "android")
        self.t2 = Team("LEADS", "leads", "")
        self.t3 = Team("ADMIN", "admin", "")
        self.db = MemoryDB(users=[self.u0, self.u1, self.admin],
                           teams=[self.t0, self.t1, self.t2, self.t3])

        self.sc = mock.MagicMock()
        self.testcommand = TeamCommand(self.config, self.db, self.gh, self.sc)
        self.help_text = self.testcommand.help
        self.maxDiff = None

        self.config.github_team_all = 'all'
        self.config.github_team_leads = 'leads'
        self.config.github_team_admin = 'admin'

    def test_get_help(self):
        subcommands = list(self.testcommand.subparser.choices.keys())
        help_message = self.testcommand.get_help()
        self.assertEqual(len(subcommands), help_message.count("usage"))

    def test_get_subcommand_help(self):
        subcommands = list(self.testcommand.subparser.choices.keys())
        for subcommand in subcommands:
            help_message = self.testcommand.get_help(subcommand=subcommand)
            self.assertEqual(1, help_message.count("usage"))

    def test_get_invalid_subcommand_help(self):
        """Test team command get_help method for invalid subcommands."""
        self.assertEqual(self.testcommand.get_help(),
                         self.testcommand.get_help(subcommand="foo"))

    def test_handle_help(self):
        ret, code = self.testcommand.handle("team help", self.u0.slack_id)
        self.assertEqual(ret, self.testcommand.get_help())
        self.assertEqual(code, 200)

    def test_handle_multiple_subcommands(self):
        """Test handling multiple observed subcommands."""
        ret, code = self.testcommand.handle("team list edit", self.u0.slack_id)
        self.assertEqual(ret, self.testcommand.get_help())
        self.assertEqual(code, 200)

    def test_handle_subcommand_help(self):
        """Test team subcommand help text."""
        subcommands = list(self.testcommand.subparser.choices.keys())
        for subcommand in subcommands:
            for arg in ['--help', '-h', '--invalid argument']:
                command = f"team {subcommand} {arg}"
                ret, code = self.testcommand.handle(command, self.u0.slack_id)
                self.assertEqual(1, ret.count("usage"))
                self.assertEqual(code, 200)

    def test_handle_list(self):
        attachment = [
            self.t0.get_basic_attachment(),
            self.t1.get_basic_attachment(),
            self.t2.get_basic_attachment(),
            self.t3.get_basic_attachment(),
        ]
        with self.app.app_context():
            resp, code = self.testcommand.handle('team list', self.u0.slack_id)
            expect = {'attachments': attachment}
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)

    def test_handle_list_no_teams(self):
        self.db.teams = {}
        self.assertTupleEqual(
            self.testcommand.handle('team list', self.u0.slack_id),
            ('No Teams Exist!', 200))

    def test_handle_view(self):
        with self.app.app_context():
            resp, code = self.testcommand.handle('team view brs',
                                                 self.u0.slack_id)
            expect = {'attachments': [self.t0.get_attachment()]}
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)

    def test_handle_view_lookup_error(self):
        self.assertTupleEqual(
            self.testcommand.handle('team view iesesebrs', self.u0.slack_id),
            (self.testcommand.lookup_error, 200))

    def test_handle_view_noleads(self):
        resp, code = self.testcommand.handle('team view brs', self.u0.slack_id)
        self.assertDictEqual(resp['attachments'][0], self.t0.get_attachment())
        self.assertEqual(code, 200)

    def test_handle_delete_not_admin(self):
        self.assertTupleEqual(
            self.testcommand.handle('team delete brs', self.u0.slack_id),
            (self.testcommand.permission_error, 200))
        self.gh.org_delete_team.assert_not_called()

    def test_handle_delete_lookup_error(self):
        self.assertTupleEqual(
            self.testcommand.handle('team delete brs', 'ioenairsetno'),
            (self.testcommand.lookup_error, 200))
        self.gh.org_delete_team.assert_not_called()

    def test_handle_delete_github_error(self):
        self.t0.github_team_id = '123452'
        self.gh.org_delete_team.side_effect = GithubAPIException('error')
        self.assertTupleEqual(
            self.testcommand.handle('team delete brs', self.admin.slack_id),
            ('Team delete was unsuccessful with '
             'the following error: '
             'error', 200))

    def test_handle_delete(self):
        self.t0.github_team_id = '12345'
        self.u0.github_id = '132432'
        self.u0.permissions_level = Permissions.team_lead
        self.t0.add_team_lead(self.u0.github_id)
        self.assertTupleEqual(
            self.testcommand.handle('team delete brs', self.u0.slack_id),
            ('Team brs deleted', 200))
        self.gh.org_delete_team.assert_called_once_with(int('12345'))

    def test_handle_create(self):
        self.gh.org_create_team.return_value = '8934095'
        inputstring = "team create b-s --name 'B S'"
        outputstring = 'New team created: b-s, name: B S, '
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.admin.slack_id),
            (outputstring, 200))
        inputstring += ' --platform web'
        outputstring += 'platform: web, '
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.admin.slack_id),
            (outputstring, 200))
        self.gh.org_create_team.assert_called()
        self.gh.add_team_member.assert_called_with(self.admin.github_username,
                                                   '8934095')

        inputstring += " --channel 'channelID'"
        outputstring += "added channel, "
        self.sc.get_channel_users.return_value = ['someID', 'otherID']
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.admin.slack_id),
            (outputstring, 200))
        self.sc.get_channel_users.assert_called_once_with('channelID')
        self.gh.add_team_member.assert_called()
        inputstring += f' --lead {self.u0.slack_id}'
        outputstring += 'added lead'
        self.gh.has_team_member.return_value = False
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.admin.slack_id),
            (outputstring, 200))

    def test_handle_create_not_admin(self):
        self.u0.github_username = '******'
        self.u0.github_id = '12'
        self.gh.org_create_team.return_value = 'team_id'
        inputstring = "team create b-s --name 'B S'"
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.u0.slack_id),
            (self.testcommand.permission_error, 200))

    def test_handle_create_not_ghuser(self):
        self.u0.permissions_level = Permissions.admin
        self.gh.org_create_team.return_value = 'team_id'
        s = 'team create someting'
        ret, val = self.testcommand.handle(s, self.u0.slack_id)
        self.assertEqual(val, 200)
        self.assertIn('yet to register', ret)

    def test_handle_create_github_error(self):
        self.gh.org_create_team.return_value = 'team_id'
        inputstring = "team create b-s --name 'B S'"
        self.gh.add_team_member.side_effect = GithubAPIException('error')
        self.assertTupleEqual(
            self.testcommand.handle(inputstring, self.admin.slack_id),
            ('Team creation unsuccessful with the '
             'following error: error', 200))

    def test_handle_create_lookup_error(self):
        inputstring = "team create b-s --name 'B S'"
        self.assertTupleEqual(self.testcommand.handle(inputstring, 'rando'),
                              (self.testcommand.lookup_error, 200))

    def test_handle_add(self):
        self.t0.github_team_id = 'githubid'
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team add brs {self.u0.slack_id}', self.admin.slack_id)
            expect = {
                'attachments': [self.t0.get_attachment()],
                'text': 'Added User to brs'
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertTrue(self.t0.has_member("otherID"))
        self.gh.add_team_member.assert_called_once_with('myuser', 'githubid')

    def test_handle_add_but_forgot_githubid(self):
        self.t0.github_team_id = 'githubid'
        self.gh.add_team_member.side_effect = GithubAPIException('error')
        self.assertTupleEqual(
            self.testcommand.handle(f'team add brs {self.u0.slack_id}',
                                    self.admin.slack_id),
            (TeamCommand.no_ghusername_error, 200))

    def test_handle_add_not_admin(self):
        """Test team command add parser with insufficient permission."""
        self.t0.github_team_id = 'githubid'
        self.assertTupleEqual(
            self.testcommand.handle(f'team add brs {self.u1.slack_id}',
                                    self.u0.slack_id),
            (self.testcommand.permission_error, 200))
        self.gh.add_team_member.assert_not_called()

    def test_handle_add_github_error(self):
        self.t0.github_team_id = 'githubid'
        self.u0.github_id = 'myuser'
        self.gh.add_team_member.side_effect = GithubAPIException('error')
        self.assertTupleEqual(
            self.testcommand.handle(f'team add brs {self.u0.slack_id}',
                                    self.admin.slack_id),
            ('User added unsuccessfully with the'
             ' following error: error', 200))

    def test_handle_add_lookup_error(self):
        self.assertTupleEqual(
            self.testcommand.handle('team add brs ID', 'rando'),
            (self.testcommand.lookup_error, 200))
        self.gh.add_team_member.assert_not_called()

    def test_handle_add_promote(self):
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        self.t2.github_team_id = 'githubid'
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team add leads {self.u0.slack_id}', self.admin.slack_id)
            expect_msg = 'Added User to leads and promoted user to team_lead'
            expect = {
                'attachments': [self.t2.get_attachment()],
                'text': expect_msg
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertTrue(self.t2.has_member("otherID"))
        self.assertEquals(self.u0.permissions_level, Permissions.team_lead)
        self.gh.add_team_member.assert_called_once_with('myuser', 'githubid')

    def test_handle_add_promote_current_admin(self):
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        self.t2.github_team_id = 'githubid'
        # existing admin member should not be "promoted" to lead
        self.u0.permissions_level = Permissions.admin
        self.t3.add_member(self.u0.github_id)
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team add leads {self.u0.slack_id}', self.admin.slack_id)
            expect_msg = 'Added User to leads'
            expect = {
                'attachments': [self.t2.get_attachment()],
                'text': expect_msg
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertTrue(self.t2.has_member("otherID"))
        self.assertEquals(self.u0.permissions_level, Permissions.admin)
        self.gh.add_team_member.assert_called_once_with('myuser', 'githubid')

    def test_handle_remove(self):
        self.u0.github_id = 'githubID'
        self.u0.github_username = '******'
        self.t0.add_member(self.u0.github_id)
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team remove {self.t0.github_team_name} {self.u0.slack_id}',
                self.admin.slack_id)
            expect = {
                'attachments': [self.t0.get_attachment()],
                'text': f'Removed User from {self.t0.github_team_name}'
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.gh.remove_team_member.assert_called_once_with(
            self.u0.github_username, self.t0.github_team_id)

    def test_handle_remove_user_not_in_team(self):
        """Test team command remove parser when user is not in team."""
        self.u0.github_id = 'githubID'
        self.u0.github_username = '******'
        self.gh.has_team_member.return_value = False
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team remove {self.t0.github_team_name} {self.u0.slack_id}',
                    self.admin.slack_id), ("User not in team!", 200))
        self.gh.has_team_member.assert_called_once_with(
            self.u0.github_username, self.t0.github_team_id)
        self.gh.remove_team_member.assert_not_called()

    def test_handle_remove_demote(self):
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        self.t2.add_member(self.u0.github_id)
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team remove leads {self.u0.slack_id}', self.admin.slack_id)
            expect_msg = 'Removed User from leads and demoted user'
            expect = {
                'attachments': [self.t2.get_attachment()],
                'text': expect_msg
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertEquals(self.u0.permissions_level, Permissions.member)
        self.gh.remove_team_member.assert_called_once_with(
            self.u0.github_username, self.t2.github_team_id)

    def test_handle_remove_demote_to_team_lead(self):
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        self.t2.add_member(self.u0.github_id)
        self.t3.add_member(self.u0.github_id)
        with self.app.app_context():
            resp, code = self.testcommand.handle(
                f'team remove admin {self.u0.slack_id}', self.admin.slack_id)
            expect_msg = 'Removed User from admin and demoted user'
            expect = {
                'attachments': [self.t3.get_attachment()],
                'text': expect_msg
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertEquals(self.u0.permissions_level, Permissions.team_lead)
        self.gh.remove_team_member.assert_called_once_with(
            self.u0.github_username, self.t3.github_team_id)

    def test_handle_remove_demote_to_admin(self):
        self.u0.github_username = '******'
        self.u0.github_id = 'otherID'
        self.u0.permissions_level = Permissions.admin
        self.t2.add_member(self.u0.github_id)
        self.t3.add_member(self.u0.github_id)
        with self.app.app_context():
            # Leads member should not be demoted if they are also a admin
            # member
            resp, code = self.testcommand.handle(
                f'team remove leads {self.u0.slack_id}', self.admin.slack_id)
            expect_msg = 'Removed User from leads'
            expect = {
                'attachments': [self.t2.get_attachment()],
                'text': expect_msg
            }
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
        self.assertEquals(self.u0.permissions_level, Permissions.admin)
        self.gh.remove_team_member.assert_called_once_with(
            self.u0.github_username, self.t2.github_team_id)

    def test_handle_remove_not_admin(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team remove {self.t0.github_team_name} {self.u0.slack_id}',
                    self.u1.slack_id),
                (self.testcommand.permission_error, 200))
        self.gh.remove_team_member.assert_not_called()

    def test_handle_remove_lookup_error(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team remove {self.t0.github_team_name} {self.u0.slack_id}',
                    'another.rando'), (self.testcommand.lookup_error, 200))
        self.gh.remove_team_member.assert_not_called()

    def test_handle_remove_github_error(self):
        self.gh.has_team_member.side_effect = GithubAPIException('error')
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team remove {self.t0.github_team_name} {self.u0.slack_id}',
                    self.admin.slack_id),
                ('User removed unsuccessfully with the '
                 'following error: error', 200))
        self.gh.remove_team_member.assert_not_called()

    def test_handle_lead_add(self):
        self.u0.github_id = 'githubID'
        self.u0.github_username = '******'
        with self.app.app_context():
            self.assertFalse(self.t0.has_team_lead(self.u0.github_id))
            self.assertFalse(self.t0.has_member(self.u0.github_id))
            _, code = self.testcommand.handle(
                f'team lead {self.t0.github_team_name} {self.u0.slack_id}',
                self.admin.slack_id)
            self.assertEqual(code, 200)
            self.assertTrue(self.t0.has_team_lead(self.u0.github_id))
            self.assertTrue(self.t0.has_member(self.u0.github_id))
            self.gh.add_team_member.assert_called_once_with(
                self.u0.github_username, self.t0.github_team_id)

    def test_handle_lead_remove(self):
        self.u0.github_id = 'githubID'
        self.u0.github_username = '******'
        self.t0.add_member(self.u0.github_id)
        self.t0.add_team_lead(self.u0.github_id)
        with self.app.app_context():
            self.assertTrue(self.t0.has_team_lead(self.u0.github_id))
            _, code = self.testcommand.handle(
                f'team lead --remove {self.t0.github_team_name}'
                f' {self.u0.slack_id}', self.admin.slack_id)
            self.assertEqual(code, 200)
            self.assertFalse(self.t0.has_team_lead(self.u0.github_id))

    def test_handle_lead_not_admin(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team lead {self.t0.github_team_name} {self.u0.slack_id}',
                    self.u1.slack_id),
                (self.testcommand.permission_error, 200))

    def test_handle_lead_lookup_error(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team lead {self.t0.github_team_name} {self.u0.slack_id}',
                    'rando.rand'), (self.testcommand.lookup_error, 200))

    def test_handle_lead_github_error(self):
        self.gh.add_team_member.side_effect = GithubAPIException('error')
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team lead {self.t0.github_team_name} {self.u0.slack_id}',
                    self.admin.slack_id),
                ('Edit team lead was unsuccessful with the '
                 'following error: error', 200))

    def test_handle_lead_user_error(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team lead --remove {self.t0.github_team_name}'
                    f' {self.u0.slack_id}', self.admin.slack_id),
                ('User not in team!', 200))

    def test_handle_edit(self):
        with self.app.app_context():
            _, code = self.testcommand.handle(
                f'team edit {self.t0.github_team_name}'
                ' --name brS --platform web', self.admin.slack_id)
            self.assertEqual(self.t0.display_name, 'brS')
            self.assertEqual(self.t0.platform, 'web')
            self.assertEqual(code, 200)

    def test_handle_edit_not_admin(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle(
                    f'team edit {self.t0.github_team_name}', self.u0.slack_id),
                (self.testcommand.permission_error, 200))

    def test_handle_edit_lookup_error(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle('team edit rando.team',
                                        self.admin.slack_id),
                (self.testcommand.lookup_error, 200))

    def test_handle_refresh_not_admin(self):
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle('team refresh', self.u0.slack_id),
                (self.testcommand.permission_error, 200))

    def test_handle_refresh_lookup_error(self):
        """Test team command refresh parser with lookup error."""
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle('team refresh', 'rando.randy'),
                (self.testcommand.lookup_error, 200))

    def test_handle_refresh_github_error(self):
        self.gh.org_get_teams.side_effect = GithubAPIException('error')
        with self.app.app_context():
            self.assertTupleEqual(
                self.testcommand.handle('team refresh', self.admin.slack_id),
                ('Refresh teams was unsuccessful with '
                 'the following error: error', 200))

    def test_handle_refresh_changed(self):
        """Test team command refresh parser if team edited in github."""
        team = Team('TeamID', 'TeamName', 'android')
        team_update = Team('TeamID', 'new team name', 'android')
        team_update.add_member(self.admin.github_id)
        team2 = Team('OTEAM', 'other team2', 'ios')

        self.db.teams = {}
        self.db.teams['TeamID'] = team
        self.db.teams['OTEAM'] = team2

        self.gh.org_get_teams.return_value = [team_update, team2]
        attach = team_update.get_attachment()

        status = '1 teams changed, 0 added, 0 deleted. Wonderful.'
        with self.app.app_context():
            resp, code = self.testcommand.handle('team refresh',
                                                 self.admin.slack_id)
            expect = {'attachments': [attach], 'text': status}
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
            self.assertEqual(team, team_update)

    def test_handle_refresh_addition_and_deletion(self):
        """Test team command refresh parser if local differs from github."""
        team = Team('TeamID', 'TeamName', '')
        team2 = Team('OTEAM', 'other team', 'android')

        self.db.teams = {}
        self.db.teams['OTEAM'] = team2

        # In this case, github does not have team2!
        self.gh.org_get_teams.return_value = [team]
        self.gh.org_create_team.return_value = 12345
        attach = team.get_attachment()
        attach2 = team2.get_attachment()

        status = '0 teams changed, 1 added, 1 deleted. Wonderful.'
        with self.app.app_context():
            resp, code = self.testcommand.handle('team refresh',
                                                 self.admin.slack_id)
            expect = {'attachments': [attach2, attach], 'text': status}
            self.assertDictEqual(resp, expect)
            self.assertEqual(code, 200)
            self.assertEqual(len(self.db.teams), 2)
Beispiel #23
0
    def create_helper(self, args: Namespace, user_id: str) -> ResponseTuple:
        """
        Create team and calls GitHub API to create the team in GitHub.

        If ``args.displayname is not None``, will add a display name. If
        ``args.channel is not None``, will add all members of channel in
        which the command was called into the team.
        :param args: Parameters for creating team
        :param user_id: Slack ID of user who called command
        :return: error message if team created unsuccessfully otherwise returns
                 success message
        """
        try:
            command_user = self.facade.retrieve(User, user_id)
            if not check_permissions(command_user, None):
                return self.permission_error, 200
            if not command_user.github_id:
                msg = f"User {command_user.slack_id} has yet to register a"\
                    f" Github username in this system."\
                    f" Register with `/rocket user edit --github username`."
                logging.error(msg)
                return msg, 200
            msg = f"New team created: {args.team_name}, "
            team_id = str(self.gh.org_create_team(args.team_name))
            team = Team(team_id, args.team_name, "")
            if args.displayname is not None:
                msg += f"displayname: {args.displayname}, "
                team.displayname = args.displayname
            if args.platform is not None:
                msg += f"platform: {args.platform}, "
                team.platform = args.platform
            if args.folder is not None:
                msg += f"folder: {args.folder}"
                team.folder = args.folder
            if args.channel is not None:
                msg += "added channel"
                channel_users = self.sc.get_channel_users(
                    args.channel)
                users_no_ghid = []
                for member_id in channel_users:
                    try:
                        member = self.facade.retrieve(User, member_id)
                        if not member.github_username:
                            users_no_ghid.append(member_id)
                            continue
                        self.gh.add_team_member(member.github_username,
                                                team_id)
                        team.add_member(member.github_id)
                    except (LookupError, GithubAPIException):
                        users_no_ghid.append(member_id)

                if users_no_ghid:
                    users_escaped = ' '.join(
                        [f'<@{uid}>' for uid in users_no_ghid])
                    no_gh_reminder =\
                        ' (users who forgot to set Github accounts or forgot '\
                        'to register into database: ' +\
                        users_escaped + ')'
                    msg += no_gh_reminder
                msg += ', '
            else:
                self.gh.add_team_member(command_user.github_username, team_id)
                team.add_member(command_user.github_id)
            if args.lead is not None:
                msg += "added lead"
                lead_user = self.facade.retrieve(User, args.lead)
                team.add_team_lead(lead_user.github_id)
                if not self.gh.has_team_member(lead_user.github_username,
                                               team_id):
                    self.gh.add_team_member(lead_user.github_username, team_id)
            else:
                team.add_team_lead(command_user.github_id)

            self.facade.store(team)
            return msg, 200
        except GithubAPIException as e:
            logging.error(f"Team creation error with {e.data}")
            return f"Team creation unsuccessful with the" \
                   f" following error: {e.data}", 200
        except LookupError:
            logging.error(f"User(uid={user_id}) isn't in database")
            return self.lookup_error, 200
        except SlackAPIError as e:
            logging.error(f"Slack error with {e.error}")
            return f"Team creation unsuccessful with the" \
                   f" following error: {e.error}", 200
Beispiel #24
0
class TestTeamModel(TestCase):
    def setUp(self):
        self.brussel_sprouts = Team('1', 'brussel-sprouts', 'Brussel Sprouts')
        self.brussel_sprouts_copy =\
            Team('1', 'brussel-sprouts', 'Brussel Sprouts')
        self.brussel_trouts = Team('1', 'brussel-trouts', 'Brussel Trouts')

    def test_team_equality(self):
        """Test the Team class method __eq__() and __ne__()."""
        self.assertEqual(self.brussel_sprouts, self.brussel_sprouts_copy)
        self.assertNotEqual(self.brussel_sprouts, self.brussel_trouts)

    def test_valid_team(self):
        """Test the Team static class method is_valid()."""
        self.assertTrue(Team.is_valid(self.brussel_sprouts))
        self.brussel_sprouts.github_team_name = ''
        self.assertFalse(Team.is_valid(self.brussel_sprouts))

    def test_add_member(self):
        """Test the Team class method add_member(github_id)."""
        new_github_id = "U0G9QF9C6"
        self.brussel_sprouts.add_member(new_github_id)
        self.assertIn(new_github_id, self.brussel_sprouts.members)

    def test_discard_member(self):
        """Test the Team class method discard_member(github_id)."""
        new_github_id = "U0G9QF9C6"
        self.brussel_sprouts.add_member(new_github_id)
        self.brussel_sprouts.discard_member(new_github_id)
        self.assertSetEqual(self.brussel_sprouts.members, set())

    def test_is_member(self):
        """Test the Team class method is_member(github_id)."""
        new_github_id = "U0G9QF9C6"
        self.assertFalse(self.brussel_sprouts.has_member(new_github_id))
        self.brussel_sprouts.add_member(new_github_id)
        assert self.brussel_sprouts.has_member(new_github_id)

    def test_add_lead(self):
        """Test the Team class method add_team_lead(github_id)."""
        new_github_id = "U0G9QF9C6"
        self.brussel_sprouts.add_team_lead(new_github_id)
        self.assertIn(new_github_id, self.brussel_sprouts.team_leads)

    def test_is_lead(self):
        """Test the Team class method is_team_lead(github_id)."""
        new_github_id = "U0G9QF9C6"
        self.assertFalse(self.brussel_sprouts.has_team_lead(new_github_id))
        self.brussel_sprouts.add_team_lead(new_github_id)
        self.assertTrue(self.brussel_sprouts.has_team_lead(new_github_id))

    def test_print(self):
        """Test print team class."""
        new_slack_id = "U0G9QF9C6"
        self.brussel_sprouts.add_member(new_slack_id)
        self.brussel_sprouts.add_team_lead(new_slack_id)
        self.brussel_sprouts.platform = "web"
        expected = "{'github_team_id': '1'," \
            " 'github_team_name': 'brussel-sprouts'," \
            " 'display_name': 'Brussel Sprouts'," \
            " 'platform': 'web'," \
            " 'team_leads': {'U0G9QF9C6'}," \
            " 'members': {'U0G9QF9C6'}," \
            " 'folder': ''}"
        self.assertEqual(str(self.brussel_sprouts), expected)
Beispiel #25
0
class TestMembershipHandles(TestCase):
    def setUp(self):
        self.team = 'rocket'
        self.teamid = 395830
        self.member = 'theflatearth'
        self.memberid = 3058493
        self.add_payload = mem_default_payload(self.team, self.teamid,
                                               self.member, self.memberid)
        self.rm_payload = mem_default_payload(self.team, self.teamid,
                                              self.member, self.memberid)
        self.empty_payload = mem_default_payload(self.team, self.teamid,
                                                 self.member, self.memberid)

        self.add_payload['action'] = 'added'
        self.rm_payload['action'] = 'removed'
        self.empty_payload['action'] = ''

        self.u = User('U4058409')
        self.u.github_id = str(self.memberid)
        self.u.github_username = self.member
        self.t = Team(str(self.teamid), self.team, self.team.capitalize())
        self.db = MemoryDB(users=[self.u], teams=[self.t])

        self.gh = mock.Mock()
        self.conf = mock.Mock()
        self.conf.github_team_all = 'all'
        self.webhook_handler = MembershipEventHandler(self.db, self.gh,
                                                      self.conf)

    def test_handle_mem_event_add_member(self):
        rsp, code = self.webhook_handler.handle(self.add_payload)
        self.assertEqual(rsp, f'added slack ID {self.u.slack_id}')
        self.assertEqual(code, 200)

    def test_handle_mem_event_add_member_not_found_in_db(self):
        self.db.users = {}
        rsp, code = self.webhook_handler.handle(self.add_payload)
        self.assertEqual(rsp, f'could not find user {self.member}')
        self.assertEqual(code, 200)

    def test_handle_mem_event_rm_member(self):
        self.t.add_member(self.u.github_id)
        rsp, code = self.webhook_handler.handle(self.rm_payload)
        self.assertFalse(self.t.has_member(self.u.github_id))
        self.assertIn(self.u.slack_id, rsp)
        self.assertEqual(code, 200)

    def test_handle_mem_event_rm_member_missing_from_team(self):
        rsp, code = self.webhook_handler.handle(self.rm_payload)
        self.assertEqual(rsp,
                         f'slack user {self.u.slack_id} not in {self.team}')
        self.assertEqual(code, 200)

    def test_handle_mem_event_rm_member_missing_from_db(self):
        self.db.users = {}
        rsp, code = self.webhook_handler.handle(self.rm_payload)
        self.assertEqual(rsp, f'could not find user {self.memberid}')
        self.assertEqual(code, 200)

    def test_handle_mem_event_rm_multiple_members(self):
        clone = User('Uclones')
        clone.github_id = str(self.memberid)
        clone.github_username = self.member
        self.db.users['Uclones'] = clone
        rsp, code = self.webhook_handler.handle(self.rm_payload)
        self.assertEqual(
            rsp, 'Error: found github ID connected to multiple slack IDs')
        self.assertEqual(code, 200)

    def test_handle_mem_event_invalid_action(self):
        rsp, code = self.webhook_handler.handle(self.empty_payload)
        self.assertEqual(rsp, 'Unsupported action triggered, ignoring.')
        self.assertEqual(code, 202)
Beispiel #26
0
def test_add_member():
    """Test the Team class method add_member(github_id)."""
    team = Team("1", "brussel-sprouts", "Brussel Sprouts")
    new_github_id = "U0G9QF9C6"
    team.add_member(new_github_id)
    assert new_github_id in team.members
Beispiel #27
0
class TestTeamCommandApis(TestCase):
    """Test Case for TeamCommandApi methods."""

    def setUp(self) -> None:
        """Set up the test case environment."""
        self.mock_facade = mock.MagicMock(DBFacade)
        self.mock_github = mock.MagicMock(GithubInterface)
        self.mock_slack = mock.MagicMock(Bot)
        self.testapi = CommandApis(self.mock_facade,
                                   self.mock_github,
                                   self.mock_slack)

        self.regular_user = User("regular")
        self.regular_user.permissions_level = Permissions.member
        self.regular_user.github_id = "reg_gh_id"
        self.regular_user.github_username = "******"
        self.lead_user = User("lead")
        self.lead_user.permissions_level = Permissions.team_lead
        self.lead_user.github_id = "lead_gh_id"
        self.lead_user.github_username = "******"
        self.admin_user = User("admin")
        self.admin_user.permissions_level = Permissions.admin
        self.admin_user.github_id = "admin_gh_id"
        self.admin_user.github_username = "******"

        self.team1 = Team("1", "gh1", "name1")
        self.team2 = Team("2", "gh2", "name2")
        self.team3 = Team("3", "gh3", "name3")
        self.team3_dup = Team("4", "gh3", "name4")

        def mock_facade_retrieve_side_effect(*args, **kwargs):
            """Mock behavior of the retrieve mock facade function."""
            slack_id = args[1]
            if slack_id == self.regular_user.slack_id:
                return self.regular_user
            elif slack_id == self.lead_user.slack_id:
                return self.lead_user
            elif slack_id == self.admin_user.slack_id:
                return self.admin_user
            else:
                raise LookupError

        self.mock_facade.retrieve.side_effect = \
            mock_facade_retrieve_side_effect

        def mock_facade_query_side_effect(*args, **kwargs):
            """Mock behavior of the query mock facade function."""
            query_teams = []
            try:
                params = args[1]
            except IndexError:
                query_teams = [
                    self.team1,
                    self.team2,
                    self.team3,
                    self.team3_dup
                ]
            else:
                assert len(params) == 1, \
                    "Woops, too many parameters for this mock query!"
                attribute, value = params[0]
                assert attribute == "github_team_name", \
                    "Woops, this mock can only handle `github_team_name`!"

                if value == "gh1":
                    query_teams = [self.team1]
                elif value == "gh2":
                    query_teams = [self.team2]
                elif value == "gh3":
                    query_teams = [
                        self.team3,
                        self.team3_dup
                    ]

            return query_teams

        self.mock_facade.query.side_effect = \
            mock_facade_query_side_effect

        # In most cases, store will need to return True for tests
        self.mock_facade.store.return_value = True

    def test_list(self) -> None:
        """Test list team command API."""
        all_teams = self.testapi.team_list()
        self.assertListEqual(all_teams,
                             [
                                 self.team1,
                                 self.team2,
                                 self.team3,
                                 self.team3_dup
                             ])

    def test_view_missing_team(self) -> None:
        """Test view team command API with missing team."""
        self.mock_facade.query.return_value = []
        try:
            self.testapi.team_view("no_team")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_view_multiple_teams(self) -> None:
        """Test view team command API with multiple matching teams."""
        try:
            self.testapi.team_view("gh3")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_view_single_team(self) -> None:
        """Test view team command API with singular matching team."""
        team = self.testapi.team_view("gh1")
        self.assertEqual(team, self.team1)

    def test_create_missing_creator(self) -> None:
        """Test create team command API with missing calling user."""
        try:
            self.testapi.team_create("no_user", "team_name")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_create_non_lead_creator(self) -> None:
        """Test create team command API with non lead calling user."""
        try:
            self.testapi.team_create("regular", "team_name")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_create_gh_team_creation_error(self) -> None:
        """Test create team command API with Github team creation error."""
        self.mock_github.org_create_team.side_effect = GithubAPIException("")
        try:
            self.testapi.team_create("lead", "team_name")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_create_gh_team_add_member_error(self) -> None:
        """Test create team command API with Github team member add error."""
        self.mock_github.add_team_member.side_effect = GithubAPIException("")
        try:
            self.testapi.team_create("lead", "team_name")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_create_success(self) -> None:
        """Test create team command API with successful creation."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create("lead", "team_name")
        self.assertTrue(created)
        stored_team = Team("team_gh_id", "team_name", "")
        stored_team.add_member(self.lead_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_github.add_team_member.assert_called_once_with(
            self.lead_user.github_username, "team_gh_id")
        self.mock_facade.store.assert_called_once_with(stored_team)

    def test_create_with_display_name(self) -> None:
        """Test create team command API with display name."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create("lead",
                                           "team_name",
                                           display_name="display_name")
        self.assertTrue(created)
        stored_team = Team("team_gh_id", "team_name", "display_name")
        stored_team.add_member(self.lead_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_facade.store.assert_called_with(stored_team)

    def test_create_with_platform(self) -> None:
        """Test create team command API with platform."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create("lead",
                                           "team_name",
                                           platform="platform")
        self.assertTrue(created)
        stored_team = Team("team_gh_id", "team_name", "")
        stored_team.platform = "platform"
        stored_team.add_member(self.lead_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_facade.store.assert_called_with(stored_team)

    def test_create_get_channel_members_error(self) -> None:
        """Test create team command API with error getting channel users."""
        self.mock_slack.get_channel_users.side_effect = SlackAPIError("")
        try:
            self.testapi.team_create("lead", "team_name", channel="channel")
        except SlackAPIError:
            pass
        else:
            self.assertTrue(False)

    def test_create_missing_slack_user_from_channel(self) -> None:
        """Test create team command API with missing channel member."""
        self.mock_slack.get_channel_users.return_value = {"missing": None}
        try:
            self.testapi.team_create("lead", "team_name", channel="channel")
        except LookupError:
            self.assertTrue(False)
        else:
            self.assertEqual(self.mock_github.add_team_member.call_count, 0)

    def test_create_add_channel_member_gh_team_error(self) -> None:
        """Test create team command API adding channel member to Github."""
        self.mock_slack.get_channel_users.return_value = \
            {self.regular_user.slack_id: self.regular_user}
        self.mock_facade.bulk_retrieve.return_value = [self.regular_user]

        self.mock_github.add_team_member.side_effect = GithubAPIException("")

        try:
            self.testapi.team_create("lead", "team_name", channel="channel")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_create_add_channel_members(self) -> None:
        """Test create team command API with specified channel."""
        self.mock_slack.get_channel_users.return_value = \
            {self.regular_user.slack_id: self.regular_user}
        self.mock_facade.bulk_retrieve.return_value = [self.regular_user]
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create(
            "lead", "team_name", channel="channel")
        self.assertTrue(created)
        stored_team = Team("team_gh_id", "team_name", "")
        stored_team.add_member(self.regular_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_github.add_team_member.assert_called_with(
            self.regular_user.github_username, "team_gh_id")
        self.mock_facade.store.assert_called_once_with(stored_team)

    def test_create_missing_lead(self) -> None:
        """Test create team command API with missing team lead."""
        try:
            self.testapi.team_create(
                "lead", "team_name", lead_id="missing")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_create_with_lead_check_team_error(self) -> None:
        """Test create team command API with error from checking team."""
        self.mock_github.has_team_member.side_effect = GithubAPIException("")
        try:
            self.testapi.team_create(
                "admin", "team_name", lead_id="lead")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_create_with_lead_not_in_gh_team(self) -> None:
        """Test create team command API with lead not in Github team."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        self.mock_github.has_team_member.return_value = False
        self.testapi.team_create(
            "admin", "team_name", lead_id="lead")
        self.mock_github.add_team_member.assert_called_with(
            self.lead_user.github_username, "team_gh_id")

    def test_create_with_lead_in_gh_team(self) -> None:
        """Test create team command API with lead in Github team."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        self.mock_github.has_team_member.return_value = True
        self.testapi.team_create(
            "admin", "team_name", lead_id="lead")
        self.assertEqual(self.mock_github.add_team_member.call_count, 1)

    def test_create_with_non_lead_lead(self) -> None:
        """Test create team command API with non-lead lead."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        try:
            self.testapi.team_create("admin",
                                     "team_name",
                                     lead_id="regular")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_create_with_lead(self) -> None:
        """Test create team command API with lead."""
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create(
            "admin", "team_name", lead_id="lead")
        self.assertTrue(created)
        stored_team = Team("team_gh_id", "team_name", "")
        stored_team.add_member(self.admin_user.github_id)
        stored_team.add_member(self.lead_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_facade.store.assert_called_once_with(stored_team)

    def test_create_store_fail(self) -> None:
        """Test create team command API with failing store."""
        self.mock_facade.store.return_value = False
        self.mock_github.org_create_team.return_value = "team_gh_id"
        created = self.testapi.team_create("lead", "team_name")
        self.assertFalse(created)
        stored_team = Team("team_gh_id", "team_name", "")
        stored_team.add_member(self.lead_user.github_id)
        stored_team.add_team_lead(self.lead_user.github_id)
        self.mock_github.add_team_member.assert_called_once_with(
            self.lead_user.github_username, "team_gh_id")
        self.mock_facade.store.assert_called_once_with(stored_team)

    def test_add_missing_adder(self) -> None:
        """Test add team command API with missing calling user."""
        try:
            self.testapi.team_add("no_user", "no_user_2", "team_name")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_add_missing_team(self) -> None:
        """Test add team command API with missing team to add to."""
        try:
            self.testapi.team_add("lead", "regular", "missing_team")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_add_non_unique_team(self) -> None:
        """Test add team command API with non unique Github team name."""
        try:
            self.testapi.team_add("lead", "regular", "gh3")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_add_permission_error(self) -> None:
        """Test add team command API with caller without permissions."""
        try:
            self.testapi.team_add("regular", "lead", "gh1")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_add_missing_new_member(self) -> None:
        """Test add team command API with missing user."""
        self.team1.add_team_lead(self.lead_user.github_id)
        try:
            self.testapi.team_add("lead", "no_user", "gh1")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_add_gh_team_add_member_error(self) -> None:
        """Test add team command API w/ error adding to Github team."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.add_team_member.side_effect = GithubAPIException("")
        try:
            self.testapi.team_add("lead", "regular", "gh1")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_add_success(self) -> None:
        """Test add team command API successful execution."""
        self.team1.add_team_lead(self.lead_user.github_id)
        added = self.testapi.team_add("lead", "regular", "gh1")
        self.assertTrue(added)
        self.assertTrue(self.team1.has_member(self.regular_user.github_id))
        self.mock_github.add_team_member.assert_called_once_with(
            self.regular_user.github_username,
            self.team1.github_team_id
        )

    def test_add_fail(self) -> None:
        """Test add team command API when store fails."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_facade.store.return_value = False
        added = self.testapi.team_add("lead", "regular", "gh1")
        self.assertFalse(added)

    def test_remove_missing_remover(self) -> None:
        """Test remove team command API with missing remover."""
        try:
            self.testapi.team_remove("no_user", "gh1", "regular")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_remove_missing_team(self) -> None:
        """Test remove team command API with missing team."""
        try:
            self.testapi.team_remove("lead", "no_team", "regular")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_remove_non_unique_team(self) -> None:
        """Test remove team command API with non unique Github team name."""
        try:
            self.testapi.team_remove("lead", "gh3", "regular")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_remove_permission_error(self) -> None:
        """Test remove team command API with caller without permissions."""
        try:
            self.testapi.team_remove("regular", "gh1", "lead")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_remove_missing_user_to_remove(self) -> None:
        """Test remove team command API with missing member to remove."""
        try:
            self.testapi.team_remove("lead", "gh1", "no_user")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_remove_gh_team_not_has_member(self) -> None:
        """Test remove team command API when member not in Github team."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.has_team_member.return_value = False
        try:
            self.testapi.team_remove("lead", "gh1", "regular")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_remove_gh_team_gh_exception(self) -> None:
        """Test remove team command API when GithubAPIException is raised."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.has_team_member.side_effect = GithubAPIException("")
        try:
            self.testapi.team_remove("lead", "gh1", "regular")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_remove_store_fail(self) -> None:
        """Test remove team command API when db store fails."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.has_team_member.return_value = True
        self.mock_facade.store.return_value = False
        removed = self.testapi.team_remove("lead", "gh1", "regular")
        self.assertFalse(removed)

    def test_remove_success(self) -> None:
        """Test remove team command API successful execution."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.has_team_member.return_value = True
        removed = self.testapi.team_remove("lead", "gh1", "regular")
        self.assertTrue(removed)
        self.assertFalse(self.team1.has_member(self.regular_user.github_id))
        self.mock_github.remove_team_member.assert_called_once_with(
            self.regular_user.github_username,
            self.team1.github_team_id
        )

    def test_remove_lead_success(self) -> None:
        """Test remove team command API on lead successful execution."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.mock_github.has_team_member.return_value = True
        removed = self.testapi.team_remove("lead", "gh1", "lead")
        self.assertTrue(removed)
        self.assertFalse(self.team1.has_member(self.lead_user.github_id))
        self.assertFalse(self.team1.has_team_lead(self.lead_user.github_id))
        self.mock_github.remove_team_member.assert_called_once_with(
            self.lead_user.github_username,
            self.team1.github_team_id
        )

    def test_edit_missing_editor(self) -> None:
        """Test edit team command API with missing calling user."""
        try:
            self.testapi.team_edit("no_user", "gh1")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_edit_missing_team(self) -> None:
        """Test edit team command API with missing team."""
        try:
            self.testapi.team_edit("lead", "no_team")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_edit_non_unique_team(self) -> None:
        """Test edit team command API with non unique Github team name."""
        try:
            self.testapi.team_edit("lead", "gh3")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_edit_permission_error(self) -> None:
        """Test edit team command API with caller without permissions."""
        try:
            self.testapi.team_edit("regular", "gh1")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_edit_store_fail(self) -> None:
        """Test edit team command API when db store fails."""
        self.mock_facade.store.return_value = False
        self.team1.add_team_lead(self.lead_user.github_id)
        edited = self.testapi.team_edit("lead",
                                        "gh1",
                                        display_name="tempname")
        self.assertFalse(edited)

    def test_edit_display_name(self) -> None:
        """Test edit team command API to edit team display name."""
        self.team1.add_team_lead(self.lead_user.github_id)
        edited = self.testapi.team_edit("lead",
                                        "gh1",
                                        display_name="tempname")
        self.assertTrue(edited)
        self.assertEqual("tempname", self.team1.display_name)

    def test_edit_platform(self) -> None:
        """Test edit team command API to edit platform."""
        self.team1.add_team_lead(self.lead_user.github_id)
        edited = self.testapi.team_edit("lead",
                                        "gh1",
                                        platform="tempplat")
        self.assertTrue(edited)
        self.assertEqual("tempplat", self.team1.platform)

    def test_lead_missing_lead_assigner(self) -> None:
        """Test lead team command API with missing calling user."""
        try:
            self.testapi.team_lead("no_user", "lead", "gh1")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_missing_team(self) -> None:
        """Test lead team command API with missing team."""
        try:
            self.testapi.team_lead("lead", "regular", "no_team")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_non_unique_team(self) -> None:
        """Test lead team command API with non unique Github team name."""
        try:
            self.testapi.team_lead("lead", "regular", "gh3")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_permission_error(self) -> None:
        """Test lead team command API with caller without permissions."""
        try:
            self.testapi.team_lead("regular", "lead", "gh1")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_missing_intended_lead(self) -> None:
        """Test lead team command API with missing intended lead."""
        self.team1.add_team_lead(self.lead_user.github_id)
        try:
            self.testapi.team_lead("lead", "no_user", "gh1")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_gh_team_add_member_error(self) -> None:
        """Test lead team command API with Github team member add error."""
        self.mock_github.add_team_member.side_effect = GithubAPIException("")
        self.team1.add_team_lead(self.lead_user.github_id)
        try:
            self.testapi.team_lead("lead", "regular", "gh1")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_lead_store_fail(self) -> None:
        """Test lead command API failing store."""
        self.mock_facade.store.return_value = False
        self.team1.add_team_lead(self.lead_user.github_id)
        lead_assigned = self.testapi.team_lead("lead", "regular", "gh1")
        self.assertFalse(lead_assigned)

    def test_lead_successful(self) -> None:
        """Test lead team command API setting team lead successfully."""
        self.team1.add_team_lead(self.lead_user.github_id)
        lead_assigned = self.testapi.team_lead("lead", "regular", "gh1")
        self.mock_github.add_team_member.assert_called_once_with(
            self.regular_user.github_username,
            self.team1.github_team_id
        )
        self.assertTrue(lead_assigned)
        self.assertTrue(self.team1.has_member(self.regular_user.github_id))
        self.assertTrue(self.team1.has_team_lead(self.regular_user.github_id))

    def test_lead_remove_not_in_team(self) -> None:
        """Test lead team command API remove a member not in a team."""
        self.team1.add_team_lead(self.lead_user.github_id)
        try:
            self.testapi.team_lead("lead", "regular", "gh1", remove=True)
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_remove_not_lead_of_team(self) -> None:
        """Test lead team command API remove a member not lead of team."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.team1.add_member(self.regular_user.github_id)
        try:
            self.testapi.team_lead("lead", "regular", "gh1", remove=True)
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_lead_remove_store_fail(self) -> None:
        """Test lead command API removal failing store."""
        self.mock_facade.store.return_value = False
        self.team1.add_team_lead(self.lead_user.github_id)
        self.team1.add_member(self.regular_user.github_id)
        self.team1.add_team_lead(self.regular_user.github_id)
        lead_removed = self.testapi.team_lead("lead", "regular", "gh1",
                                              remove=True)
        self.assertFalse(lead_removed)

    def test_lead_remove_successful(self) -> None:
        """Test lead team command API successfully remove lead from team."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.team1.add_member(self.regular_user.github_id)
        self.team1.add_team_lead(self.regular_user.github_id)
        lead_removed = self.testapi.team_lead("lead", "regular", "gh1",
                                              remove=True)
        self.assertTrue(lead_removed)
        self.assertTrue(self.team1.has_member(self.regular_user.github_id))
        self.assertFalse(self.team1.has_team_lead(self.regular_user.github_id))

    def test_delete_missing_deleter(self) -> None:
        """Test delete team command API with missing calling user."""
        try:
            self.testapi.team_delete("no_user", "gh1")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_delete_missing_team(self) -> None:
        """Test delete team command API with missing team."""
        try:
            self.testapi.team_delete("lead", "no_team")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_delete_non_unique_team(self) -> None:
        """Test delete team command API with non unique Github team name."""
        try:
            self.testapi.team_delete("lead", "gh3")
        except RuntimeError:
            pass
        else:
            self.assertTrue(False)

    def test_delete_permission_error(self) -> None:
        """Test delete team command API with caller without permissions."""
        try:
            self.testapi.team_delete("regular", "gh1")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_delete_gh_team_delete_team_error(self) -> None:
        """Test delete team command API with Github team delete error."""
        self.mock_github.org_delete_team.side_effect = GithubAPIException("")
        self.team1.add_team_lead(self.lead_user.github_id)
        try:
            self.testapi.team_delete("lead", "gh1")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_delete_successful(self) -> None:
        """Test delete team command API deleting team successfully."""
        self.team1.add_team_lead(self.lead_user.github_id)
        self.testapi.team_delete("lead", "gh1")
        self.mock_github.org_delete_team.assert_called_once_with(
            int(self.team1.github_team_id))
        self.mock_facade.delete.assert_called_once_with(
            Team,
            self.team1.github_team_id)

    def test_refresh_missing_refresher(self) -> None:
        """Test refresh team command API with missing calling user."""
        try:
            self.testapi.team_refresh("no_user")
        except LookupError:
            pass
        else:
            self.assertTrue(False)

    def test_refresh_permission_error(self) -> None:
        """Test refresh team command API with caller without permissions."""
        try:
            self.testapi.team_refresh("regular")
        except PermissionError:
            pass
        else:
            self.assertTrue(False)

    def test_refresh_gh_get_teams_error(self) -> None:
        """Test refresh team command API with Github error getting teams."""
        self.mock_github.org_get_teams.side_effect = GithubAPIException("")
        try:
            self.testapi.team_refresh("admin")
        except GithubAPIException:
            pass
        else:
            self.assertTrue(False)

    def test_refresh_github_deleted(self) -> None:
        """Test refresh team command API with teams removed from Github."""
        self.mock_github.org_get_teams.return_value = [
            self.team2,
            self.team3,
            self.team3_dup
        ]
        refreshed = self.testapi.team_refresh("admin")
        self.assertTrue(refreshed)
        self.mock_facade.delete.assert_called_once_with(
            Team, self.team1.github_team_id)

    def test_refresh_github_added_failed_store(self) -> None:
        """Test refresh team command API unable to store new Github teams."""
        team5 = Team("5", "gh5", "name5")
        self.mock_github.org_get_teams.return_value = [
            self.team1,
            self.team2,
            self.team3,
            self.team3_dup,
            team5
        ]
        self.mock_facade.store.return_value = False
        refreshed = self.testapi.team_refresh("admin")
        self.assertFalse(refreshed)
        self.mock_facade.store.assert_called_once_with(team5)

    def test_refresh_github_added_success(self) -> None:
        """Test refresh team command API storing new Github teams."""
        team5 = Team("5", "gh5", "name5")
        self.mock_github.org_get_teams.return_value = [
            self.team1,
            self.team2,
            self.team3,
            self.team3_dup,
            team5
        ]
        refreshed = self.testapi.team_refresh("admin")
        self.assertTrue(refreshed)
        self.mock_facade.store.assert_called_once_with(team5)

    def test_refresh_github_changed_failed_store(self) -> None:
        """Test refresh team command API unable to edit teams."""
        new_team1 = Team("1", "newgh1", "name1")
        new_team1.add_member(self.regular_user.github_id)
        self.mock_github.org_get_teams.return_value = [
            new_team1,
            self.team2,
            self.team3,
            self.team3_dup,
        ]
        self.mock_facade.store.return_value = False
        refreshed = self.testapi.team_refresh("admin")
        self.assertFalse(refreshed)
        self.team1.github_team_name = "newgh1"
        self.team1.add_member(self.regular_user.github_id)
        self.mock_facade.store.assert_called_once_with(self.team1)

    def test_refresh_github_changed_success(self) -> None:
        """Test refresh team command API to edit teams."""
        new_team1 = Team("1", "newgh1", "name1")
        new_team1.add_member(self.regular_user.github_id)
        self.mock_github.org_get_teams.return_value = [
            new_team1,
            self.team2,
            self.team3,
            self.team3_dup,
        ]
        refreshed = self.testapi.team_refresh("admin")
        self.assertTrue(refreshed)
        self.team1.github_team_name = "newgh1"
        self.team1.add_member(self.regular_user.github_id)
        self.mock_facade.store.assert_called_once_with(self.team1)
Beispiel #28
0
    def create_helper(self, param_list, user_id) -> ResponseTuple:
        """
        Create team and calls GitHub API to create the team in GitHub.

        If ``param_list[name] is not None``, will add a display name. If
        ``param_list[channel] is not None``, will add all members of channel in
        which the command was called into the team.

        :param param_list: List of parameters for creating team
        :param user_id: Slack ID of user who called command
        :return: error message if team created unsuccessfully otherwise returns
                 success message
        """
        try:
            command_user = self.facade.retrieve(User, user_id)
            if not check_permissions(command_user, None):
                return self.permission_error, 200
            if not command_user.github_id:
                msg = f"User {command_user.slack_id} has yet to register a"\
                    f" Github username in this system."\
                    f" Register with `/rocket user edit --github username`."
                logging.error(msg)
                return msg, 200
            msg = f"New team created: {param_list['team_name']}, "
            team_id = str(self.gh.org_create_team(param_list['team_name']))
            team = Team(team_id, param_list['team_name'], "")
            if param_list["name"] is not None:
                msg += f"name: {param_list['name']}, "
                team.display_name = param_list['name']
            if param_list["platform"] is not None:
                msg += f"platform: {param_list['platform']}, "
                team.platform = param_list['platform']
            if param_list["folder"] is not None:
                msg += f"folder: {param_list['folder']}"
                team.folder = param_list['folder']
            if param_list["channel"] is not None:
                msg += "added channel, "
                for member_id in self.sc.get_channel_users(
                        param_list["channel"]):
                    try:
                        member = self.facade.retrieve(User, member_id)
                        self.gh.add_team_member(member.github_username,
                                                team_id)
                        team.add_member(member.github_id)
                    except LookupError:
                        pass
            else:
                self.gh.add_team_member(command_user.github_username, team_id)
                team.add_member(command_user.github_id)
            if param_list["lead"] is not None:
                msg += "added lead"
                lead_user = self.facade.retrieve(User, param_list["lead"])
                team.add_team_lead(lead_user.github_id)
                if not self.gh.has_team_member(lead_user.github_username,
                                               team_id):
                    self.gh.add_team_member(lead_user.github_username, team_id)
            else:
                team.add_team_lead(command_user.github_id)

            self.facade.store(team)
            return msg, 200
        except GithubAPIException as e:
            logging.error(f"Team creation error with {e.data}")
            return f"Team creation unsuccessful with the" \
                   f" following error: {e.data}", 200
        except LookupError:
            logging.error(f"User(uid={user_id}) isn't in database")
            return self.lookup_error, 200
        except SlackAPIError as e:
            logging.error(f"Slack error with {e.error}")
            return f"Team creation unsuccessful with the" \
                   f" following error: {e.error}", 200
Beispiel #29
0
    def team_create(self,
                    caller_id: str,
                    gh_team_name: str,
                    display_name: str = None,
                    platform: str = None,
                    channel: str = None,
                    lead_id: str = None) -> bool:
        """
        Create a team both in the Rocket database and Github organization.

        :param caller_id: Slack ID of the user who is calling the API
        :param gh_team_name: desired team name to give the team on Github
        :param display_name: display name to give the team when displayed
                             in various places
        :param platform: main platform this team's projects are based on
        :param channel: name of the Slack channel whose channel members
                        are to be added to the team - its members will be
                        added to the team in the Rocket database and added
                        to the Github team as well
        :param lead_id: Slack ID of the user who will be made the lead of
                        this team
        :raises: LookupError if the calling user or tech lead cannot be found
                 in the database
        :raises: PermissionError if the calling user has insufficient
                 permissions to create a team, or if the specified user with
                 lead_id does not have the permission to be a lead
        :raises: SlackAPIError if a channel name is provided by an error
                 is encountered retrieving the members of that channel
        :raises: GithubAPIException if an error occurs on team creation or
                 Github team member addition
        :raises: Exception for any other generic error
        :return: True if the team creation was successful, False otherwise
        """
        logging.info("Team create command API called")
        command_user = self._db_facade.retrieve(User, caller_id)
        logging.debug(f"Calling user: {command_user.__str__()}")

        if not check_permissions(command_user, None):
            msg = f"Calling user with Slack ID {caller_id} has permission" \
                f" level {str(command_user.permissions_level)}, " \
                "insufficient for creating a team!"
            logging.error(msg)
            raise PermissionError(msg)

        if not command_user.github_id:
            msg = f"User {command_user.slack_id} has yet to register a"\
                f" Github username in this system."\
                f" Register with `/rocket user edit --github username`."
            logging.error(msg)
            raise Exception(msg)

        gh_team_id = str(self._gh_interface.org_create_team(gh_team_name))
        logging.debug(f"Github team {gh_team_name} created with "
                      f"Github team ID {gh_team_id}")
        team = Team(gh_team_id, gh_team_name, "")

        if display_name is not None:
            logging.debug(f"Attaching display name {display_name} "
                          f"to {gh_team_name}")
            team.display_name = display_name

        if platform is not None:
            logging.debug(f"Attaching platform {platform} to {gh_team_name}")
            team.platform = platform

        if channel is not None:
            logging.debug(f"Adding channel members of #{channel} "
                          f"to {gh_team_name}")
            try:
                channel_member_ids = \
                    self._slack_client.get_channel_users(channel)
                logging.debug(f"Member IDs of members found in #{channel}: "
                              f"{channel_member_ids}")
            except SlackAPIError as e:
                msg = f"Channel member query on channel #{channel} failed: " \
                    f"{e.error}"
                logging.error(msg)
                raise SlackAPIError(msg)

            channel_members = \
                self._db_facade.bulk_retrieve(User,
                                              list(channel_member_ids.keys()))

            if len(channel_members) is not len(channel_member_ids):
                retrieved_members_ids = [
                    member.slack_id for member in channel_members
                ]
                unaccounted_member_ids = [
                    member_id for member_id in channel_member_ids
                    if member_id not in retrieved_members_ids
                ]
                logging.warning("Users not found for following Slack IDs: "
                                f"{unaccounted_member_ids}")

            for member in channel_members:
                self._gh_interface.add_team_member(member.github_username,
                                                   gh_team_id)
                team.add_member(member.github_id)
                logging.debug(f"Member with ID {member.slack_id} added "
                              f"to {gh_team_name}")
        else:
            self._gh_interface.add_team_member(command_user.github_username,
                                               gh_team_id)
            team.add_member(command_user.github_id)
            logging.debug(f"Calling user with ID {command_user.slack_id} "
                          f"added to {gh_team_name}")

        if lead_id is not None:
            lead = self._db_facade.retrieve(User, lead_id)

            if check_permissions(lead, None):
                lead_in_team = self._gh_interface.has_team_member(
                    lead.github_username, gh_team_id)
                if not lead_in_team:
                    self._gh_interface.add_team_member(lead.github_username,
                                                       gh_team_id)

                team.add_member(lead.github_id)
                team.add_team_lead(lead.github_id)
                logging.debug(f"User with ID {lead_id} set as tech lead of "
                              f"{gh_team_name}")
            else:
                msg = f"User specified with lead ID {lead_id} has" \
                    f" permission level {str(lead.permissions_level)}, " \
                    "insufficient to lead a team!"
                logging.error(msg)
                raise PermissionError(msg)
        else:
            team.add_team_lead(command_user.github_id)
            logging.debug(f"Calling user with ID {command_user.github_id} set"
                          f" as tech lead of {gh_team_name}")

        created = self._db_facade.store(team)
        return created
Beispiel #30
0
class TestExportCommand(TestCase):
    def setUp(self):
        self.u0 = User('U0G9QF9C6')
        self.u0.email = '*****@*****.**'
        self.u0.github_id = '305834954'

        self.u1 = User('Utheomadude')
        self.u1.email = '*****@*****.**'
        self.u1.github_id = '349850564'

        self.admin = create_test_admin('Uadmin')

        self.lead = User('Ualley')
        self.lead.email = '*****@*****.**'
        self.lead.github_id = '2384858'
        self.lead.permissions_level = Permissions.team_lead

        self.t0 = Team('305849', 'butter-batter', 'Butter Batters')
        self.t0.add_member(self.u0.github_id)
        self.t0.add_member(self.lead.github_id)
        self.t0.add_team_lead(self.lead.github_id)

        self.t1 = Team('320484', 'aqua-scepter', 'Aqua Scepter')
        self.t1.add_member(self.u1.github_id)

        self.t2 = Team('22234', 'tiger-dear', 'Shakespearean')

        self.db = MemoryDB(users=[self.u0, self.u1, self.admin, self.lead],
                           teams=[self.t0, self.t1, self.t2])

        self.cmd = ExportCommand(self.db)

    def test_get_help_from_bad_syntax(self):
        resp, _ = self.cmd.handle('export emails hanrse', self.admin.slack_id)
        self.assertEqual(resp, self.cmd.get_help('emails'))

    def test_get_help_bad_syntax_all(self):
        resp, _ = self.cmd.handle('export blah', self.admin.slack_id)
        self.assertEqual(resp, self.cmd.get_help())

    def test_lookup_error_user_calling(self):
        resp, _ = self.cmd.handle('export emails', 'blah blah')
        self.assertEqual(resp, ExportCommand.lookup_error)

    def test_get_all_emails(self):
        resp, _ = self.cmd.handle('export emails', self.admin.slack_id)
        self.assertIn(self.u0.email, resp)
        self.assertIn(self.u1.email, resp)
        self.assertIn(self.admin.email, resp)
        self.assertIn(self.lead.email, resp)
        self.assertIn(ExportCommand.no_emails_missing_msg, resp)

    def test_lead_get_all_emails(self):
        resp, _ = self.cmd.handle('export emails', self.lead.slack_id)
        self.assertIn(self.u0.email, resp)
        self.assertIn(self.u1.email, resp)
        self.assertIn(self.admin.email, resp)
        self.assertIn(self.lead.email, resp)
        self.assertIn(ExportCommand.no_emails_missing_msg, resp)

    def test_member_get_all_emails(self):
        resp, _ = self.cmd.handle('export emails', self.u0.slack_id)
        self.assertIn(ExportCommand.permission_error, resp)

    def test_get_team_emails(self):
        resp, _ = self.cmd.handle(
            f'export emails --team {self.t0.github_team_name}',
            self.admin.slack_id)
        self.assertIn(self.u0.email, resp)
        self.assertIn(self.lead.email, resp)
        self.assertIn(ExportCommand.no_emails_missing_msg, resp)

    def test_lead_get_team_emails(self):
        resp, _ = self.cmd.handle(
            f'export emails --team {self.t0.github_team_name}',
            self.lead.slack_id)
        self.assertIn(self.u0.email, resp)
        self.assertIn(self.lead.email, resp)
        self.assertIn(ExportCommand.no_emails_missing_msg, resp)

    def test_member_get_team_emails(self):
        resp, _ = self.cmd.handle(
            f'export emails --team {self.t0.github_team_name}',
            self.u1.slack_id)
        self.assertIn(ExportCommand.permission_error, resp)

    def test_lead_get_team_emails_one_missing(self):
        self.u0.email = ''
        resp, _ = self.cmd.handle(
            f'export emails --team {self.t0.github_team_name}',
            self.lead.slack_id)
        self.assertIn(self.u0.slack_id, resp)
        self.assertIn(self.lead.email, resp)
        self.assertIn('Members who don\'t have an email:', resp)
        self.assertNotIn(ExportCommand.no_emails_missing_msg, resp)

    def test_get_emails_no_users_in_team(self):
        resp, _ = self.cmd.handle(
            f'export emails --team {self.t2.github_team_name}',
            self.admin.slack_id)
        self.assertEqual(resp, ExportCommand.no_user_msg)

    def test_get_all_emails_char_limit_reached(self):
        old_lim = ExportCommand.MAX_CHAR_LIMIT
        ExportCommand.MAX_CHAR_LIMIT = 30
        resp, _ = self.cmd.handle('export emails', self.admin.slack_id)
        self.assertIn(ExportCommand.char_limit_exceed_msg, resp)

        # reset things because python doesn't do that
        ExportCommand.MAX_CHAR_LIMIT = old_lim

    def test_get_all_emails_one_missing_char_limit_reached(self):
        old_lim = ExportCommand.MAX_CHAR_LIMIT
        ExportCommand.MAX_CHAR_LIMIT = 30
        self.u0.email = ''
        resp, _ = self.cmd.handle('export emails', self.lead.slack_id)
        self.assertIn(self.u0.slack_id, resp)
        self.assertIn('Members who don\'t have an email:', resp)
        self.assertNotIn(ExportCommand.no_emails_missing_msg, resp)

        # reset things because python doesn't do that
        ExportCommand.MAX_CHAR_LIMIT = old_lim