django-cachalot icon indicating copy to clipboard operation
django-cachalot copied to clipboard

Compatibility with freezegun

Open kazqvaizer opened this issue 6 years ago • 1 comments

In our tests, we often use pytest + freezegun. Some time ago we started using cachalot and found out that our tests sometimes behave unstable.

For example, this simple test will fail if cachalot is connected:

    @pytest.mark.freeze_time('2032-12-11')
    def tests_broken():
        created_entry = SomeModel.objects.create(data='OriginalData')
    
        fetched_entry = SomeModel.objects.get(pk=created_entry.id)
        fetched_entry.data = 'UpdatedData'
        fetched_entry.save()
    
>       assert SomeModel.objects.get(pk=created_entry.id).data == 'UpdatedData'
E       AssertionError: assert 'OriginalData' == 'UpdatedData'
E         - OriginalData
E         + UpdatedData

This happens because with freezegun all dates are patched with static ones, and in this place the cachalot instead of making a new SELECT request takes the cache data, although the table was UPDATEd.

So we just turned off the cachalot in our tests.

I do not know if it is possible to fix it, but it would be great to write somewhere in the documentation that these libraries are not compatible. It can saves a lot of time to someone.

kazqvaizer avatar Feb 19 '19 03:02 kazqvaizer

Hi ik I'm pretty late but better late than never. Cachalot works by setting cached values in a tuple: (time set, queryset value). By using freezegun, cachalot won't work properly as we need to use these set times to properly invalidate caches.

As to enabling or disabling cachalot during tests, it depends. I like keeping it on, so you must be aware that by putting it off your system is prone to any slight error that cachalot may make. I noticed in #181 that Django 3.1.10 included a new ORM attribute that broke Django 3.1 temporarily. It's fixed in v2.4.0.

So my recommendation:

Anytime you use freezegun, create a pytest fixture and mark any test that uses freezegun. Like @pytest.mark.freezegun. Then, you should have an autouse=True fixture of scope function to override the setting: CACHALOT_ENABLED=False. That way, you can test all your queries properly while still being able to use freezegun. I hope this helped!

Andrew-Chen-Wang avatar May 13 '21 05:05 Andrew-Chen-Wang