Skip to content

Feature/allocation model tests #699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

Eric-Butcher
Copy link
Contributor

@Eric-Butcher Eric-Butcher commented Jun 12, 2025

This is the start of adding to the Allocation app test suite. I have wrote several tests covering the clean method, the save method, and the get_information property.

Many of the tests for the clean method use datetimes. I am not sure how well coldfront currently handles dates and times so these may need to be revised as currently they are quite naive.

Because the save() method uses an external setting to control whether or not it calls arbitrary functions it was quite hard to test and I had to get quite creative. Some of the code for that is admittedly ugly but it seems that it was the only way I could test it without making huge changes to the current way the code is written. I did need to make a small change to the save() method so that it refreshes the setting ALLOCATION_FUNCS_ON_EXPIRE when the method is called instead of relying on the value from when the module was instantiated by python. Without doing this there would be no way to test that behavior during test time. Some of the code that assists with the TestCase for save() had to live outside of the actual class because of issues with the way python initializes things and the meta-programming the I had to use to be able to test that an external function actually was being called by save().

It seems that it might be a bigger issue throughout the codebase of settings being loaded in at the top of a python file but then having their values used inside of functions defined in that file. This would mean that if someone ever went in a changed the value for an environment variable it might not take effect until they restarted the entire application. Let me know if you would like me to make an issue / PR to go through the codebase and fix everywhere that happens.

…on clean() method

Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
@Eric-Butcher Eric-Butcher force-pushed the feature/allocation-model-tests branch from 7a006e2 to df3a03b Compare June 17, 2025 17:18
Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
@Eric-Butcher Eric-Butcher force-pushed the feature/allocation-model-tests branch from df3a03b to cce5415 Compare June 17, 2025 17:23
@Eric-Butcher
Copy link
Contributor Author

Eric-Butcher commented Jun 18, 2025

I did more research on how Django handles datetimes and inspected how coldfront currently handles timezones.

It seems that coldfront is appropriately using the configuration environment variables to set the locality. However, in most instances in this codebase it seems that the project uses datetime.datetime.now() to create and reference datetimes and dates which are timezone naive.

For now I am using all dates and times as utc. The django.utils.timezone.now() function returns a timezone aware datetime object for the current time represented in UTC. It seems like it would be best practice to replace all instances of datetime.datetime.now() with django.utils.timezone.now() throughout the project. Similarly, all instances of datetime.date.today() should be replaced by timezone.now().date() to ensure that all dates we are storing and comparing are in UTC. Another option would be to change all DateFields where appropriate to DateTimeFields.

If having timezone aware tests are important it might be worth considering bringing a global time mocking library in such as freezegun or time machine.

https://docs.djangoproject.com/en/5.2/topics/i18n/timezones/

@Eric-Butcher Eric-Butcher force-pushed the feature/allocation-model-tests branch from eec246e to cce5415 Compare June 18, 2025 18:10
Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
@Eric-Butcher Eric-Butcher marked this pull request as ready for review June 18, 2025 18:55
…amming

Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
Signed-off-by: Eric Butcher <107886303+Eric-Butcher@users.noreply.github.com>
@Eric-Butcher
Copy link
Contributor Author

Eric-Butcher commented Jun 20, 2025

So I went ahead and replaced all occurrences of replacing environment variables using django.test.override_settings with monkey patches using unittest.mock.patch.

The problem with testing any functions that relied on the value of environment variables was that the code does not actually use the values of the environment variables inside of its functions.

For example, at the top of the file coldfront.core.allocation.models there are lines that create variables with the values of the environment variables:

ALLOCATION_ATTRIBUTE_VIEW_LIST = import_from_settings("ALLOCATION_ATTRIBUTE_VIEW_LIST", [])
ALLOCATION_FUNCS_ON_EXPIRE = import_from_settings("ALLOCATION_FUNCS_ON_EXPIRE", [])
ALLOCATION_RESOURCE_ORDERING = import_from_settings("ALLOCATION_RESOURCE_ORDERING", ["-is_allocatable", "name"])

Crucially, these are now new variables that are set to the values of the environment variables in the settings, but are not actually the environment variables in the settings. The code in the module then uses these newly created variables.

This meant that when trying to change the values of the environment variables in test cases using django.test.override_settings, the actual variable that the functions were using did not get changed and would be stuck to whatever the default value was in the source code.

The first approach I used to fix this was to just put a new line at the top of each function that used an env value to get the current value of the environment. However, this could be problematic because I do not know how python would handle it if an admin ever came in and manually changed the values in settings file at some point in time in the middle of a coldfront deployment. When the function would then be called and the env value fetched, I am not sure if it would use the new or old value.

The second approach is to use monkey patching instead, which hot-changes the value specifically of the variable inside the particular module when the tests are run using unittest.mock.patch. This is a very important distinction because this could cause confusion down the road. This is not actually changing the value of the environment variable while testing. It will only change the specific variable in the specific module being tested. You could now get a scenario where you are testing some module_a.function_a() that calls inside of it some module_b.function_b(). If both of these functions at same point use environment variables, then you would need to perform two separate patches, one for each module; even if they are referencing the same value in the env ultimately. This allows to test without changing the way the code is currently written.

@Eric-Butcher
Copy link
Contributor Author

Anton requested that this get split up into different PRs to make it more reviewable.

Now split into #706 #705 #704 and #703

I will close this PR once those are looked at. Will probably take the information here and move it into an issue.

@Eric-Butcher
Copy link
Contributor Author

Anton requested that this get split up into different PRs to make it more reviewable.

Now split into #707 #705 #704 and #703

@Eric-Butcher Eric-Butcher marked this pull request as draft June 30, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant