diff --git a/README.md b/README.md index e39bb703..75d1bc96 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,27 @@ A specific test of an app can also be executed - `python manage.py test sharing_ Or a specific test case can also be executed - `python manage.py test sharing_portal.tests.test_git_parser` -Todo: Currently, running test cases that require a DB connection does not work. This needs to be fixed + +#### Writing tests that require a DB connection + +Currently, automatic setup and teardown of the test DB is not supported. To run tests that require a DB connection, we are required to manually manage + +To guarantee the idempotence of DB tests, any tests that save records to the DB should delete the records gracefully upon finishing execution to avoid spillover into the results of the next tests. + +#### Deploying tests that require a DB connection + +Upon running test cases, Django tries to create a test DB with an identical schema to the production DB; Django however encounters migrations issues and fails the creation. To circumvent this issue, we manually create and mantain the test DB as follows: +- Create a dump of the production dev DB by running the following command in the DB deployment container: + - `mysqldump -u chameleon_dev -p*specifypasswordhere* PROD_DB_NAME > PROD_DB_NAME_TODAYSDATETIME.sql` +- Create a new test DB by appending "_test" to the prod DB name and load the prod DB dump onto the newly created test DB: + - `mysql --user chameleon_dev -p*specifypasswordhere* CREATE DATABASE *PROD_DB_NAME*_test` + - `mysqldump -u chameleon_dev -p*specifypasswordhere* TEST_DB_NAME < PROD_DB_NAME_TODAYSDATETIME.sql` +- Ensure all migrations run properly on the test DB using: + - `./manage.py migrate --database TEST_DB_NAME` +- **(Important)** Run **ALL** db tests tests with the --keepdb flag as follows to prevent Django's auto setup and teardown of the test DB: + - `sudo docker exec portal ./manage.py test allocations.tests --keepdb` + ## Deployment -The production deployment of Portal is managed via [portal-camino](https://github.com/ChameleonCloud/portal-camino). +The production deployment of Portal is managed via [portal-camino](https://github.com/ChameleonCloud/portal-camino). \ No newline at end of file diff --git a/TestSummary.md b/TestSummary.md new file mode 100644 index 00000000..fad02483 --- /dev/null +++ b/TestSummary.md @@ -0,0 +1,241 @@ +# Lists of tests that do not work: +``` +ERROR: test_allocation_form_fields_required (projects.tests.ProjectViewTests) +Tests that appropriate fields are required on the project form. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1346, in patched + return func(*newargs, **newkeywargs) + File "/project/projects/tests.py", line 227, in test_allocation_form_fields_required + mock_tas_project.return_value = json.loads(f.read()) + File "/usr/local/lib/python3.7/json/__init__.py", line 348, in loads + return _default_decoder.decode(s) + File "/usr/local/lib/python3.7/json/decoder.py", line 337, in decode + obj, end = self.raw_decode(s, idx=_w(s, 0).end()) + File "/usr/local/lib/python3.7/json/decoder.py", line 353, in raw_decode + obj, end = self.scan_once(s, idx) +json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 106 column 1 (char 2953) +``` +``` +ERROR: test_project_form_fields_required (projects.tests.ProjectViewTests) +Tests that appropriate fields are required on the project form. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/keycloak/client.py", line 84, in _handle_response + response.raise_for_status() + File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 1021, in raise_for_status + raise HTTPError(http_error_msg, response=self) +requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://auth.dev.chameleoncloud.org/auth/realms/master/protocol/openid-connect/token +``` +``` +====================================================================== +ERROR: test_view_allocation_rejected (projects.tests.ProjectViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_view_allocation_rejected_with_active (projects.tests.ProjectViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_view_project (projects.tests.ProjectViewTests) +Test that a project with an active allocation up for renewal displays the recharge +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_view_project_redirect (projects.tests.ProjectViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_view_project_with_pending (projects.tests.ProjectViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_edit_profile_submit (tas.tests.EditProfileViewTests) +POSTing the form on the edit profile page should call TASClient.save_user. Also, +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_edit_profile_view (tas.tests.EditProfileViewTests) +Logged in users can access the edit profile view. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_edit_profile_view_source_not_chameleon (tas.tests.EditProfileViewTests) +User accounts sourced from places other than Chameleon cannot edit their profile +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute + return self.cursor.execute(sql, params) + File "/usr/local/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 73, in execute + return self.cursor.execute(query, args) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute + res = self._query(query) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query + db.query(q) + File "/usr/local/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query + _mysql.connection.query(self, query) +MySQLdb._exceptions.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`chameleon_dev_test`.`cms_pageuser`, CONSTRAINT `cms_pageuser_created_by_id_18eb7aa0ce6f1c16_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`))') +``` +``` +ERROR: test_register_view (tas.tests.RegisterViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1345, in patched + keywargs) as (newargs, newkeywargs): + File "/usr/local/lib/python3.7/contextlib.py", line 112, in __enter__ + return next(self.gen) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1325, in decoration_helper + arg = exit_stack.enter_context(patching) + File "/usr/local/lib/python3.7/contextlib.py", line 427, in enter_context + result = _cm_type.__enter__(cm) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1414, in __enter__ + original, local = self.get_original() + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1388, in get_original + "%s does not have the attribute %r" % (target, name) +AttributeError: does not have the attribute 'get_institution_choices' +``` +```ERROR: test_register_view_submit_not_pi (tas.tests.RegisterViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1345, in patched + keywargs) as (newargs, newkeywargs): + File "/usr/local/lib/python3.7/contextlib.py", line 112, in __enter__ + return next(self.gen) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1325, in decoration_helper + arg = exit_stack.enter_context(patching) + File "/usr/local/lib/python3.7/contextlib.py", line 427, in enter_context + result = _cm_type.__enter__(cm) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1414, in __enter__ + original, local = self.get_original() + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1388, in get_original + "%s does not have the attribute %r" % (target, name) +AttributeError: does not have the attribute 'get_institution_choices' +``` +``` +ERROR: test_register_view_submit_pi (tas.tests.RegisterViewTests) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1345, in patched + keywargs) as (newargs, newkeywargs): + File "/usr/local/lib/python3.7/contextlib.py", line 112, in __enter__ + return next(self.gen) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1325, in decoration_helper + arg = exit_stack.enter_context(patching) + File "/usr/local/lib/python3.7/contextlib.py", line 427, in enter_context + result = _cm_type.__enter__(cm) + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1414, in __enter__ + original, local = self.get_original() + File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1388, in get_original + "%s does not have the attribute %r" % (target, name) +AttributeError: does not have the attribute 'get_institution_choices' +``` +``` +ERROR: sharing_portal.tests.test_artifact (unittest.loader._FailedTest) +---------------------------------------------------------------------- +ImportError: Failed to import test module: sharing_portal.tests.test_artifact +Traceback (most recent call last): + File "/usr/local/lib/python3.7/unittest/loader.py", line 436, in _find_test_path + module = self._get_module_from_name(name) + File "/usr/local/lib/python3.7/unittest/loader.py", line 377, in _get_module_from_name + __import__(name) + File "/project/sharing_portal/tests/test_artifact.py", line 7, in + from .. import DEV as dev +ImportError: cannot import name 'DEV' from 'sharing_portal' (/project/sharing_portal/__init__.py) +``` +``` +ERROR: sharing_portal.tests.test_views (unittest.loader._FailedTest) +---------------------------------------------------------------------- +ImportError: Failed to import test module: sharing_portal.tests.test_views +Traceback (most recent call last): + File "/usr/local/lib/python3.7/unittest/loader.py", line 436, in _find_test_path + module = self._get_module_from_name(name) + File "/usr/local/lib/python3.7/unittest/loader.py", line 377, in _get_module_from_name + __import__(name) + File "/project/sharing_portal/tests/test_views.py", line 8, in + from ..views import make_author, upload_artifact +ImportError: cannot import name 'make_author' from 'sharing_portal.views' (/project/sharing_portal/views.py) +``` \ No newline at end of file diff --git a/allocations/tests.py b/allocations/tests.py index 7ce503c2..476f0673 100644 --- a/allocations/tests.py +++ b/allocations/tests.py @@ -1,3 +1,385 @@ +import logging + +from datetime import timedelta +from unittest import mock + from django.test import TestCase +from django.utils import timezone +from django.contrib.auth import get_user_model + +from projects.models import Project +from util.keycloak_client import KeycloakClient + +from allocations import tasks +from allocations.models import Allocation + + +LOG = logging.getLogger(__name__) + +class StatusTests(TestCase): + def setUp(self): + User = get_user_model() + + self.test_requestor = User.objects.create_user( + username="test_requestor", + password="test_password", + ) + + self.test_reviewer = User.objects.create_user( + username="test_reviewer", + password="test_password", + ) + + self.test_project = Project( + tag=None, + automatically_tagged=False, + description="This is a test project for allocations.", + pi=self.test_requestor, + title="Test Project", + nickname="test_project", + charge_code="TEST123" + ) + + self.test_project.save() + + def tearDown(self): + self.test_requestor.delete() + self.test_reviewer.delete() + self.test_project.delete() + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": False}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_deactivate_active_allocation(self, update_project_mock, lookup_group_mock): + """ Tests whether deactivate_active_allocation() + updates an active allocation's status to inactive + """ + test_active_allocation = Allocation( + project=self.test_project, + status="active", + justification="This is a test allocation.", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now(), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + sample_dict = {"has_active_allocation": False} + sample_dict.get('has_active_allocation') + tasks._deactivate_allocation(test_active_allocation) + + update_project_mock.assert_called_once_with( + test_active_allocation.project.charge_code, has_active_allocation="false" + ) + lookup_group_mock.assert_called_once_with( + test_active_allocation.project.charge_code + ) + + self.assertEqual(test_active_allocation.status, "inactive") + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": False}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_deactivate_inactive_allocation(self, update_project_mock, lookup_group_mock): + """Tests whether deactivate_active_allocation() does not update + an inactive allocation's status + """ + test_inactive_allocation = Allocation( + project=self.test_project, + status="inactive", + justification="This is a test allocation.", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now(), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + sample_dict = {"has_active_allocation": False} + sample_dict.get('has_active_allocation') + tasks._deactivate_allocation(test_inactive_allocation) + + update_project_mock.assert_called_once_with( + test_inactive_allocation.project.charge_code, has_active_allocation="false" + ) + lookup_group_mock.assert_called_once_with( + test_inactive_allocation.project.charge_code + ) + + self.assertEqual(test_inactive_allocation.status, "inactive") + + def test_deactivate_multiple_allocations_of_projects(self): + """Tests whether deactivate_multiple_active_allocations_of_projects() + deactivates all allocations but the latest expiry date one + """ + test_project_multiple_alloc = Project( + tag=None, # You can set the tag if necessary + automatically_tagged=False, + description="This is a test project for allocations.", + pi=self.test_requestor, # Replace my_user with an actual User instance + title="Multiple Alloc Project", + nickname="multiple_alloc_project", + charge_code="multiple_alloc" # You can set a unique charge code + ) + + test_project_multiple_alloc.save() + + test_active_allocation_1 = Allocation( + project=test_project_multiple_alloc, + status="active", + justification="later alloc", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now() + timedelta(hours=1, minutes=0), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_active_allocation_2 = Allocation( + project=test_project_multiple_alloc, + status="active", + justification="earlier alloc", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now(), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_active_allocation_1.save() + test_active_allocation_2.save() + + tasks.deactivate_multiple_active_allocations_of_projects() + + inactive_allocs = Allocation.objects.filter(project=test_project_multiple_alloc) + + passed_assertions = 0 + for alloc in inactive_allocs: + if (alloc.justification == "earlier alloc"): + self.assertEqual(alloc.status, "inactive") + passed_assertions += 1 + alloc.delete() + if (alloc.justification == "later alloc"): + self.assertEqual(alloc.status, "active") + passed_assertions += 1 + alloc.delete() + + test_project_multiple_alloc.delete() + + self.assertEqual(passed_assertions, 2) + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": True}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_active_approved_allocations(self, update_project_mock, lookup_group_mock): + """Tests that active_approved_allocations() changes the status of + approved allocations to active + """ + test_approved_allocation = Allocation( + project=self.test_project, + status="approved", + justification="approved alloc", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now(), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_approved_allocation.save() + tasks.active_approved_allocations() + + test_allocations = Allocation.objects.filter(project=self.test_project, + justification="approved alloc") + + update_project_mock.assert_called_once_with( + test_approved_allocation.project.charge_code, has_active_allocation="true" + ) + lookup_group_mock.assert_called_once_with( + test_approved_allocation.project.charge_code + ) + + for alloc in test_allocations: + self.assertEqual(alloc.status, "active") + alloc.delete() + + test_approved_allocation.delete() + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": False}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_nonapproved_active_approved_allocation(self, update_project_mock, lookup_group_mock): + """Tests that active_approved_allocations() does not change + the status of non-approved allocations + """ + test_nonapproved_allocation = Allocation( + project=self.test_project, + status="pending", + justification="pending alloc", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now() + timedelta(hours=1, minutes=0), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_nonapproved_allocation.save() + tasks.active_approved_allocations() + + test_allocations = Allocation.objects.filter(project=self.test_project, + justification="pending alloc") + + for alloc in test_allocations: + self.assertEqual(alloc.status, "pending") + alloc.delete() + + update_project_mock.assert_not_called() + lookup_group_mock.assert_not_called() + + test_nonapproved_allocation.delete() + + +class ExpireTests(TestCase): + def setUp(self): + User = get_user_model() + + self.test_requestor = User.objects.create_user( + username="test_requestor", + password="test_password", + ) + + self.test_reviewer = User.objects.create_user( + username="test_reviewer", # Replace with the desired username + password="test_password", # Replace with the desired password + ) + + self.test_project = Project( + tag=None, # You can set the tag if necessary + automatically_tagged=False, + description="This is a test project for allocations.", + pi=self.test_requestor, # Replace my_user with an actual User instance + title="Test Project", + nickname="test_project", + charge_code="TEST123" # You can set a unique charge code + ) + + self.test_project.save() + + def tearDown(self): + self.test_requestor.delete() + self.test_reviewer.delete() + self.test_project.delete() + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": False}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_expire_expired_alloc_allocations(self, update_project_mock, lookup_group_mock): + """Tests that expore_allocations() changes the status + of all expired allocations to inactive + """ + test_expired_allocation = Allocation( + project=self.test_project, + status="active", + justification="expired allocation", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now() - timedelta(hours=1, minutes=0), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_expired_allocation.save() + + tasks.expire_allocations() + + update_project_mock.assert_called_once_with( + test_expired_allocation.project.charge_code, has_active_allocation="false" + ) + lookup_group_mock.assert_called_once_with( + test_expired_allocation.project.charge_code + ) + + expired_allocations = Allocation.objects.filter( + project=self.test_project, + justification="expired allocation", + expiration_date__lte=timezone.now() + ) + + for alloc in expired_allocations: + self.assertTrue(alloc.status, "inactive") + alloc.delete() + + @mock.patch.object(KeycloakClient, '_lookup_group', return_value={"attributes": {"has_active_allocation": False}}) + @mock.patch.object(KeycloakClient, 'update_project', return_value=None) + def test_expire_non_expired_alloc_allocations(self, update_project_mock, lookup_group_mock): + """Tests that expore_allocations() does not change the status + of unexpired allocations + """ + test_expired_allocation = Allocation( + project=self.test_project, + status="active", + justification="non expired allocation", + requestor=self.test_requestor, + date_requested=timezone.now(), + decision_summary="Test decision summary.", + reviewer=self.test_reviewer, + date_reviewed=timezone.now(), + expiration_date=timezone.now() + timedelta(hours=1, minutes=0), + su_requested=100.0, + start_date=timezone.now(), + su_allocated=50.0, + su_used=25.0, + balance_service_version=2, + ) + + test_expired_allocation.save() + + tasks.expire_allocations() + + update_project_mock.assert_not_called() + lookup_group_mock.assert_not_called() + + expired_allocations = Allocation.objects.filter( + project=self.test_project, + justification="non expired allocation", + ) -# Create your tests here. + for alloc in expired_allocations: + self.assertTrue(alloc.status, "active") + alloc.delete() diff --git a/chameleon/settings.py b/chameleon/settings.py index 7424b7c2..c4f76e36 100644 --- a/chameleon/settings.py +++ b/chameleon/settings.py @@ -257,6 +257,9 @@ "PORT": os.environ.get("DB_PORT"), "USER": os.environ.get("DB_USER"), "PASSWORD": os.environ.get("DB_PASSWORD"), + "TEST": { + 'NAME': os.environ.get("DB_NAME") + "_test", + }, }, } else: @@ -918,3 +921,4 @@ ######## SEMANTIC_SCHOLAR_API_KEY = os.environ.get("SEMANTIC_SCHOLAR_API_KEY") SCRAPER_API_KEY = os.environ.get("SCRAPER_API_KEY") +