silverstripe-terraformers/keys-for-cache

Add developer documentation regarding unit tests with KFC

Closed this issue · 0 comments

  • KFC includes a feature to make sure that it only updates the cache for any unique record once per request.
  • An entire unit test case is considered "one request".
  • A developer might want to create tests that check their cache key updates when they trigger a change on that record.

Below is an example of a reasonable test that a developer might want to undertake. You would expect that the LastEdited and getCacheKey() values update with each var_dump().

class SiteConfigTest extends SapphireTest
{

    protected $usesDatabase = true;

    public function testSiteConfigCacheKey(): void
    {
        $siteConfig = SiteConfig::current_site_config();
        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());

        // Sleep for a second to make sure our date changes
        sleep(1);

        // Make a change to SiteConfig
        $siteConfig->Title = 'Updated Site Title 1';
        $siteConfig->write();

        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());

        // Sleep for a second to make sure our date changes
        sleep(1);

        // Make a change to SiteConfig
        $siteConfig->Title = 'Updated Site Title 2';
        $siteConfig->write();

        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());
    }

}

Actual: LastEdited does update, but getCacheKey() does not.

In order to get the expected outcome, developers need to add ProcessedUpdatesService::singleton()->flush(); before they write() their record. This clears the cache for KFC, and will mean that any records saved will now have their cache key updated (even if they have done so previously in this request).

EG:

class SiteConfigTest extends SapphireTest
{

    protected $usesDatabase = true;

    public function testSiteConfigCacheKey(): void
    {
        $siteConfig = SiteConfig::current_site_config();
        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());

        // Sleep for a second to make sure our date changes
        sleep(1);

        // Flush updates from KFC so that new writes invalidate cache keys
        ProcessedUpdatesService::singleton()->flush();

        // Make a change to SiteConfig
        $siteConfig->Title = 'Updated Site Title 1';
        $siteConfig->write();

        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());

        // Sleep for a second to make sure our date changes
        sleep(1);

        // Flush updates from KFC so that new writes invalidate cache keys
        ProcessedUpdatesService::singleton()->flush();

        // Make a change to SiteConfig
        $siteConfig->Title = 'Updated Site Title 2';
        $siteConfig->write();

        var_dump($siteConfig->LastEdited);
        var_dump($siteConfig->getCacheKey());
    }

}

Reconsider how we cache updated records?

It's possible as well that we should reconsider how we cache what records have been updated, so that devs don't even ever have this issue.

Off the top of my head, perhaps we could use onAfter hooks in our Extension to perform a flush() on ProcessedUpdatesService