Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace cachestore_redis;
  18  
  19  use cache_definition;
  20  use cache_store;
  21  use cachestore_redis;
  22  
  23  require_once (__DIR__.'/../../../tests/fixtures/stores.php');
  24  require_once (__DIR__.'/../lib.php');
  25  
  26  /**
  27   * Redis cache test - compressor settings.
  28   *
  29   * If you wish to use these unit tests all you need to do is add the following definition to
  30   * your config.php file.
  31   *
  32   * define('TEST_CACHESTORE_REDIS_TESTSERVERS', '127.0.0.1');
  33   *
  34   * @package   cachestore_redis
  35   * @author    Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
  36   * @copyright 2018 Catalyst IT Australia {@link http://www.catalyst-au.net}
  37   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class compressor_test extends \advanced_testcase {
  40  
  41      /**
  42       * Test set up
  43       */
  44      public function setUp(): void {
  45          if (!cachestore_redis::are_requirements_met() || !defined('TEST_CACHESTORE_REDIS_TESTSERVERS')) {
  46              $this->markTestSkipped('Could not test cachestore_redis. Requirements are not met.');
  47          }
  48  
  49          parent::setUp();
  50      }
  51  
  52      /**
  53       * Create a cachestore.
  54       *
  55       * @param int $compressor
  56       * @param int $serializer
  57       * @return cachestore_redis
  58       */
  59      public function create_store($compressor, $serializer) {
  60          /** @var cache_definition $definition */
  61          $definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_redis', 'phpunit_test');
  62          $config = cachestore_redis::unit_test_configuration();
  63          $config['compressor'] = $compressor;
  64          $config['serializer'] = $serializer;
  65          $store = new cachestore_redis('Test', $config);
  66          $store->initialise($definition);
  67  
  68          return $store;
  69      }
  70  
  71      /**
  72       * It misses a value.
  73       */
  74      public function test_it_can_miss_one() {
  75          $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, \Redis::SERIALIZER_PHP);
  76  
  77          self::assertFalse($store->get('missme'));
  78      }
  79  
  80      /**
  81       * It misses many values.
  82       */
  83      public function test_it_can_miss_many() {
  84          $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, \Redis::SERIALIZER_PHP);
  85  
  86          $expected = ['missme' => false, 'missmetoo' => false];
  87          $actual = $store->get_many(array_keys($expected));
  88          self::assertSame($expected, $actual);
  89      }
  90  
  91      /**
  92       * It misses some values.
  93       */
  94      public function test_it_can_miss_some() {
  95          $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, \Redis::SERIALIZER_PHP);
  96          $store->set('iamhere', 'youfoundme');
  97  
  98          $expected = ['missme' => false, 'missmetoo' => false, 'iamhere' => 'youfoundme'];
  99          $actual = $store->get_many(array_keys($expected));
 100          self::assertSame($expected, $actual);
 101      }
 102  
 103      /**
 104       * A provider for test_works_with_different_types
 105       *
 106       * @return array
 107       */
 108      public function provider_for_test_it_works_with_different_types() {
 109          $object = new \stdClass();
 110          $object->field = 'value';
 111  
 112          return [
 113              ['string', 'Abc Def'],
 114              ['string_empty', ''],
 115              ['string_binary', gzencode('some binary data')],
 116              ['int', 123],
 117              ['int_zero', 0],
 118              ['int_negative', -100],
 119              ['int_huge', PHP_INT_MAX],
 120              ['float', 3.14],
 121              ['boolean_true', true],
 122              // Boolean 'false' is not tested as it is not allowed in Moodle.
 123              ['array', [1, 'b', 3.4]],
 124              ['array_map', ['a' => 'b', 'c' => 'd']],
 125              ['object_stdClass', $object],
 126              ['null', null],
 127          ];
 128      }
 129  
 130      /**
 131       * It works with different types.
 132       *
 133       * @dataProvider provider_for_test_it_works_with_different_types
 134       * @param string $key
 135       * @param mixed $value
 136       */
 137      public function test_it_works_with_different_types($key, $value) {
 138          $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, \Redis::SERIALIZER_PHP);
 139          $store->set($key, $value);
 140  
 141          self::assertEquals($value, $store->get($key), "Failed set/get for: {$key}");
 142      }
 143  
 144      /**
 145       * Test it works with different types for many.
 146       */
 147      public function test_it_works_with_different_types_for_many() {
 148          $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, \Redis::SERIALIZER_PHP);
 149  
 150          $provider = $this->provider_for_test_it_works_with_different_types();
 151          $keys = [];
 152          $values = [];
 153          $expected = [];
 154          foreach ($provider as $item) {
 155              $keys[] = $item[0];
 156              $values[] = ['key' => $item[0], 'value' => $item[1]];
 157              $expected[$item[0]] = $item[1];
 158          }
 159          $store->set_many($values);
 160          $actual = $store->get_many($keys);
 161          self::assertEquals($expected, $actual);
 162      }
 163  
 164      /**
 165       * Provider for set/get combination tests.
 166       *
 167       * @return array
 168       */
 169      public function provider_for_tests_setget() {
 170          if (!cachestore_redis::are_requirements_met()) {
 171              // Even though we skip all tests in this case, this provider can still show warnings about non-existing class.
 172              return [];
 173          }
 174  
 175          $data = [
 176              ['none, none',
 177                  \Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_NONE,
 178                  'value1', 'value2'],
 179              ['none, gzip',
 180                  \Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_PHP_GZIP,
 181                  gzencode('value1'), gzencode('value2')],
 182              ['php, none',
 183                  \Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_NONE,
 184                  serialize('value1'), serialize('value2')],
 185              ['php, gzip',
 186                  \Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_PHP_GZIP,
 187                  gzencode(serialize('value1')), gzencode(serialize('value2'))],
 188          ];
 189  
 190          if (defined('Redis::SERIALIZER_IGBINARY')) {
 191              $data[] = [
 192                  'igbinary, none',
 193                      \Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_NONE,
 194                      igbinary_serialize('value1'), igbinary_serialize('value2'),
 195              ];
 196              $data[] = [
 197                  'igbinary, gzip',
 198                      \Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_PHP_GZIP,
 199                      gzencode(igbinary_serialize('value1')), gzencode(igbinary_serialize('value2')),
 200              ];
 201          }
 202  
 203          if (extension_loaded('zstd')) {
 204              $data[] = [
 205                  'none, zstd',
 206                  \Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_PHP_ZSTD,
 207                  zstd_compress('value1'), zstd_compress('value2'),
 208              ];
 209              $data[] = [
 210                  'php, zstd',
 211                  \Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_PHP_ZSTD,
 212                  zstd_compress(serialize('value1')), zstd_compress(serialize('value2')),
 213              ];
 214  
 215              if (defined('\Redis::SERIALIZER_IGBINARY')) {
 216                  $data[] = [
 217                      'igbinary, zstd',
 218                      \Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_PHP_ZSTD,
 219                      zstd_compress(igbinary_serialize('value1')), zstd_compress(igbinary_serialize('value2')),
 220                  ];
 221              }
 222          }
 223  
 224          return $data;
 225      }
 226  
 227      /**
 228       * Test we can use get and set with all combinations.
 229       *
 230       * @dataProvider provider_for_tests_setget
 231       * @param string $name
 232       * @param int $serializer
 233       * @param int $compressor
 234       * @param string $rawexpected1
 235       * @param string $rawexpected2
 236       */
 237      public function test_it_can_use_getset($name, $serializer, $compressor, $rawexpected1, $rawexpected2) {
 238          // Create a connection with the desired serialisation.
 239          $store = $this->create_store($compressor, $serializer);
 240          $store->set('key', 'value1');
 241  
 242          // Disable compressor and serializer to check the actual stored value.
 243          $rawstore = $this->create_store(cachestore_redis::COMPRESSOR_NONE, \Redis::SERIALIZER_NONE);
 244  
 245          $data = $store->get('key');
 246          $rawdata = $rawstore->get('key');
 247          self::assertSame('value1', $data, "Invalid serialisation/unserialisation for: {$name}");
 248          self::assertSame($rawexpected1, $rawdata, "Invalid rawdata for: {$name}");
 249      }
 250  
 251      /**
 252       * Test we can use get and set many with all combinations.
 253       *
 254       * @dataProvider provider_for_tests_setget
 255       * @param string $name
 256       * @param int $serializer
 257       * @param int $compressor
 258       * @param string $rawexpected1
 259       * @param string $rawexpected2
 260       */
 261      public function test_it_can_use_getsetmany($name, $serializer, $compressor, $rawexpected1, $rawexpected2) {
 262          $many = [
 263              ['key' => 'key1', 'value' => 'value1'],
 264              ['key' => 'key2', 'value' => 'value2'],
 265          ];
 266          $keys = ['key1', 'key2'];
 267          $expectations = ['key1' => 'value1', 'key2' => 'value2'];
 268          $rawexpectations = ['key1' => $rawexpected1, 'key2' => $rawexpected2];
 269  
 270          // Create a connection with the desired serialisation.
 271          $store = $this->create_store($compressor, $serializer);
 272          $store->set_many($many);
 273  
 274          // Disable compressor and serializer to check the actual stored value.
 275          $rawstore = $this->create_store(cachestore_redis::COMPRESSOR_NONE, \Redis::SERIALIZER_NONE);
 276  
 277          $data = $store->get_many($keys);
 278          $rawdata = $rawstore->get_many($keys);
 279          foreach ($keys as $key) {
 280              self::assertSame($expectations[$key],
 281                               $data[$key],
 282                               "Invalid serialisation/unserialisation for {$key} with serializer {$name}");
 283              self::assertSame($rawexpectations[$key],
 284                               $rawdata[$key],
 285                               "Invalid rawdata for {$key} with serializer {$name}");
 286          }
 287      }
 288  }