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
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()
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
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)
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))
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
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_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)
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_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_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'}}"
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_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
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)
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
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
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)
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])
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.')
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)
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)
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
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)
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)
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
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)
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
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
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