Merge branch 'staging' into azure-custom-integration

This commit is contained in:
tomdds
2020-01-24 11:16:11 -05:00
committed by GitHub
192 changed files with 3127 additions and 3262 deletions

29
tests/domain/test_auth.py Normal file
View File

@@ -0,0 +1,29 @@
from flask import make_response, session
from atst.domain.auth import logout
def _write_session(app):
response = make_response("")
app.session_interface.save_session(app, session, response)
return session
def test_logout_destroys_session(app):
session = _write_session(app)
key = app.config.get("SESSION_KEY_PREFIX") + session.sid
assert app.redis.get(key)
logout()
assert app.redis.get(key) is None
def test_logout_logs_dod_id_for_current_user(monkeypatch, mock_logger):
dod_id = "3434343434"
monkeypatch.setattr("atst.domain.auth._current_dod_id", lambda: dod_id)
logout()
assert dod_id in mock_logger.messages[-1]
def test_logout_logs_message_for_unathenticated_user(mock_logger):
logout()
assert "unauthenticated" in mock_logger.messages[-1]

View File

@@ -37,6 +37,10 @@ def random_task_order_number():
return "".join(random.choices(string.digits, k=10))
def random_clin_number():
return "".join(random.choices(string.digits, k=4))
def random_past_date(year_min=1, year_max=5):
return _random_date(year_min, year_max, operator.sub)
@@ -327,7 +331,7 @@ class CLINFactory(Base):
model = CLIN
task_order = factory.SubFactory(TaskOrderFactory)
number = factory.LazyFunction(random_task_order_number)
number = factory.LazyFunction(random_clin_number)
start_date = datetime.date.today()
end_date = factory.LazyFunction(random_future_date)
total_amount = factory.LazyFunction(lambda *args: random.randint(50000, 999999))

View File

@@ -1,13 +1,12 @@
from wtforms.validators import ValidationError
import uuid
from atst.domain.permission_sets import PermissionSets
from atst.forms.data import ENV_ROLES, ENV_ROLE_NO_ACCESS as NO_ACCESS
from atst.forms.data import ENV_ROLES
from atst.forms.application_member import *
def test_environment_form():
form_data = {
"environment_id": 123,
"environment_id": str(uuid.uuid4()),
"environment_name": "testing",
"role": ENV_ROLES[0][0],
"disabled": True,
@@ -17,12 +16,13 @@ def test_environment_form():
def test_environment_form_default_no_access():
form_data = {"environment_id": 123, "environment_name": "testing"}
env_id = str(uuid.uuid4())
form_data = {"environment_id": env_id, "environment_name": "testing"}
form = EnvironmentForm(data=form_data)
assert form.validate()
assert form.data == {
"environment_id": 123,
"environment_id": env_id,
"environment_name": "testing",
"role": None,
"disabled": False,
@@ -31,7 +31,7 @@ def test_environment_form_default_no_access():
def test_environment_form_invalid():
form_data = {
"environment_id": 123,
"environment_id": str(uuid.uuid4()),
"environment_name": "testing",
"role": "not a real choice",
}
@@ -43,10 +43,8 @@ def test_update_member_form():
form_data = {
"perms_team_mgmt": True,
"perms_env_mgmt": False,
"perms_del_env": False,
}
form = UpdateMemberForm(data=form_data)
assert form.validate()
assert form.perms_team_mgmt.data
assert not form.perms_env_mgmt.data
assert not form.perms_del_env.data

View File

@@ -4,16 +4,16 @@ import pytest
from atst.forms.validators import *
class TestIsNumber:
class TestNumber:
@pytest.mark.parametrize("valid", ["0", "12", "-12"])
def test_IsNumber_accepts_integers(self, valid, dummy_form, dummy_field):
validator = IsNumber()
def test_Number_accepts_integers(self, valid, dummy_form, dummy_field):
validator = Number()
dummy_field.data = valid
validator(dummy_form, dummy_field)
@pytest.mark.parametrize("invalid", ["12.1", "two", "", None])
def test_IsNumber_rejects_anything_else(self, invalid, dummy_form, dummy_field):
validator = IsNumber()
@pytest.mark.parametrize("invalid", ["12.1", "two"])
def test_Number_rejects_anything_else(self, invalid, dummy_form, dummy_field):
validator = Number()
dummy_field.data = invalid
with pytest.raises(ValidationError):
validator(dummy_form, dummy_field)

View File

@@ -160,7 +160,6 @@ def test_post_new_member(monkeypatch, client, user_session, session):
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
},
)
@@ -208,7 +207,6 @@ def test_post_update_member(client, user_session):
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
},
)

View File

@@ -206,7 +206,6 @@ def test_get_members_data(app, client, user_session):
assert member["permission_sets"] == {
"perms_team_mgmt": False,
"perms_env_mgmt": False,
"perms_del_env": False,
}
assert member["environment_roles"] == [
{
@@ -401,15 +400,14 @@ def test_create_member(monkeypatch, client, user_session, session):
"user_data-last_name": user.last_name,
"user_data-dod_id": user.dod_id,
"user_data-email": user.email,
"environment_roles-0-environment_id": env.id,
"environment_roles-0-environment_id": str(env.id),
"environment_roles-0-role": "ADMIN",
"environment_roles-0-environment_name": env.name,
"environment_roles-1-environment_id": env_1.id,
"environment_roles-1-environment_id": str(env_1.id),
"environment_roles-1-role": NO_ACCESS,
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
},
)
@@ -527,18 +525,17 @@ def test_update_member(client, user_session, session):
application_role_id=app_role.id,
),
data={
"environment_roles-0-environment_id": env.id,
"environment_roles-0-environment_id": str(env.id),
"environment_roles-0-role": "CONTRIBUTOR",
"environment_roles-0-environment_name": env.name,
"environment_roles-1-environment_id": env_1.id,
"environment_roles-1-environment_id": str(env_1.id),
"environment_roles-1-environment_name": env_1.name,
"environment_roles-1-disabled": "True",
"environment_roles-2-environment_id": env_2.id,
"environment_roles-2-environment_id": str(env_2.id),
"environment_roles-2-role": "BILLING_READ",
"environment_roles-2-environment_name": env_2.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
},
)
@@ -558,9 +555,6 @@ def test_update_member(client, user_session, session):
assert bool(
app_role.has_permission_set(PermissionSets.EDIT_APPLICATION_ENVIRONMENTS)
)
assert bool(
app_role.has_permission_set(PermissionSets.DELETE_APPLICATION_ENVIRONMENTS)
)
environment_roles = application.roles[0].environment_roles
# check that the user has roles in the correct envs
@@ -694,15 +688,14 @@ def test_handle_create_member(monkeypatch, set_g, session):
"user_data-last_name": user.last_name,
"user_data-dod_id": user.dod_id,
"user_data-email": user.email,
"environment_roles-0-environment_id": env.id,
"environment_roles-0-environment_id": str(env.id),
"environment_roles-0-role": "ADMIN",
"environment_roles-0-environment_name": env.name,
"environment_roles-1-environment_id": env_1.id,
"environment_roles-1-environment_id": str(env_1.id),
"environment_roles-1-role": NO_ACCESS,
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
}
)
handle_create_member(application.id, form_data)
@@ -731,17 +724,17 @@ def test_handle_update_member_success(set_g):
form_data = ImmutableMultiDict(
{
"environment_roles-0-environment_id": env.id,
"environment_roles-0-environment_id": str(env.id),
"environment_roles-0-role": "ADMIN",
"environment_roles-0-environment_name": env.name,
"environment_roles-1-environment_id": env_1.id,
"environment_roles-1-environment_id": str(env_1.id),
"environment_roles-1-role": NO_ACCESS,
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
}
)
handle_update_member(application.id, app_role.id, form_data)
assert len(application.roles) == 1
@@ -771,17 +764,53 @@ def test_handle_update_member_with_error(set_g, monkeypatch, mock_logger):
form_data = ImmutableMultiDict(
{
"environment_roles-0-environment_id": env.id,
"environment_roles-0-environment_id": str(env.id),
"environment_roles-0-role": "ADMIN",
"environment_roles-0-environment_name": env.name,
"environment_roles-1-environment_id": env_1.id,
"environment_roles-1-environment_id": str(env_1.id),
"environment_roles-1-role": NO_ACCESS,
"environment_roles-1-environment_name": env_1.name,
"perms_env_mgmt": True,
"perms_team_mgmt": True,
"perms_del_env": True,
}
)
handle_update_member(application.id, app_role.id, form_data)
assert mock_logger.messages[-1] == exception
def test_create_subscription_success(client, user_session):
environment = EnvironmentFactory.create()
user_session(environment.portfolio.owner)
response = client.post(
url_for("applications.create_subscription", environment_id=environment.id),
)
assert response.status_code == 302
assert response.location == url_for(
"applications.settings",
application_id=environment.application.id,
_external=True,
fragment="application-environments",
_anchor="application-environments",
)
def test_create_subscription_failure(client, user_session, monkeypatch):
environment = EnvironmentFactory.create()
def _raise_csp_exception(*args, **kwargs):
raise GeneralCSPException("An error occurred.")
monkeypatch.setattr(
"atst.domain.csp.cloud.MockCloudProvider.create_subscription",
_raise_csp_exception,
)
user_session(environment.portfolio.owner)
response = client.post(
url_for("applications.create_subscription", environment_id=environment.id),
)
assert response.status_code == 400

View File

@@ -1,3 +1,4 @@
import pytest
from flask import url_for
from unittest.mock import MagicMock
@@ -11,29 +12,6 @@ from atst.utils.localization import translate
from tests.factories import PortfolioFactory, PortfolioRoleFactory, UserFactory
def test_member_table_access(client, user_session):
admin = UserFactory.create()
portfolio = PortfolioFactory.create(owner=admin)
rando = UserFactory.create()
PortfolioRoleFactory.create(
user=rando,
portfolio=portfolio,
permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN)],
)
url = url_for("portfolios.admin", portfolio_id=portfolio.id)
# editable
user_session(admin)
edit_resp = client.get(url)
assert "<select" in edit_resp.data.decode()
# not editable
user_session(rando)
view_resp = client.get(url)
assert "<select" not in view_resp.data.decode()
def test_update_portfolio_name_and_description(client, user_session):
portfolio = PortfolioFactory.create()
user_session(portfolio.owner)
@@ -47,6 +25,7 @@ def test_update_portfolio_name_and_description(client, user_session):
assert portfolio.description == "a portfolio for things"
@pytest.mark.skip(reason="Out of scope for MVP")
def updating_ppoc_successfully(client, old_ppoc, new_ppoc, portfolio):
response = client.post(
url_for("portfolios.update_ppoc", portfolio_id=portfolio.id, _external=True),
@@ -67,6 +46,7 @@ def updating_ppoc_successfully(client, old_ppoc, new_ppoc, portfolio):
assert Permissions.EDIT_PORTFOLIO_POC not in old_ppoc.permissions
@pytest.mark.skip(reason="Out of scope for MVP")
def test_update_ppoc_no_user_id_specified(client, user_session):
portfolio = PortfolioFactory.create()
@@ -80,6 +60,7 @@ def test_update_ppoc_no_user_id_specified(client, user_session):
assert response.status_code == 404
@pytest.mark.skip(reason="Out of scope for MVP")
def test_update_ppoc_to_member_not_on_portfolio(client, user_session):
portfolio = PortfolioFactory.create()
original_ppoc = portfolio.owner
@@ -97,6 +78,7 @@ def test_update_ppoc_to_member_not_on_portfolio(client, user_session):
assert portfolio.owner.id == original_ppoc.id
@pytest.mark.skip(reason="Out of scope for MVP")
def test_update_ppoc_when_ppoc(client, user_session):
portfolio = PortfolioFactory.create()
original_ppoc = portfolio.owner_role
@@ -113,7 +95,8 @@ def test_update_ppoc_when_ppoc(client, user_session):
)
def test_update_ppoc_when_cpo(client, user_session):
@pytest.mark.skip(reason="Out of scope for MVP")
def test_update_ppoc_when_ccpo(client, user_session):
ccpo = UserFactory.create_ccpo()
portfolio = PortfolioFactory.create()
original_ppoc = portfolio.owner_role
@@ -130,6 +113,7 @@ def test_update_ppoc_when_cpo(client, user_session):
)
@pytest.mark.skip(reason="Out of scope for MVP")
def test_update_ppoc_when_not_ppoc(client, user_session):
portfolio = PortfolioFactory.create()
new_owner = UserFactory.create()
@@ -145,15 +129,6 @@ def test_update_ppoc_when_not_ppoc(client, user_session):
assert response.status_code == 404
def test_portfolio_admin_screen_when_ppoc(client, user_session):
portfolio = PortfolioFactory.create()
user_session(portfolio.owner)
response = client.get(url_for("portfolios.admin", portfolio_id=portfolio.id))
assert response.status_code == 200
assert portfolio.name in response.data.decode()
assert translate("fragments.ppoc.update_btn").encode("utf8") in response.data
def test_portfolio_admin_screen_when_not_ppoc(client, user_session):
portfolio = PortfolioFactory.create()
user = UserFactory.create()
@@ -254,3 +229,54 @@ def test_remove_portfolio_member_ppoc(client, user_session):
PortfolioRoles.get(portfolio_id=portfolio.id, user_id=portfolio.owner.id).status
== PortfolioRoleStatus.ACTIVE
)
def test_portfolios_update_member(client, user_session):
portfolio = PortfolioFactory.create()
portfolio_role = PortfolioRoleFactory.create(
portfolio=portfolio,
permission_sets=[PermissionSets.get(PermissionSets.EDIT_PORTFOLIO_ADMIN)],
)
form_data = {
"perms_app_mgmt": "y",
}
user_session(portfolio.owner)
response = client.post(
url_for(
"portfolios.update_member",
portfolio_id=portfolio.id,
portfolio_role_id=portfolio_role.id,
),
data=form_data,
follow_redirects=False,
)
assert response.status_code == 302
assert portfolio_role.has_permission_set(
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT
)
assert not portfolio_role.has_permission_set(PermissionSets.EDIT_PORTFOLIO_ADMIN)
def test_can_not_update_ppoc_permissions(client, user_session):
portfolio = PortfolioFactory.create()
owner = portfolio.owner
form_data = {
"perms_app_mgmt": "y",
}
user_session(owner)
response = client.post(
url_for(
"portfolios.update_member",
portfolio_id=portfolio.id,
portfolio_role_id=portfolio.owner_role.id,
),
data=form_data,
follow_redirects=False,
)
assert response.status_code == 400

View File

@@ -219,11 +219,11 @@ def test_resend_invitation_sends_email(monkeypatch, client, user_session):
monkeypatch.setattr("atst.jobs.send_mail.delay", job_mock)
user = UserFactory.create()
portfolio = PortfolioFactory.create()
ws_role = PortfolioRoleFactory.create(
portfolio_role = PortfolioRoleFactory.create(
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
)
invite = PortfolioInvitationFactory.create(
user_id=user.id, role=ws_role, status=InvitationStatus.PENDING
user_id=user.id, role=portfolio_role, status=InvitationStatus.PENDING
)
user_session(portfolio.owner)
client.post(
@@ -231,48 +231,23 @@ def test_resend_invitation_sends_email(monkeypatch, client, user_session):
"portfolios.resend_invitation",
portfolio_id=portfolio.id,
portfolio_token=invite.token,
)
),
data={
"user_data-dod_id": user.dod_id,
"user_data-first_name": user.first_name,
"user_data-last_name": user.last_name,
"user_data-email": user.email,
},
)
assert job_mock.called
def test_existing_member_invite_resent_to_email_submitted_in_form(
monkeypatch, client, user_session
):
job_mock = Mock()
monkeypatch.setattr("atst.jobs.send_mail.delay", job_mock)
portfolio = PortfolioFactory.create()
user = UserFactory.create()
ws_role = PortfolioRoleFactory.create(
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
)
invite = PortfolioInvitationFactory.create(
user_id=user.id,
role=ws_role,
status=InvitationStatus.PENDING,
email="example@example.com",
)
user_session(portfolio.owner)
client.post(
url_for(
"portfolios.resend_invitation",
portfolio_id=portfolio.id,
portfolio_token=invite.token,
)
)
assert user.email != "example@example.com"
ordered_args, _unordered_args = job_mock.call_args
recipients, _subject, _message = ordered_args
assert recipients[0] == "example@example.com"
_DEFAULT_PERMS_FORM_DATA = {
"permission_sets-perms_app_mgmt": False,
"permission_sets-perms_funding": False,
"permission_sets-perms_reporting": False,
"permission_sets-perms_portfolio_mgmt": False,
"permission_sets-perms_app_mgmt": "n",
"permission_sets-perms_funding": "n",
"permission_sets-perms_reporting": "n",
"permission_sets-perms_portfolio_mgmt": "n",
}

View File

@@ -219,13 +219,13 @@ def test_task_orders_submit_form_step_three_add_clins(client, user_session, task
user_session(task_order.portfolio.owner)
form_data = {
"clins-0-jedi_clin_type": "JEDI_CLIN_1",
"clins-0-clin_number": "12312",
"clins-0-number": "1212",
"clins-0-start_date": "01/01/2020",
"clins-0-end_date": "01/01/2021",
"clins-0-obligated_amount": "5000",
"clins-0-total_amount": "10000",
"clins-1-jedi_clin_type": "JEDI_CLIN_1",
"clins-1-number": "12312",
"clins-1-number": "1212",
"clins-1-start_date": "01/01/2020",
"clins-1-end_date": "01/01/2021",
"clins-1-obligated_amount": "5000",
@@ -269,7 +269,7 @@ def test_task_orders_submit_form_step_three_add_clins_existing_to(
user_session(task_order.portfolio.owner)
form_data = {
"clins-0-jedi_clin_type": "JEDI_CLIN_1",
"clins-0-clin_number": "12312",
"clins-0-number": "1212",
"clins-0-start_date": "01/01/2020",
"clins-0-end_date": "01/01/2021",
"clins-0-obligated_amount": "5000",

View File

@@ -373,6 +373,24 @@ def test_portfolios_edit_access(post_url_assert_status):
post_url_assert_status(rando, url, 404)
# portfolios.update_member
def test_portfolios_update_member_access(post_url_assert_status):
ccpo = user_with(PermissionSets.EDIT_PORTFOLIO_ADMIN)
owner = user_with()
rando = user_with()
portfolio = PortfolioFactory.create(owner=owner)
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio)
url = url_for(
"portfolios.update_member",
portfolio_id=portfolio.id,
portfolio_role_id=portfolio_role.id,
)
post_url_assert_status(ccpo, url, 302)
post_url_assert_status(owner, url, 302)
post_url_assert_status(rando, url, 404)
# applications.new
def test_applications_new_access(get_url_assert_status):
ccpo = user_with(PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT)
@@ -650,7 +668,7 @@ def test_task_orders_new_post_routes(post_url_assert_status):
"task_orders.submit_form_step_three_add_clins",
{
"clins-0-jedi_clin_type": "JEDI_CLIN_1",
"clins-0-clin_number": "12312",
"clins-0-number": "1212",
"clins-0-start_date": "01/01/2020",
"clins-0-end_date": "01/01/2021",
"clins-0-obligated_amount": "5000",

View File

@@ -97,25 +97,12 @@ def test_protected_routes_redirect_to_login(client, app):
def test_unprotected_routes_set_user_if_logged_in(client, app, user_session):
user = UserFactory.create()
resp = client.get(url_for("atst.helpdocs"))
resp = client.get(url_for("atst.about"))
assert resp.status_code == 200
assert user.full_name not in resp.data.decode()
user_session(user)
resp = client.get(url_for("atst.helpdocs"))
assert resp.status_code == 200
assert user.full_name in resp.data.decode()
def test_unprotected_routes_set_user_if_logged_in(client, app, user_session):
user = UserFactory.create()
resp = client.get(url_for("atst.helpdocs"))
assert resp.status_code == 200
assert user.full_name not in resp.data.decode()
user_session(user)
resp = client.get(url_for("atst.helpdocs"))
resp = client.get(url_for("atst.about"))
assert resp.status_code == 200
assert user.full_name in resp.data.decode()