def test_invite_without_email(client): """The email is required.""" user_no_email = first_new_user.copy() user_no_email.pop("email") for inviter in ["superadmin", "unitadmin", "unituser"]: # Attempt invite response = client.post( tests.DDSEndpoint.USER_ADD, headers=tests.UserAuth( tests.USER_CREDENTIALS[inviter]).token(client), json=user_no_email, # query_string={"project": existing_project}, ) # There should be an error message assert response.status_code == http.HTTPStatus.BAD_REQUEST assert "Email address required to add or invite." in response.json[ "message"]
def test_del_request_others_unprivileged(client): """Unprivileged deletion request""" email_to_delete = "*****@*****.**" # with pytest.raises(ddserr.AccessDeniedError): response = client.delete( tests.DDSEndpoint.USER_DELETE, headers=tests.UserAuth( tests.USER_CREDENTIALS["delete_me_unituser"]).token(client), json={"email": email_to_delete}, ) assert response.status_code == http.HTTPStatus.FORBIDDEN # verify that user was not deleted exists = user_from_email(email_to_delete) assert exists is not None assert type(exists).__name__ == "UnitUser" assert exists.primary_email == email_to_delete
def test_del_request_others_self(client): """Unit Admin tries to instantly self-delete via this endpoint""" email_to_delete = "*****@*****.**" # with pytest.raises(ddserr.UserDeletionError): response = client.delete( tests.DDSEndpoint.USER_DELETE, headers=tests.UserAuth( tests.USER_CREDENTIALS["delete_me_unitadmin"]).token(client), json={"email": email_to_delete}, ) assert response.status_code == http.HTTPStatus.BAD_REQUEST # verify that user was not deleted exists = user_from_email(email_to_delete) assert exists is not None assert type(exists).__name__ == "UnitUser" assert exists.primary_email == email_to_delete
def test_new_file_sizeprocessed_bigint(client): """Add huge file.""" project_1 = project_row(project_id="file_testing_project") assert project_1 file_sizeprocessed_bigint = FIRST_NEW_FILE.copy() file_sizeprocessed_bigint[ "size_processed"] = 9223372036854775807 # 9223 petabytes (big int sql definition) response = client.post( tests.DDSEndpoint.FILE_NEW, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=file_sizeprocessed_bigint, ) assert response.status_code == http.HTTPStatus.OK assert file_in_db(test_dict=file_sizeprocessed_bigint, project=project_1.id)
def test_set_project_to_available_no_mail(module_client, boto3_session): """Set status to Available for test project, but skip sending mails""" current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 token = tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(module_client) response = module_client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=token, json=proj_data_with_existing_users, ) assert response.status_code == http.HTTPStatus.OK assert response.json and response.json.get("user_addition_statuses") for x in response.json.get("user_addition_statuses"): assert "given access to the Project" in x public_project_id = response.json.get("project_id") with unittest.mock.patch.object(flask_mail.Mail, "send") as mock_mail_send: with unittest.mock.patch.object( dds_web.api.user.AddUser, "compose_and_send_email_to_user") as mock_mail_func: response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=token, query_string={"project": public_project_id}, json={ "new_status": "Available", "deadline": 10, "send_email": False }, ) # assert that no mail is being sent. assert mock_mail_func.called == False assert mock_mail_send.call_count == 0 assert response.status_code == http.HTTPStatus.OK assert "An e-mail notification has not been sent." in response.json[ "message"]
def test_create_project_unknown_field(client): """Make request with unknown field passed.""" # Make sure there's 3 unit admins for unit create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 # Attempt creating project response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), json={"test": "test"}, ) assert response.status_code == http.HTTPStatus.BAD_REQUEST response_json = response.json assert (response_json and "title" in response_json and response_json["title"].get("message") == "Title is required.")
def test_auth_second_factor_expired_hotp_statuscode_401_unauthorized(client): """Test that the second_factor endpoint with expired hotp returns 401/UNAUTHORIZED""" user_auth = tests.UserAuth(tests.USER_CREDENTIALS["researcher"]) hotp_token = user_auth.fetch_hotp() user = dds_web.database.models.User.query.filter_by( username=user_auth.username).first() user.hotp_issue_time = datetime.datetime.now() - datetime.timedelta( minutes=15, seconds=1) db.session.commit() response = client.get( tests.DDSEndpoint.SECOND_FACTOR, headers=user_auth.partial_token(client), json={"HOTP": hotp_token.decode()}, ) assert response.status_code == http.HTTPStatus.UNAUTHORIZED response_json = response.json assert response_json.get("message") assert "Invalid one-time authentication code." == response_json.get( "message")
def test_invite_unituser_with_valid_unit_as_superadmin(client): """A unit user should be invited if the super admin provides a valid unit.""" for invitee in [new_unit_admin, new_unit_user]: valid_unit = models.Unit.query.filter_by(name="Unit 1").one_or_none() assert valid_unit invite_with_valid_unit = invitee.copy() invite_with_valid_unit["unit"] = valid_unit.public_id # Attempt invite response = client.post( tests.DDSEndpoint.USER_ADD, headers=tests.UserAuth( tests.USER_CREDENTIALS["superadmin"]).token(client), json=invite_with_valid_unit, ) new_invite = models.Invite.query.filter_by( email=invite_with_valid_unit["email"]).one_or_none() assert new_invite
def test_create_project_no_title(client): """Create project without a title specified.""" create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(client), json={"pi": "piName"}, ) assert response.status_code == http.HTTPStatus.BAD_REQUEST created_proj = models.Project.query.filter_by( created_by="unituser", pi=proj_data["pi"], ).one_or_none() assert created_proj is None
def test_create_project_none_pi(client): """Make request with missing title.""" create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 proj_data_none_pi = proj_data.copy() proj_data_none_pi["pi"] = None response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), json=proj_data_none_pi, ) assert response.status_code == http.HTTPStatus.BAD_REQUEST response_json = response.json assert ("pi" in response_json and response_json["pi"].get("message") == "A principal investigator is required.")
def perform_invite(client, inviting_user, email, role=None, project=None): json_data = {"email": email, "role": role} query_string = {} if project: if not role: raise ValueError( "Role must be specified when inviting to a project") query_string = {"project": project.public_id} # get the auth token here to avoid interfering with the invite token fetching auth_token = tests.UserAuth( tests.USER_CREDENTIALS[inviting_user.username]).token(client) # Need to get hold of the actual invite token invite_token = None with unittest.mock.patch.object(dds_web.api.user, "encrypted_jwt_token", return_value="token") as mock_token_method: response = client.post( tests.DDSEndpoint.USER_ADD, headers=auth_token, query_string=query_string, json=json_data, content_type="application/json", ) if DEBUG: print(response.data) # New invite token is not generated if invite is already sent assert mock_token_method.call_count <= 1 if mock_token_method.call_args is not None: call_args = mock_token_method.call_args invite_token = encrypted_jwt_token(*call_args.args, **call_args.kwargs) if response.status != "200 OK": if DEBUG: print(response.status_code) raise ValueError(f"Invitation failed: {response.data}") return invite_token
def test_add_existing_user_to_existing_project_no_mail_flag(client): "Test that an e-mail notification is not send when the --no-mail flag is used" user_copy = existing_research_user_to_existing_project.copy() project_id = user_copy.pop("project") new_status = {"new_status": "Available"} user_copy["send_email"] = False token = tests.UserAuth(tests.USER_CREDENTIALS["unituser"]).token(client) # make project available prior to test, otherwise an e-mail is never sent. response = client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=token, query_string={"project": project_id}, data=json.dumps(new_status), content_type="application/json", ) # Test mail sending is suppressed with unittest.mock.patch.object(flask_mail.Mail, "send") as mock_mail_send: with unittest.mock.patch.object( dds_web.api.user.AddUser, "compose_and_send_email_to_user") as mock_mail_func: print(user_copy) response = client.post( tests.DDSEndpoint.USER_ADD, headers=token, query_string={"project": project_id}, data=json.dumps(user_copy), content_type="application/json", ) # assert that no mail is being sent. assert mock_mail_func.called == False assert mock_mail_send.call_count == 0 assert response.status_code == http.HTTPStatus.OK assert "An e-mail notification has not been sent." in response.json[ "message"]
def test_create_project_with_malformed_json(client): """Create a project with malformed project info.""" create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(client), json="", ) assert response.status_code == http.HTTPStatus.BAD_REQUEST created_proj = models.Project.query.filter_by( created_by="unituser", title="", pi="", description="", ).one_or_none() assert created_proj is None
def test_create_project_without_credentials(client): """Create project without valid user credentials.""" create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), json=proj_data, ) assert response.status_code == http.HTTPStatus.FORBIDDEN created_proj = models.Project.query.filter_by( created_by="researchuser", title=proj_data["title"], pi=proj_data["pi"], description=proj_data["description"], ).one_or_none() assert created_proj is None
def test_auth_second_factor_correctauth_reused_hotp_401_unauthorized(client): """Test that the token endpoint called with an already used hotp returns 401/UNAUTHORIZED""" user_auth = tests.UserAuth(tests.USER_CREDENTIALS["researcher"]) hotp_token = user_auth.fetch_hotp() response = client.get( tests.DDSEndpoint.SECOND_FACTOR, headers=user_auth.partial_token(client), json={"HOTP": hotp_token.decode()}, ) assert response.status_code == http.HTTPStatus.OK # Reuse the same hotp token response = client.get( tests.DDSEndpoint.SECOND_FACTOR, headers=user_auth.partial_token(client), json={"HOTP": hotp_token.decode()}, ) assert response.status_code == http.HTTPStatus.UNAUTHORIZED response_json = response.json assert response_json.get("message") assert "Invalid one-time authentication code." == response_json.get( "message")
def test_fix_access_projectowner_valid_email_invalid_otheruser(client): """Project owner giving access to another user - no permissions.""" token = tests.UserAuth( tests.USER_CREDENTIALS["projectowner"]).token(client) response = client.post( tests.DDSEndpoint.PROJECT_ACCESS, headers=token, query_string=proj_query, json={"email": "*****@*****.**"}, ) assert response.status_code == http.HTTPStatus.FORBIDDEN assert "You do not have the necessary permissions" in response.json.get( "message") response = client.post( tests.DDSEndpoint.PROJECT_ACCESS, headers=token, query_string=proj_query, json={"email": "*****@*****.**"}, ) assert response.status_code == http.HTTPStatus.FORBIDDEN assert "You do not have the necessary permissions" in response.json.get( "message")
def test_add_user_with_unitadmin(client): with unittest.mock.patch.object(flask_mail.Mail, "send") as mock_mail_send: token = tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client) response = client.post( tests.DDSEndpoint.USER_ADD, headers=token, json=first_new_user, ) # One mail sent for partial token and one for the invite assert mock_mail_send.call_count == 2 assert response.status_code == http.HTTPStatus.OK invited_user = models.Invite.query.filter_by( email=first_new_user["email"]).one_or_none() assert invited_user assert invited_user.email == first_new_user["email"] assert invited_user.role == first_new_user["role"] assert invited_user.nonce is not None assert invited_user.public_key is not None assert invited_user.private_key is not None assert invited_user.project_invite_keys == [] # Repeating the invite should not send a new invite: with unittest.mock.patch.object(flask_mail.Mail, "send") as mock_mail_send: response = client.post( tests.DDSEndpoint.USER_ADD, headers=token, json=first_new_user, ) # No new mail should be sent for the token and neither for an invite assert mock_mail_send.call_count == 0 assert response.status_code == http.HTTPStatus.BAD_REQUEST message = response.json.get("message") assert "user was already added to the system" in message
def test_set_project_to_archived(module_client, test_project, boto3_session): """Archive an expired project""" new_status = {"new_status": "Archived"} project_id = test_project project = project_row(project_id=project_id) assert file_in_db(test_dict=FIRST_NEW_FILE, project=project.id) assert project.project_user_keys response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Archived" assert not max(project.project_statuses, key=lambda x: x.date_created).is_aborted assert not file_in_db(test_dict=FIRST_NEW_FILE, project=project.id) assert not project.project_user_keys
def test_create_project_sensitive(client, boto3_session): """Create a sensitive project.""" create_unit_admins(num_admins=2) current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 p_data = proj_data p_data["non_sensitive"] = False response = client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(client), json=p_data, ) assert response.status_code == http.HTTPStatus.OK created_proj = models.Project.query.filter_by( created_by="unituser", title=proj_data["title"], pi=proj_data["pi"], description=proj_data["description"], ).one_or_none() assert created_proj and not created_proj.non_sensitive
def test_cancel_2fa(client): user_auth = tests.UserAuth(tests.USER_CREDENTIALS["researcher"]) response = client.get(tests.DDSEndpoint.LOGIN) assert response.status == "200 OK" form_token = flask.g.csrf_token form_data = { "csrf_token": form_token, "username": user_auth.as_tuple()[0], "password": user_auth.as_tuple()[1], "submit": "Login", } response = client.post( tests.DDSEndpoint.LOGIN, json=form_data, follow_redirects=True, ) assert response.status == "200 OK" assert flask.request.path == tests.DDSEndpoint.CONFIRM_2FA second_factor_token = flask.session.get("2fa_initiated_token") assert second_factor_token is not None response = client.post( tests.DDSEndpoint.CANCEL_2FA, follow_redirects=True, ) assert response.status == "200 OK" assert flask.request.path == tests.DDSEndpoint.LOGIN second_factor_token = flask.session.get("2fa_initiated_token") assert second_factor_token is None
def test_fix_access_projectowner_valid_email(client): """Project Owner giving access to users - ok.""" project = models.Project.query.filter_by( public_id="public_project_id").one_or_none() assert project user_project_row = models.ProjectUsers.query.filter_by( project_id=project.id, user_id="researchuser").first() assert user_project_row po_project_row = models.ProjectUsers.query.filter_by( project_id=project.id, user_id="projectowner").first() assert po_project_row and po_project_row.owner user_project_key_row = models.ProjectUserKeys.query.filter_by( project_id=project.id, user_id="researchuser").first() if user_project_key_row: db.session.delete(user_project_key_row) db.session.commit() user_project_key_row = models.ProjectUserKeys.query.filter_by( project_id=project.id, user_id="researchuser").first() assert not user_project_key_row token = tests.UserAuth( tests.USER_CREDENTIALS["projectowner"]).token(client) response = client.post( tests.DDSEndpoint.PROJECT_ACCESS, headers=token, query_string=proj_query, json={"email": "*****@*****.**"}, ) assert response.status_code == http.HTTPStatus.OK user_project_key_row = models.ProjectUserKeys.query.filter_by( project_id=project.id, user_id="researchuser").first() assert user_project_key_row
def test_invite_to_register_unituser_by_unitadmin(client): "Test that a unit user can be created with project access" unitadmin = models.User.query.filter_by(username="******").one_or_none() unituser_to_be = "*****@*****.**" projects = set(unitadmin.projects) assert len(projects) > 1 user = invite_confirm_register_and_get_private( client, inviting_user=unitadmin, email=unituser_to_be, projects=None, role_per_project=["Unit Personnel"], ) assert user.role == "Unit Personnel" assert user.is_active assert set(user.projects) == projects assert len(user.project_user_keys) == len(projects) auth_token = tests.UserAuth(f"{user.username}:{REGISTRATION_DATA['password']}").token(client) for project in projects: get_private(client, project, auth_token)
def test_list_files_auth(client): """Confirm that the correct files/folders are listed.""" response = client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(client), query_string={"project": "public_project_id"}, json={"new_status": "Available"}, ) assert response.status_code == http.HTTPStatus.OK response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"show_size": True}, ) expected = { "files_folders": [ { "folder": True, "name": "filename1", "size": "15 KB" }, { "folder": True, "name": "filename2", "size": "82.5 KB" }, { "folder": True, "name": "sub", "size": "15 KB" }, ] } assert "files_folders" in response.json assert len(response.json["files_folders"]) == len( expected["files_folders"]) for entry in response.json["files_folders"]: assert len(entry) == 3 assert entry["folder"] is True assert set(entry["name"] for entry in response.json["files_folders"]) == set( entry["name"] for entry in expected["files_folders"]) response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"subpath": ""}, ) expected = { "files_folders": [ { "folder": True, "name": "filename1" }, { "folder": True, "name": "filename2" }, { "folder": True, "name": "sub" }, ] } assert "files_folders" in response.json assert len(response.json["files_folders"]) == len( expected["files_folders"]) for entry in response.json["files_folders"]: assert len(entry) == 2 assert entry["folder"] is True assert set(entry["name"] for entry in response.json["files_folders"]) == set( entry["name"] for entry in expected["files_folders"]) response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"subpath": "sub/path"}, ) assert response.json == {"files_folders": [{"folder": True, "name": "to"}]} response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"subpath": "sub/path/to"}, ) # compare in multiple steps as the order of the returned entries is not guaranteed expected = { "files_folders": [ { "folder": True, "name": "folder1" }, { "folder": True, "name": "folder2" }, { "folder": True, "name": "folder3" }, { "folder": True, "name": "folder4" }, { "folder": True, "name": "folder5" }, { "folder": True, "name": "files" }, ] } assert "files_folders" in response.json assert len(response.json["files_folders"]) == len( expected["files_folders"]) for entry in response.json["files_folders"]: assert len(entry) == 2 assert entry["folder"] is True assert set(entry["name"] for entry in response.json["files_folders"]) == set( entry["name"] for entry in expected["files_folders"]) response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"subpath": "sub/path/to/folder1"}, ) assert response.json == { "files_folders": [{ "folder": False, "name": "filename_a1" }] } response = client.get( tests.DDSEndpoint.LIST_FILES, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, json={"subpath": "sub/path/to/files"}, ) # compare in multiple steps as the order of the returned entries is not guaranteed expected = { "files_folders": [ { "folder": False, "name": "filename_b1" }, { "folder": False, "name": "filename_b2" }, { "folder": False, "name": "filename_b3" }, { "folder": False, "name": "filename_b4" }, { "folder": False, "name": "filename_b5" }, ] } assert "files_folders" in response.json assert len(response.json["files_folders"]) == len( expected["files_folders"]) for entry in response.json["files_folders"]: assert len(entry) == 2 assert entry["folder"] is False assert set(entry["name"] for entry in response.json["files_folders"]) == set( entry["name"] for entry in expected["files_folders"])
def test_load_login_page(client): user_auth = tests.UserAuth(tests.USER_CREDENTIALS["researcher"]) response = client.get(tests.DDSEndpoint.LOGIN) assert response.status == "200 OK"
def get_token(username, client): return tests.UserAuth(tests.USER_CREDENTIALS[username]).token(client)
def test_abort_from_in_progress_once_made_available(module_client, boto3_session): """Create project and abort it from In Progress after it has been made available""" current_unit_admins = models.UnitUser.query.filter_by( unit_id=1, is_admin=True).count() assert current_unit_admins == 3 response = module_client.post( tests.DDSEndpoint.PROJECT_CREATE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(module_client), json=proj_data, ) assert response.status_code == http.HTTPStatus.OK project_id = response.json.get("project_id") # add a file response = module_client.post( tests.DDSEndpoint.FILE_NEW, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=FIRST_NEW_FILE, ) project = project_row(project_id=project_id) assert file_in_db(test_dict=FIRST_NEW_FILE, project=project.id) new_status = {"new_status": "Available"} time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Available" new_status["new_status"] = "In Progress" time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "In Progress" assert project.project_user_keys response = module_client.get( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json={"history": True}, ) assert response.status_code == http.HTTPStatus.OK assert response.json["current_status"] == project.current_status assert response.json["current_deadline"] assert response.json["history"] time.sleep(1) new_status["new_status"] = "Archived" new_status["is_aborted"] = True response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Archived" assert max(project.project_statuses, key=lambda x: x.date_created).is_aborted assert not file_in_db(test_dict=FIRST_NEW_FILE, project=project.id) for field, value in vars(project).items(): if field in fields_set_to_null: assert not value assert len(project.researchusers) == 0 assert not project.project_user_keys
def test_project_availability_after_set_to_expired_more_than_twice( module_client, test_project): """Try to set status to Available for test project after being in Expired 3 times""" new_status = {"new_status": "Available", "deadline": 5} project_id = test_project project = project_row(project_id=project_id) time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Available" new_status["new_status"] = "Expired" time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Expired" new_status["new_status"] = "Available" time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Available" new_status["new_status"] = "Expired" time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project.current_status == "Expired" new_status["new_status"] = "Available" time.sleep(1) response = module_client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(module_client), query_string={"project": project_id}, json=new_status, ) assert response.status_code == http.HTTPStatus.BAD_REQUEST assert project.current_status == "Expired" assert "Project cannot be made Available any more times" in response.json[ "message"]
def test_files_find_all_for_download(client, boto3_session): """Check if correct file info for all files is returned for download""" # Set status to available response = client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unituser"]).token(client), query_string={"project": "public_project_id"}, json={"new_status": "Available"}, ) assert response.status_code == http.HTTPStatus.OK with unittest.mock.patch( "dds_web.api.api_s3_connector.ApiS3Connector.generate_get_url" ) as mock_url: mock_url.return_value = "url" response = client.get( tests.DDSEndpoint.FILE_INFO_ALL, headers=tests.UserAuth( tests.USER_CREDENTIALS["researchuser"]).token(client), query_string={"project": "public_project_id"}, ) assert response.status_code == http.HTTPStatus.OK # filenames in conftest expected_output = { "filename1": { "subpath": "filename1/subpath", "size_original": 15000, "size_stored": 10000, "compressed": True, "salt": "A" * 32, "public_key": "B" * 64, "checksum": "C" * 64, "url": "url", }, "filename2": { "subpath": "filename2/subpath", "size_original": 15000, "size_stored": 10000, "compressed": True, "salt": "D" * 32, "public_key": "E" * 64, "checksum": "F" * 64, "url": "url", }, } for i in range(5): expected_output[f"filename_a{i+1}"] = { "subpath": f"sub/path/to/folder{i+1}", "size_original": 5000 * (i + 1), "size_stored": 3000 * (i + 1), "compressed": True, "salt": chr(ord("A") + 3 * i) * 32, "public_key": chr(ord("B") + 3 * i) * 64, "checksum": chr(ord("C") + 3 * i) * 64, "url": "url", } expected_output[f"filename_b{i+1}"] = { "subpath": f"sub/path/to/files", "size_original": 500 * (i + 1), "size_stored": 300 * (i + 1), "compressed": True, "salt": chr(ord("Z") - 3 * i) * 32, "public_key": chr(ord("Y") - 3 * i) * 64, "checksum": chr(ord("X") - 3 * i) * 64, "url": "url", } files = response.json["files"] for file in files: files[file].pop("name_in_bucket") assert "filename1" in files assert "filename2" in files for i in range(5): assert f"filename_a{i+1}" in files assert f"filename_b{i+1}" in files unittest.TestCase().assertDictEqual(expected_output, files)
def test_upload_move_available_delete_file(client, boto3_session): """Test delete a file once project has been made available""" project_1 = project_row(project_id="file_testing_project") assert project_1 assert project_1.current_status == "In Progress" response = client.post( tests.DDSEndpoint.FILE_NEW, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=FIRST_NEW_FILE, ) assert response.status_code == http.HTTPStatus.OK assert file_in_db(test_dict=FIRST_NEW_FILE, project=project_1.id) # Make project Available new_status = {"new_status": "Available"} response = client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project_1.current_status == "Available" # Try deleting the uploaded file response = client.delete( tests.DDSEndpoint.REMOVE_FILE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=[FIRST_NEW_FILE["name"]], ) assert response.status_code == http.HTTPStatus.BAD_REQUEST assert "Project Status prevents files from being deleted." in response.json[ "message"] # Move project back to In Progress time.sleep(1) new_status["new_status"] = "In Progress" response = client.post( tests.DDSEndpoint.PROJECT_STATUS, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=new_status, ) assert response.status_code == http.HTTPStatus.OK assert project_1.current_status == "In Progress" # Try deleting uploaded file again response = client.delete( tests.DDSEndpoint.REMOVE_FILE, headers=tests.UserAuth( tests.USER_CREDENTIALS["unitadmin"]).token(client), query_string={"project": "file_testing_project"}, json=[FIRST_NEW_FILE["name"]], ) assert response.status_code == http.HTTPStatus.BAD_REQUEST assert ( "Existing project contents cannot be deleted since the project has been previously made available to recipients." in response.json["message"])
def invite_confirm_register_and_get_private(client, inviting_user, email, projects, role_per_project=None, no_checkbox=False): # Invite if projects is None or projects == []: assert len(role_per_project) == 1 invite_token = perform_invite(client, inviting_user, email, role=role_per_project[0]) else: for project, role in zip(projects, role_per_project): most_recent_invite_token = perform_invite(client, inviting_user, email, role=role, project=project) # only the first invite returns a token if most_recent_invite_token is not None: invite_token = most_recent_invite_token if DEBUG: print([(invite.email, invite.role) for invite in models.Invite.query.all()]) print([(pik.project.public_id, pik.invite.email, pik.owner) for pik in models.ProjectInviteKeys.query.all()]) # Confirm invite response = client.get(tests.DDSEndpoint.USER_CONFIRM + invite_token, content_type="application/json") assert response.status == "200 OK" # Complete registration form_token = flask.g.csrf_token if no_checkbox: NO_CHECKBOX_REGISTRATION_DATA = REGISTRATION_DATA.copy() NO_CHECKBOX_REGISTRATION_DATA.pop("policy_checkbox") form_data = { **NO_CHECKBOX_REGISTRATION_DATA, "csrf_token": form_token, "email": email } response = client.post( tests.DDSEndpoint.USER_NEW, json=form_data, follow_redirects=True, ) assert response.status == "200 OK" user = models.User.query.filter_by( username=form_data["username"]).one_or_none() else: form_data = { **REGISTRATION_DATA, "csrf_token": form_token, "email": email } response = client.post( tests.DDSEndpoint.USER_NEW, json=form_data, follow_redirects=True, ) assert response.status == "200 OK" user = models.User.query.filter_by( username=form_data["username"]).one_or_none() auth_token = tests.UserAuth( f"{form_data['username']}:{form_data['password']}").token(client) if projects is not None: for project in projects: # Request decrypted project private key for user just created # to somewhat test that the decryption works get_private(client, project, auth_token) return user