MDL-45513 cache: added support to unit tests for alt cache stores
authorSam Hemelryk <sam@moodle.com>
Sun, 11 May 2014 20:38:43 +0000 (08:38 +1200)
committerSam Hemelryk <sam@moodle.com>
Thu, 29 May 2014 20:41:07 +0000 (08:41 +1200)
cache/classes/config.php
cache/classes/factory.php
cache/locallib.php
cache/tests/administration_helper_test.php
cache/tests/cache_test.php
cache/tests/fixtures/lib.php
lib/phpunit/bootstrap.php

index 322035f..5fdf2b9 100644 (file)
@@ -100,8 +100,8 @@ class cache_config {
      * @return bool True if it exists
      */
     public static function config_file_exists() {
-        // Allow for late static binding.
-        return file_exists(self::get_config_file_path());
+        // Allow for late static binding by using static.
+        return file_exists(static::get_config_file_path());
     }
 
     /**
@@ -324,7 +324,8 @@ class cache_config {
      */
     protected function include_configuration() {
         $configuration = array();
-        $cachefile = self::get_config_file_path();
+        // We need to allow for late static bindings to allow for class path mudling happending for unit tests.
+        $cachefile = static::get_config_file_path();
 
         if (!file_exists($cachefile)) {
             throw new cache_exception('Default cache config could not be found. It should have already been created by now.');
index 825a441..b9b42f4 100644 (file)
@@ -325,11 +325,21 @@ class cache_factory {
     public function create_config_instance($writer = false) {
         global $CFG;
 
-        // Check if we need to create a config file with defaults.
-        $needtocreate = !cache_config::config_file_exists();
-
         // The class to use.
         $class = 'cache_config';
+        // Check if this is a PHPUnit test and redirect to the phpunit config classes if it is.
+        if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
+            require_once($CFG->dirroot.'/cache/locallib.php');
+            require_once($CFG->dirroot.'/cache/tests/fixtures/lib.php');
+            // We have just a single class for PHP unit tests. We don't care enough about its
+            // performance to do otherwise and having a single method allows us to inject things into it
+            // while testing.
+            $class = 'cache_config_phpunittest';
+        }
+
+        // Check if we need to create a config file with defaults.
+        $needtocreate = !$class::config_file_exists();
+
         if ($writer || $needtocreate) {
             require_once($CFG->dirroot.'/cache/locallib.php');
             $class .= '_writer';
@@ -350,6 +360,7 @@ class cache_factory {
             // Create the default configuration.
             // Update the state, we are now initialising the cache.
             self::set_state(self::STATE_INITIALISING);
+            /** @var cache_config_writer $class */
             $configuration = $class::create_default_configuration();
             if ($configuration !== true) {
                 // Failed to create the default configuration. Disable the cache stores and update the state.
index c7948cf..042b891 100644 (file)
@@ -68,7 +68,7 @@ class cache_config_writer extends cache_config {
      */
     protected function config_save() {
         global $CFG;
-        $cachefile = self::get_config_file_path();
+        $cachefile = static::get_config_file_path();
         $directory = dirname($cachefile);
         if ($directory !== $CFG->dataroot && !file_exists($directory)) {
             $result = make_writable_directory($directory, false);
index c30ae0c..68f8d95 100644 (file)
@@ -165,9 +165,9 @@ class core_cache_administration_helper_testcase extends advanced_testcase {
      */
     public function test_get_edit_store_form() {
         $config = cache_config_writer::instance();
-        $this->assertTrue($config->add_store_instance('summariesstore', 'file'));
+        $this->assertTrue($config->add_store_instance('test_get_edit_store_form', 'file'));
 
-        $form = cache_administration_helper::get_edit_store_form('file', 'summariesstore');
+        $form = cache_administration_helper::get_edit_store_form('file', 'test_get_edit_store_form');
         $this->assertInstanceOf('moodleform', $form);
 
         try {
index 5a85f14..7d8fe16 100644 (file)
@@ -62,6 +62,14 @@ class core_cache_testcase extends advanced_testcase {
      * Tests cache configuration
      */
     public function test_cache_config() {
+        global $CFG;
+
+        if (!empty($CFG->altcacheconfigpath)) {
+            // We need to skip this test - it checks the default config structure, but very likely we arn't using the
+            // default config structure here so theres no point in running the test.
+            $this->markTestSkipped('Skipped testing default cache config structure as alt cache path is being used.');
+        }
+
         $instance = cache_config::instance();
         $this->assertInstanceOf('cache_config_phpunittest', $instance);
 
@@ -1074,6 +1082,9 @@ class core_cache_testcase extends advanced_testcase {
      */
     public function test_alt_cache_path() {
         global $CFG;
+        if ($CFG->altcacheconfigpath) {
+            $this->markTestSkipped('Skipped testing alt cache path as it is already being used.');
+        }
         $this->resetAfterTest();
         $CFG->altcacheconfigpath = $CFG->dataroot.'/cache/altcacheconfigpath';
         $instance = cache_config_phpunittest::instance();
@@ -1150,6 +1161,12 @@ class core_cache_testcase extends advanced_testcase {
     public function test_disable() {
         global $CFG;
 
+        if (!empty($CFG->altcacheconfigpath)) {
+            // We can't run this test as it requires us to delete the cache configuration script which we just
+            // cant do with a custom path in play.
+            $this->markTestSkipped('Skipped testing cache disable functionality as alt cache path is being used.');
+        }
+
         $configfile = $CFG->dataroot.'/muc/config.php';
 
         // That's right, we're deleting the config file.
index e6ecbe0..845ca41 100644 (file)
@@ -36,6 +36,47 @@ defined('MOODLE_INTERNAL') || die();
  */
 class cache_config_phpunittest extends cache_config_writer {
 
+    /**
+     * Returns the expected path to the configuration file.
+     *
+     * We override this function to add handling for $CFG->altcacheconfigpath.
+     * We want to support it so that people can run unit tests against alternative cache setups.
+     * However we don't want to ever make changes to the file at $CFG->altcacheconfigpath so we
+     * always use dataroot and copy the alt file there as required.
+     *
+     * @throws cache_exception
+     * @return string The absolute path
+     */
+    protected static function get_config_file_path() {
+        global $CFG;
+        // We always use this path.
+        $configpath = $CFG->dataroot.'/muc/config.php';
+
+        if (!empty($CFG->altcacheconfigpath)) {
+            $path = $CFG->altcacheconfigpath;
+            if (is_dir($path) && is_writable($path)) {
+                // Its a writable directory, thats fine. Convert it to a file.
+                $path = $CFG->altcacheconfigpath.'/cacheconfig.php';
+            }
+            if (is_readable($path)) {
+                $directory = dirname($configpath);
+                if ($directory !== $CFG->dataroot && !file_exists($directory)) {
+                    $result = make_writable_directory($directory, false);
+                    if (!$result) {
+                        throw new cache_exception('ex_configcannotsave', 'cache', '', null, 'Cannot create config directory. Check the permissions on your moodledata directory.');
+                    }
+                }
+                // We don't care that this fails but we should let the developer know.
+                if (!is_readable($configpath) && !@copy($path, $configpath)) {
+                    debugging('Failed to copy alt cache config file to required location');
+                }
+            }
+        }
+
+        // We always use the dataroot location.
+        return $configpath;
+    }
+
     /**
      * Adds a definition to the stack
      * @param string $area
@@ -56,6 +97,17 @@ class cache_config_phpunittest extends cache_config_writer {
             }
         }
         $this->configdefinitions[$area] = $properties;
+        switch ($properties['mode']) {
+            case cache_store::MODE_APPLICATION:
+                $this->phpunit_add_definition_mapping($area, 'default_application', 0);
+                break;
+            case cache_store::MODE_SESSION:
+                $this->phpunit_add_definition_mapping($area, 'default_session', 0);
+                break;
+            case cache_store::MODE_REQUEST:
+                $this->phpunit_add_definition_mapping($area, 'default_request', 0);
+                break;
+        }
     }
 
     /**
index 983e5e2..683e764 100644 (file)
@@ -181,6 +181,7 @@ $CFG->dboptions = isset($CFG->phpunit_dboptions) ? $CFG->phpunit_dboptions : $CF
 $allowed = array('wwwroot', 'dataroot', 'dirroot', 'admin', 'directorypermissions', 'filepermissions',
                  'dbtype', 'dblibrary', 'dbhost', 'dbname', 'dbuser', 'dbpass', 'prefix', 'dboptions',
                  'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword', 'proxybypass', // keep proxy settings from config.php
+                 'altcacheconfigpath'
                 );
 $productioncfg = (array)$CFG;
 $CFG = new stdClass();