Skip to content

Commit

Permalink
MDL-45513 cache: added support to unit tests for alt cache stores
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Hemelryk committed May 29, 2014
1 parent 8e478c9 commit 79a8ea6
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 9 deletions.
7 changes: 4 additions & 3 deletions cache/classes/config.php
Expand Up @@ -100,8 +100,8 @@ public static function instance() {
* @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());
}

/**
Expand Down Expand Up @@ -324,7 +324,8 @@ public function get_site_identifier() {
*/
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.');
Expand Down
17 changes: 14 additions & 3 deletions cache/classes/factory.php
Expand Up @@ -325,11 +325,21 @@ public function get_caches_in_use() {
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';
Expand All @@ -350,6 +360,7 @@ public function create_config_instance($writer = false) {
// 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.
Expand Down
2 changes: 1 addition & 1 deletion cache/locallib.php
Expand Up @@ -68,7 +68,7 @@ public static function instance() {
*/
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);
Expand Down
4 changes: 2 additions & 2 deletions cache/tests/administration_helper_test.php
Expand Up @@ -165,9 +165,9 @@ public function test_get_add_store_form() {
*/
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 {
Expand Down
17 changes: 17 additions & 0 deletions cache/tests/cache_test.php
Expand Up @@ -62,6 +62,14 @@ public static function tearDownAfterClass() {
* 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);

Expand Down Expand Up @@ -1074,6 +1082,9 @@ public function test_application_definition_purge() {
*/
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();
Expand Down Expand Up @@ -1150,6 +1161,12 @@ public function test_disable_stores() {
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.
Expand Down
52 changes: 52 additions & 0 deletions cache/tests/fixtures/lib.php
Expand Up @@ -36,6 +36,47 @@
*/
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
Expand All @@ -56,6 +97,17 @@ public function phpunit_add_definition($area, array $properties) {
}
}
$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;
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/phpunit/bootstrap.php
Expand Up @@ -181,6 +181,7 @@
$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();
Expand Down

0 comments on commit 79a8ea6

Please sign in to comment.