MDL-56273 cache: Use cache initialise always.

purge_all() and purge_by_definition() look in the configuration
for which caches are available and then creates them to purge them.
The configuration stores the values used by initialise(), not
initialise_unit_test_instance() and would therefore fail to purge
all caches if they were not purged by another means.

In the case of filestore, it's purged by unit tests, in the case
of memcache(d), it purges the whole store when a single definition
is requested.

Therefore all configuration was moved into the configuration file
during unit tests and does not have any special override codes in
the unit test infrastructure.
This commit is contained in:
Russell Smith 2016-10-06 12:23:24 +11:00
parent 577bd70d38
commit a169739d5d
18 changed files with 123 additions and 147 deletions

View File

@ -262,6 +262,15 @@ class cachestore_dummy extends cache_store {
return $cache;
}
/**
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function unit_test_configuration() {
return [];
}
/**
* Returns the name of this instance.
* @return string

View File

@ -81,15 +81,11 @@ interface cache_store_interface {
public static function initialise_test_instance(cache_definition $definition);
/**
* Initialises a test instance for unit tests.
* Generates the appropriate configuration required for unit testing.
*
* This differs from initialise_test_instance in that it doesn't rely on interacting with the config table.
*
* @since 2.8
* @param cache_definition $definition
* @return cache_store|false
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function initialise_unit_test_instance(cache_definition $definition);
public static function unit_test_configuration();
}
/**
@ -369,20 +365,6 @@ abstract class cache_store implements cache_store_interface {
return clone($this);
}
/**
* Initialises a test instance for unit tests.
*
* This differs from initialise_test_instance in that it doesn't rely on interacting with the config table.
* By default however it calls initialise_test_instance to support backwards compatibility.
*
* @since 2.8
* @param cache_definition $definition
* @return cache_store|false
*/
public static function initialise_unit_test_instance(cache_definition $definition) {
return static::initialise_test_instance($definition);
}
/**
* Can be overridden to return any warnings this store instance should make to the admin.
*

View File

@ -369,23 +369,12 @@ class cachestore_apcu extends cache_store implements cache_is_key_aware, cache_i
}
/**
* Generates an instance of the cache store that can be used for testing.
* Generates the appropriate configuration required for unit testing.
*
* @param cache_definition $definition
* @return cachestore_apcu|false
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function initialise_unit_test_instance(cache_definition $definition) {
if (!self::are_requirements_met()) {
return false;
}
$store = new cachestore_apcu('Test APCu', array('prefix' => 'phpunit'));
if (!$store->is_ready()) {
return false;
}
$store->initialise($definition);
return $store;
public static function unit_test_configuration() {
return array('prefix' => 'phpunit');
}
/**
@ -416,4 +405,16 @@ class cachestore_apcu extends cache_store implements cache_is_key_aware, cache_i
}
$editform->set_data($data);
}
/**
* Returns true if this cache store instance is both suitable for testing, and ready for testing.
*
* Cache stores that support being used as the default store for unit and acceptance testing should
* override this function and return true if there requirements have been met.
*
* @return bool
*/
public static function ready_to_be_used_for_testing() {
return true;
}
}

View File

@ -57,7 +57,8 @@ class cachestore_apcu_test extends cachestore_tests {
*/
public function test_cross_application_interaction() {
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_apcu', 'phpunit_test');
$instance = cachestore_apcu::initialise_unit_test_instance($definition);
$instance = new cachestore_apcu('Test', cachestore_apcu::unit_test_configuration());
$instance->initialise($definition);
// Test purge with custom data.
$this->assertTrue($instance->set('test', 'monster'));
@ -75,9 +76,12 @@ class cachestore_apcu_test extends cachestore_tests {
public function test_different_caches_have_different_prefixes() {
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_apcu', 'phpunit_test');
$instance = cachestore_apcu::initialise_unit_test_instance($definition);
$instance = new cachestore_apcu('Test', cachestore_apcu::unit_test_configuration());
$instance->initialise($definition);
$definition2 = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_apcu', 'phpunit_test2');
$instance2 = cachestore_apcu::initialise_unit_test_instance($definition2);
$instance2 = new cachestore_apcu('Test', cachestore_apcu::unit_test_configuration());
$instance2->initialise($definition2);
$instance->set('test1', 1);
$this->assertFalse($instance2->get('test1'));

View File

@ -677,6 +677,15 @@ class cachestore_file extends cache_store implements cache_is_key_aware, cache_i
return $cache;
}
/**
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function unit_test_configuration() {
return array();
}
/**
* Writes your madness to a file.
*

View File

@ -582,24 +582,16 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
}
/**
* Creates a test instance for unit tests if possible.
* @param cache_definition $definition
* @return bool|cachestore_memcache
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function initialise_unit_test_instance(cache_definition $definition) {
if (!self::are_requirements_met()) {
return false;
}
public static function unit_test_configuration() {
// If the configuration is not defined correctly, return only the configuration know about.
if (!defined('TEST_CACHESTORE_MEMCACHE_TESTSERVERS')) {
return false;
return [];
}
$configuration = array();
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MEMCACHE_TESTSERVERS);
$store = new cachestore_memcache('Test memcache', $configuration);
$store->initialise($definition);
return $store;
return ['servers' => explode("\n", TEST_CACHESTORE_MEMCACHE_TESTSERVERS)];
}
/**

View File

@ -57,7 +57,8 @@ class cachestore_memcache_test extends cachestore_tests {
$this->resetAfterTest(true);
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcache', 'phpunit_test');
$instance = cachestore_memcache::initialise_unit_test_instance($definition);
$instance = new cachestore_memcache('Memcache Test', cachestore_memcache::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) { // Something prevented memcache store to be inited (extension, TEST_CACHESTORE_MEMCACHE_TESTSERVERS...).
$this->markTestSkipped();

View File

@ -739,25 +739,16 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
}
/**
* Creates a test instance for unit tests if possible.
* @param cache_definition $definition
* @return bool|cachestore_memcached
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function initialise_unit_test_instance(cache_definition $definition) {
if (!self::are_requirements_met()) {
return false;
}
public static function unit_test_configuration() {
// If the configuration is not defined correctly, return only the configuration know about.
if (!defined('TEST_CACHESTORE_MEMCACHED_TESTSERVERS')) {
return false;
return [];
}
$configuration = array();
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MEMCACHED_TESTSERVERS);
$store = new cachestore_memcached('Test memcached', $configuration);
$store->initialise($definition);
return $store;
return ['servers' => explode("\n", TEST_CACHESTORE_MEMCACHED_TESTSERVERS)];
}
/**

View File

@ -61,9 +61,11 @@ class cachestore_memcached_test extends cachestore_tests {
$this->resetAfterTest(true);
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
$instance = cachestore_memcached::initialise_unit_test_instance($definition);
$instance = new cachestore_memcached('Memcached Test', cachestore_memcached::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) { // Something prevented memcached store to be inited (extension, TEST_CACHESTORE_MEMCACHED_TESTSERVERS...).
if (!$instance->is_ready()) {
// Something prevented memcached store to be inited (extension, TEST_CACHESTORE_MEMCACHED_TESTSERVERS...).
$this->markTestSkipped();
}

View File

@ -571,25 +571,16 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
* @param cache_definition $definition
* @return false
*/
public static function initialise_unit_test_instance(cache_definition $definition) {
if (!self::are_requirements_met()) {
return false;
}
if (!defined('TEST_CACHESTORE_MONGODB_TESTSERVER')) {
return false;
}
public static function unit_test_configuration() {
$configuration = array();
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MONGODB_TESTSERVER);
$configuration['usesafe'] = 1;
$store = new cachestore_mongodb('Test mongodb', $configuration);
if (!$store->is_ready()) {
return false;
// If the configuration is not defined correctly, return only the configuration know about.
if (defined('TEST_CACHESTORE_MONGODB_TESTSERVER')) {
$configuration['servers'] = explode("\n", TEST_CACHESTORE_MONGODB_TESTSERVER);
}
$store->initialise($definition);
return $store;
return $configuration;
}
/**

View File

@ -56,9 +56,10 @@ class cachestore_mongodb_test extends cachestore_tests {
public function test_collection_name() {
// This generates a definition that has a hash starting with a number. MDL-46208.
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_mongodb', 'abc');
$instance = cachestore_mongodb::initialise_unit_test_instance($definition);
$instance = new cachestore_mongodb('MongoDB_Test', cachestore_mongodb::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) {
if (!$instance->is_ready()) {
$this->markTestSkipped();
}

View File

@ -516,6 +516,14 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
return $cache;
}
/**
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function unit_test_configuration() {
return array();
}
/**
* Returns the name of this instance.
* @return string

View File

@ -492,6 +492,15 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
return $cache;
}
/**
* Generates the appropriate configuration required for unit testing.
*
* @return array Array of unit test configuration data to be used by initialise().
*/
public static function unit_test_configuration() {
return array();
}
/**
* Returns the name of this instance.
* @return string

View File

@ -1315,8 +1315,10 @@ class core_cache_testcase extends advanced_testcase {
$configfile = $CFG->dataroot.'/muc/config.php';
// That's right, we're deleting the config file.
$this->assertTrue(@unlink($configfile));
// The config file will not exist yet as we've not done anything with the cache.
// reset_all_data removes the file and without a call to create a configuration it doesn't exist
// as yet.
$this->assertFileNotExists($configfile);
// Disable the cache
cache_phpunit_factory::phpunit_disable();

View File

@ -73,13 +73,13 @@ class cache_config_testing extends cache_config_writer {
if (class_exists($class) && $class::ready_to_be_used_for_testing()) {
/* @var cache_store $class */
$writer->configstores['test_application'] = array(
'use_test_store' => true,
'name' => 'test_application',
'plugin' => $expectedstore,
'alt' => $writer->configstores[$defaultapplication],
'modes' => $class::get_supported_modes(),
'features' => $class::get_supported_features()
'features' => $class::get_supported_features(),
'configuration' => $class::unit_test_configuration()
);
$defaultapplication = 'test_application';
}
}
@ -535,47 +535,4 @@ class cache_phpunit_factory extends cache_factory {
public static function phpunit_disable() {
parent::disable();
}
/**
* @var bool Whether the warning notice about alternative cache store used has been displayed.
*/
protected $altcachestorenotice = false;
/**
* Creates a store instance given its name and configuration.
*
* If the store has already been instantiated then the original object will be returned. (reused)
*
* @param string $name The name of the store (must be unique remember)
* @param array $details
* @param cache_definition $definition The definition to instantiate it for.
* @return boolean|cache_store
*/
public function create_store_from_config($name, array $details, cache_definition $definition) {
if (isset($details['use_test_store'])) {
// name, plugin, alt
$class = 'cachestore_'.$details['plugin'];
$method = 'initialise_unit_test_instance';
if (class_exists($class) && method_exists($class, $method)) {
$instance = $class::$method($definition);
if ($instance) {
return $instance;
}
}
// Notify user that alternative store is being used, so action can be taken.
if (!$this->altcachestorenotice) {
echo PHP_EOL . "++ WARNING: " . 'Failed to use "' . $details['plugin'] . '" cache store, alt "' .
$details['alt']['plugin'] . '" cache store is used.' . PHP_EOL . PHP_EOL;
$this->altcachestorenotice = true;
}
$details = $details['alt'];
$details['class'] = 'cachestore_'.$details['plugin'];
$name = $details['name'];
}
return parent::create_store_from_config($name, $details, $definition);
}
}

View File

@ -42,19 +42,29 @@ abstract class cachestore_tests extends advanced_testcase {
*/
abstract protected function get_class_name();
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*/
public function setUp() {
$class = $this->get_class_name();
if (!class_exists($class) || !$class::are_requirements_met()) {
$this->markTestSkipped('Could not test '.$class.'. Requirements are not met.');
}
parent::setUp();
}
/**
* Run the unit tests for the store.
*/
public function test_test_instance() {
$class = $this->get_class_name();
if (!class_exists($class) || !method_exists($class, 'initialise_test_instance') || !$class::are_requirements_met()) {
$this->markTestSkipped('Could not test '.$class.'. Requirements are not met.');
}
$modes = $class::get_supported_modes();
if ($modes & cache_store::MODE_APPLICATION) {
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, $class, 'phpunit_test');
$instance = $class::initialise_unit_test_instance($definition);
$instance = new $class($class.'_test', $class::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) {
$this->markTestSkipped('Could not test '.$class.'. No test instance configured for application caches.');
} else {
@ -63,7 +73,9 @@ abstract class cachestore_tests extends advanced_testcase {
}
if ($modes & cache_store::MODE_SESSION) {
$definition = cache_definition::load_adhoc(cache_store::MODE_SESSION, $class, 'phpunit_test');
$instance = $class::initialise_unit_test_instance($definition);
$instance = new $class($class.'_test', $class::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) {
$this->markTestSkipped('Could not test '.$class.'. No test instance configured for session caches.');
} else {
@ -72,7 +84,9 @@ abstract class cachestore_tests extends advanced_testcase {
}
if ($modes & cache_store::MODE_REQUEST) {
$definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $class, 'phpunit_test');
$instance = $class::initialise_unit_test_instance($definition);
$instance = new $class($class.'_test', $class::unit_test_configuration());
$instance->initialise($definition);
if (!$instance) {
$this->markTestSkipped('Could not test '.$class.'. No test instance configured for request caches.');
} else {

2
cache/upgrade.txt vendored
View File

@ -13,6 +13,8 @@ Information provided here is intended especially for developers.
- cache_store::cleanup()
* cachestore_dummy::cleanup() has been deprecated.
* cachestore_dummy::instance_deleted() implemented in lieu of cachestore_dummy::cleanup().
* Added cache_store::unit_test_configuration() to calculate unit testing configuration.
* Remove cache_store:initialise_unit_test_instance() as it is incompatible with cache_helper purge functions.
=== 3.1 ===
* Cache stores has a new feature DEREFERENCES_OBJECTS.

View File

@ -814,12 +814,13 @@ abstract class testing_util {
make_temp_directory('');
make_cache_directory('');
make_localcache_directory('');
// Purge all data from the caches. This is required for consistency between tests.
// Any file caches that happened to be within the data root will have already been clearer (because we just deleted cache)
// and now we will purge any other caches as well. This must be done before the cache_factory::reset() as that
// removes all definitions of caches and purge does not have valid caches to operate on.
cache_helper::purge_all();
// Reset the cache API so that it recreates it's required directories as well.
cache_factory::reset();
// Purge all data from the caches. This is required for consistency.
// Any file caches that happened to be within the data root will have already been clearer (because we just deleted cache)
// and now we will purge any other caches as well.
cache_helper::purge_all();
}
/**