import pytest from uuid import uuid4 from atst.domain.exceptions import NotFoundError, UnauthorizedError from atst.domain.portfolios import ( Portfolios, PortfolioError, PortfolioDeletionApplicationsExistError, ) from atst.domain.portfolio_roles import PortfolioRoles from atst.domain.applications import Applications from atst.domain.application_roles import ApplicationRoles from atst.domain.environments import Environments from atst.domain.permission_sets import PermissionSets, PORTFOLIO_PERMISSION_SETS from atst.models.application_role import Status as ApplicationRoleStatus from atst.models.portfolio_role import Status as PortfolioRoleStatus from atst.models import FSMStates from tests.factories import ( ApplicationFactory, ApplicationRoleFactory, UserFactory, PortfolioRoleFactory, PortfolioFactory, PortfolioStateMachineFactory, get_all_portfolio_permission_sets, ) @pytest.fixture(scope="function") def portfolio_owner(): return UserFactory.create() @pytest.fixture(scope="function") def portfolio(portfolio_owner): portfolio = PortfolioFactory.create(owner=portfolio_owner) return portfolio def test_can_create_portfolio(): portfolio = PortfolioFactory.create(name="frugal-whale") assert portfolio.name == "frugal-whale" def test_get_nonexistent_portfolio_raises(): with pytest.raises(NotFoundError): Portfolios.get(UserFactory.build(), uuid4()) def test_creating_portfolio_adds_owner(portfolio, portfolio_owner): assert portfolio.roles[0].user == portfolio_owner def test_portfolio_has_timestamps(portfolio): assert portfolio.time_created == portfolio.time_updated def test_update_portfolio_role_role(portfolio, portfolio_owner): user_data = { "first_name": "New", "last_name": "User", "email": "new.user@mail.com", "portfolio_role": "developer", "dod_id": "1234567890", } PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush" member = PortfolioRoleFactory.create(portfolio=portfolio) permission_sets = [PermissionSets.EDIT_PORTFOLIO_FUNDING] updated_member = Portfolios.update_member(member, permission_sets=permission_sets) assert updated_member.portfolio == portfolio def test_scoped_portfolio_for_admin_missing_view_apps_perms(portfolio_owner, portfolio): Applications.create( portfolio.owner, portfolio, "My Application 2", "My application 2", ["dev", "staging", "prod"], ) restricted_admin = UserFactory.create() PortfolioRoleFactory.create( portfolio=portfolio, user=restricted_admin, permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO)], ) scoped_portfolio = Portfolios.get(restricted_admin, portfolio.id) assert scoped_portfolio.id == portfolio.id assert len(portfolio.applications) == 1 assert len(scoped_portfolio.applications) == 0 def test_scoped_portfolio_returns_all_applications_for_portfolio_admin( portfolio, portfolio_owner ): for _ in range(5): Applications.create( portfolio.owner, portfolio, "My Application", "My application", ["dev", "staging", "prod"], ) admin = UserFactory.create() perm_sets = get_all_portfolio_permission_sets() PortfolioRoleFactory.create( user=admin, portfolio=portfolio, permission_sets=perm_sets ) scoped_portfolio = Portfolios.get(admin, portfolio.id) assert len(scoped_portfolio.applications) == 5 assert len(scoped_portfolio.applications[0].environments) == 3 def test_scoped_portfolio_returns_all_applications_for_portfolio_owner( portfolio, portfolio_owner ): for _ in range(5): Applications.create( portfolio.owner, portfolio, "My Application", "My application", ["dev", "staging", "prod"], ) scoped_portfolio = Portfolios.get(portfolio_owner, portfolio.id) assert len(scoped_portfolio.applications) == 5 assert len(scoped_portfolio.applications[0].environments) == 3 def test_for_user_returns_portfolios_for_applications_user_invited_to(): bob = UserFactory.create() portfolio = PortfolioFactory.create() application = ApplicationFactory.create(portfolio=portfolio) ApplicationRoleFactory.create( application=application, user=bob, status=ApplicationRoleStatus.ACTIVE ) assert portfolio in Portfolios.for_user(user=bob) def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner): bob = UserFactory.create() PortfolioRoleFactory.create( user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE ) PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 1 def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner): bob = UserFactory.create() Portfolios.add_member(portfolio, bob) PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 0 def test_for_user_returns_all_portfolios_for_ccpo(portfolio, portfolio_owner): sam = UserFactory.create_ccpo() PortfolioFactory.create() sams_portfolios = Portfolios.for_user(sam) assert len(sams_portfolios) == 2 def test_can_create_portfolios_with_matching_names(): portfolio_name = "Great Portfolio" PortfolioFactory.create(name=portfolio_name) PortfolioFactory.create(name=portfolio_name) def test_disabled_members_dont_show_up(session): portfolio = PortfolioFactory.create() PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioRoleFactory.create( portfolio=portfolio, status=PortfolioRoleStatus.DISABLED ) # should only return portfolio owner and ACTIVE member assert len(portfolio.members) == 2 def test_does_not_count_disabled_members(session): portfolio = PortfolioFactory.create() PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioRoleFactory.create(portfolio=portfolio) PortfolioRoleFactory.create( portfolio=portfolio, status=PortfolioRoleStatus.DISABLED ) assert portfolio.user_count == 3 def test_invite(): portfolio = PortfolioFactory.create() inviter = UserFactory.create() member_data = UserFactory.dictionary() invitation = Portfolios.invite(portfolio, inviter, {"user_data": member_data}) assert invitation.role assert invitation.role.portfolio == portfolio assert invitation.role.user is None assert invitation.dod_id == member_data["dod_id"] def test_delete_success(): portfolio = PortfolioFactory.create() assert not portfolio.deleted Portfolios.delete(portfolio=portfolio) assert portfolio.deleted def test_delete_failure_with_applications(): portfolio = PortfolioFactory.create() application = ApplicationFactory.create(portfolio=portfolio) assert not portfolio.deleted with pytest.raises(PortfolioDeletionApplicationsExistError): Portfolios.delete(portfolio=portfolio) assert not portfolio.deleted def test_for_user_does_not_include_deleted_portfolios(): user = UserFactory.create() PortfolioFactory.create(owner=user, deleted=True) assert len(Portfolios.for_user(user)) == 0 def test_for_user_does_not_include_deleted_application_roles(): user1 = UserFactory.create() user2 = UserFactory.create() portfolio = PortfolioFactory.create() app = ApplicationFactory.create(portfolio=portfolio) ApplicationRoleFactory.create( status=ApplicationRoleStatus.ACTIVE, user=user1, application=app ) assert len(Portfolios.for_user(user1)) == 1 ApplicationRoleFactory.create( status=ApplicationRoleStatus.ACTIVE, user=user2, application=app, deleted=True ) assert len(Portfolios.for_user(user2)) == 0 def test_create_state_machine(portfolio): fsm = Portfolios.create_state_machine(portfolio) assert fsm def test_get_portfolios_pending_provisioning(session): for x in range(5): portfolio = PortfolioFactory.create() sm = PortfolioStateMachineFactory.create(portfolio=portfolio) if x == 2: sm.state = FSMStates.COMPLETED assert len(Portfolios.get_portfolios_pending_provisioning()) == 4