Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: colinmollenhour/Cm_Cache_Backend_Redis
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.13.0
Choose a base ref
...
head repository: colinmollenhour/Cm_Cache_Backend_Redis
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Jan 3, 2020

  1. Updated to Support Sentinel Auth

    Added Configuration with Sentinel AUTH Support
    tschirmer authored Jan 3, 2020
    Copy the full SHA
    7e877aa View commit details
  2. Merge pull request #149 from tschirmer/master

    Updated to Support Sentinel Auth
    colinmollenhour authored Jan 3, 2020
    Copy the full SHA
    5dd4032 View commit details

Commits on Feb 28, 2020

  1. 151 fix

    ilnytskyi authored Feb 28, 2020
    Copy the full SHA
    d58327f View commit details

Commits on Mar 10, 2020

  1. Copy the full SHA
    02eef64 View commit details

Commits on Mar 11, 2020

  1. Harden _decodeData in the face applications which convert php notices…

    … into exceptions resulting in cache entries not being regenerated
    Xon committed Mar 11, 2020
    Copy the full SHA
    0996fcb View commit details
  2. Merge pull request #154 from Xon/decodeDataTweaks

    Harden _decodeData
    colinmollenhour authored Mar 11, 2020
    Copy the full SHA
    a4cfd52 View commit details

Commits on Apr 24, 2020

  1. Track Credit 1.11.1;

    - Add TLS support
    - Php 7.3+ support
    - Minor redis command fixes
    Xon committed Apr 24, 2020
    Copy the full SHA
    cdc23e9 View commit details

Commits on Apr 25, 2020

  1. Merge pull request #157 from Xon/credis_update

    Track Credit 1.11.1
    colinmollenhour authored Apr 25, 2020
    Copy the full SHA
    39b3257 View commit details

Commits on Jun 4, 2020

  1. Merge pull request #152 from ilnytskyi/ilnytskyi-patch-1

    Fix when get Object(Credis_Client) to decode
    colinmollenhour authored Jun 4, 2020
    Copy the full SHA
    1132d90 View commit details

Commits on Feb 27, 2021

  1. Copy the full SHA
    b19e3a5 View commit details

Commits on Mar 2, 2021

  1. Merge pull request #163 from nemphys/lua-clean-fix

    Fix bug in lua clean script (tags not removed from global list of tags)
    colinmollenhour authored Mar 2, 2021
    Copy the full SHA
    0b042d2 View commit details

Commits on May 20, 2022

  1. Fix PHP 8.1 deprecation error

    zamu87 authored May 20, 2022
    Copy the full SHA
    e75ea1e View commit details

Commits on Jun 11, 2022

  1. Copy the full SHA
    08154b2 View commit details

Commits on Jun 20, 2022

  1. Merge pull request #166 from bbakalov/fix-php81-warning-array-access

    Fix PHP 8.1 Warning: Trying to access array offset on value of type bool
    colinmollenhour authored Jun 20, 2022
    Copy the full SHA
    068a4e1 View commit details
  2. Merge pull request #165 from zamu87/master

    Fix PHP 8.1 warning with sentinel
    colinmollenhour authored Jun 20, 2022
    Copy the full SHA
    30915e6 View commit details

Commits on Jul 5, 2022

  1. Copy the full SHA
    c0fca0b View commit details
  2. Copy the full SHA
    f5d8553 View commit details

Commits on Aug 11, 2022

  1. Copy the full SHA
    933c6ab View commit details

Commits on Aug 12, 2022

  1. Merge pull request #169 from shiftedreality/fix-auth

    Add username to auth params
    colinmollenhour authored Aug 12, 2022
    Copy the full SHA
    6661e3f View commit details

Commits on Dec 29, 2022

  1. Handle LOADING exception during read. (#171)

    Handle LOADING state when reading from slave by reading from master and when reading from master by retrying after 1 second wait.
    colinmollenhour authored Dec 29, 2022
    Copy the full SHA
    841d59e View commit details

Commits on Jan 18, 2023

  1. Copy the full SHA
    fe7b9a2 View commit details
  2. Copy the full SHA
    f91db67 View commit details
  3. Copy the full SHA
    38cc1d4 View commit details
  4. Replace DEL commands with UNLINK. (#160)

    Co-authored-by: Colin Mollenhour <colin@mollenhour.com>
    jonashrem and colinmollenhour authored Jan 18, 2023
    Copy the full SHA
    d87ca37 View commit details
  5. Copy the full SHA
    dd4fe9b View commit details
  6. Copy the full SHA
    6bc6f63 View commit details
  7. Copy the full SHA
    3fc3e91 View commit details

Commits on Oct 25, 2023

  1. Enable use_lua by default.

    Lua mode has proven to work best and has been supported in all non-eol versions of Redis for a very long time so it is now the default.
    colinmollenhour authored Oct 25, 2023
    Copy the full SHA
    dc2fd4f View commit details

Commits on Dec 21, 2023

  1. Copy the full SHA
    d403f44 View commit details

Commits on Aug 20, 2024

  1. Copy the full SHA
    c2e14be View commit details
Showing with 706 additions and 640 deletions.
  1. +50 −0 .github/workflows/php.yml
  2. +3 −0 .gitignore
  3. +21 −0 .php-cs-fixer.dist.php
  4. +344 −266 Cm/Cache/Backend/Redis.php
  5. +2 −0 Dockerfile
  6. +2 −1 LICENSE
  7. +46 −34 README.md
  8. +12 −2 composer.json
  9. +1 −1 lib/Credis
  10. +1 −1 modman
  11. +70 −63 stats.php
  12. +43 −142 tests/CommonBackendTest.php
  13. +37 −76 tests/CommonExtendedBackendTest.php
  14. +4 −3 tests/RedisBackendAutoExpiryTest.php
  15. +4 −5 tests/RedisBackendStandaloneTest.php
  16. +66 −46 tests/RedisBackendTest.php
50 changes: 50 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: PHPUnit

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

permissions:
contents: read

jobs:
test:

runs-on: ubuntu-latest

services:
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- uses: actions/checkout@v3

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run PHPUnit test suite
run: composer run-script test

- name: Run PHP CS Fixer
run: composer run-script php-cs-fixer -- --dry-run
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.basedir
vendor
composer.lock
/.php-cs-fixer.cache
21 changes: 21 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.4.0|configurator
* you can change this configuration by importing this file.
*/
$config = new PhpCsFixer\Config();
return $config
->setRules([
'@PSR12' => true,
])
->setFinder(
PhpCsFixer\Finder::create()
->in([
'Cm/',
'tests/',
])
->name('*.php')
->ignoreDotFiles(true)
->ignoreVCS(true)
);
610 changes: 344 additions & 266 deletions Cm/Cache/Backend/Redis.php

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM php:8.1-alpine
COPY --from=composer /usr/bin/composer /usr/bin/composer
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ modification, are permitted provided that the following conditions are met:
* The name of Colin Mollenhour may not be used to endorse or promote products
derived from this software without specific prior written permission.

* The class name must remain as Cm_Cache_Backend_Redis.
* If any files are modified, you must cause the modified files to carry prominent
notices stating that you changed the files and the date of any change.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
80 changes: 46 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
# Zend_Cache backend using Redis with full support for tags

This Zend_Cache backend allows you to use a Redis server as a central cache storage. Tags are fully supported
without the use of TwoLevels cache so this backend is great for use on a single machine or in a cluster.
This `Zend_Cache` backend allows you to use a Redis server as a central cache storage. Tags are fully supported
without the use of `TwoLevels` cache so this backend is great for use on a single machine or in a cluster.
Works with any Zend Framework project including all versions of Magento!

## FEATURES
# FEATURES

- Uses the [phpredis PECL extension](https://github.com/nicolasff/phpredis) for best performance (requires **master** branch or tagged version newer than Aug 19 2011).
- Falls back to standalone PHP if phpredis isn't available using the [Credis](https://github.com/colinmollenhour/credis) library.
- Tagging is fully supported, implemented using the Redis "set" and "hash" datatypes for efficient tag management.
- Tagging is fully supported, implemented using the Redis "set" and "hash" data types for efficient tag management.
- Key expiration is handled automatically by Redis.
- Supports unix socket connection for even better performance on a single machine.
- Supports configurable compression for memory savings. Can choose between gzip, lzf and snappy and can change configuration without flushing cache.
- Uses transactions to prevent race conditions between saves, cleans or removes causing unexpected results.
- Supports a configurable "auto expiry lifetime" which, if set, will be used as the TTL when the key otherwise wouldn't expire. In combination with "auto expiry refresh on load" offers a more sane cache management strategy for Magento's `Enterprise_PageCache` module.
- __Unit tested!__

## REQUIREMENTS
# REQUIREMENTS

As this backend uses [Credis](https://github.com/colinmollenhour/credis) there are no additional requirements, but for improved performance you can install [phpredis](https://github.com/nicolasff/phpredis) which is a compiled extension.

@@ -25,21 +23,28 @@ As this backend uses [Credis](https://github.com/colinmollenhour/credis) there a
* phpredis does not support setting read timeouts at the moment (see pull request #260). If you receive read errors (“read error on connection”), this
might be the reason.

## INSTALLATION (Composer)
# INSTALLATION

```
$ composer require colinmollenhour/cache-backend-redis
Add the package as a dependency to your project with Composer.

```shell
composer require colinmollenhour/cache-backend-redis
```

## INSTALLATION (Magento)
### modman

You may use the Composer installation (above) or you can install via [modman](https://github.com/colinmollenhour/modman):
It is not the recommended method, but you may install via [modman](https://github.com/colinmollenhour/modman):

* `modman clone https://github.com/colinmollenhour/Cm_Cache_Backend_Redis`
```shell
modman clone https://github.com/colinmollenhour/Cm_Cache_Backend_Redis
```

# CONFIGURATION

### Magento Configuration:
These examples assume you are using Magento, but the configuration can just be passed to the constructor as a PHP
array with the same key names as seen in the examples.

Edit app/etc/local.xml to configure:
Edit `app/etc/local.xml` to configure:

<!-- This is a child node of config/global -->
<cache>
@@ -83,8 +88,6 @@ Edit app/etc/local.xml to configure:

## High Availability and Load Balancing Support

There are two supported methods of achieving High Availability and Load Balancing with Cm_Cache_Backend_Redis.

### Redis Sentinel

You may achieve high availability and load balancing using [Redis Sentinel](http://redis.io/topics/sentinel). To enable use of Redis Sentinel the `server`
@@ -146,7 +149,7 @@ with multiple addresses separated by a comma.
</backend_options>
</cache>

## ElastiCache
### ElastiCache

The following example configuration lets you use ElastiCache Redis (cluster mode disabled) where the writes are sent to
the Primary node and reads are sent to the replicas. This lets you distribute the read traffic between the different nodes.
@@ -177,11 +180,11 @@ Previously the ElastiCache config instructions suggested setting up a `<cluster>
and is no longer supported. The config is still parsed and loaded for backwards-compatibility but chooses a random slave
to read from rather than using md5 hash of the keys.

## RELATED / TUNING
# TUNING

- The recommended "maxmemory-policy" is "volatile-lru". All tag metadata is non-volatile so it is
- The recommended "maxmemory-policy" is "volatile-lru". All tag metadata is non-volatile, so it is
recommended to use key expirations unless non-volatile keys are absolutely necessary so that tag
data cannot get evicted. So, be sure that the "maxmemory" is high enough to accommodate all of
data cannot get evicted. So, be sure that the "maxmemory" is high enough to accommodate all
the tag data and non-volatile data with enough room left for the volatile key data as well.
- Automatic cleaning is optional and not recommended since it is slow and uses lots of memory.
- Occasional (e.g. once a day) garbage collection is recommended if the entire cache is infrequently cleared and
@@ -197,7 +200,9 @@ to read from rather than using md5 hash of the keys.
- Monitor your redis cache statistics with my modified [munin plugin](https://gist.github.com/1177716).
- Enable persistent connections. Make sure that if you have multiple configurations connecting the persistent
string is unique for each configuration so that "select" commands don't cause conflicts.
- Use the `stats.php` script to inspect your cache to find oversized or wasteful cache tags.
- Increase your server's `lua-time-limit` if you are getting "BUSY" errors. This setting can also cause Redis Sentinel
to invoke fail-overs when you would probably prefer to let the Lua script finish and have clients wait a little longer.
- Use the `stats.php` script to inspect your cache to find over-sized or wasteful cache tags.

### Example Garbage Collection Script (Magento)

@@ -210,20 +215,27 @@ to read from rather than using md5 hash of the keys.
// uncomment this for Magento Enterprise Edition
// Enterprise_PageCache_Model_Cache::getCacheInstance()->getFrontend()->getBackend()->clean('old');

## Release Notes

- March 2017: Added support for Redis Sentinel and loading from slaves. Thanks @Xon for the help!
- Sometime in 2013: Ceased updating these release notes...
- November 19, 2012: Added read_timeout option. (Feature only supported in standalone mode, will be supported by phpredis when pull request #260 is merged)
- October 29, 2012: Added support for persistent connections. (Thanks samm-git!)
- October 12, 2012: Improved memory usage and efficiency of garbage collection and updated recommendation.
- September 17, 2012: Added connect_retries option (default: 1) to prevent errors from random connection failures.
- July 10, 2012: Added password authentication support.
- Mar 1, 2012: Using latest Credis_Client which adds auto-reconnect for standalone mode.
- Feb 15, 2012: Changed from using separate keys for data, tags and mtime to a single hash per key.
- Nov 10, 2011: Changed from using phpredis and redisent to Credis (which wraps phpredis). Implemented pipelining.
# DEVELOPMENT

Please feel free to send Pull Requests to give back your improvements to the community!

You can run the unit tests locally with just Docker installed using a simple alias:

```shell
alias cm-cache-backend-redis='docker run --rm -it -e REDIS_SERVER=host.docker.internal -u $(id -u):$(id -g) -v ${COMPOSER_HOME:-$HOME/.composer}:/tmp -v $(pwd):/app --workdir /app cm-cache-backend-redis'
docker build . -t cm-cache-backend-redis
```

Then start a Redis server, install Composer dependencies and run tests like so:
```shell
docker run --rm -d -p 6379 --name cm-cache-backend-redis redis --maxmemory 20m --maxmemory-policy noeviction
cm-cache-backend-redis composer install
cm-cache-backend-redis composer run-script test
cm-cache-backend-redis composer run-script php-cs-fixer -- --dry-run
```

```
@copyright Copyright (c) 2012 Colin Mollenhour (http://colin.mollenhour.com)
@copyright Copyright (c) 2022 Colin Mollenhour
This project is licensed under the "New BSD" license (see source).
```
14 changes: 12 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name":"colinmollenhour/cache-backend-redis",
"type":"magento-module",
"license":"BSD-3-Clause",
"license":"BSD-3-Clause-Modification",
"homepage":"https://github.com/colinmollenhour/Cm_Cache_Backend_Redis",
"description":"Zend_Cache backend using Redis with full support for tags.",
"authors":[
@@ -10,11 +10,21 @@
}
],
"require":{
"colinmollenhour/credis": "*"
"colinmollenhour/credis": "^1.14"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"phpunit/phpunit": "^9",
"zf1s/zend-cache": "~1.15"
},
"autoload": {
"classmap": [
"Cm/Cache/Backend/Redis.php"
]
},
"scripts": {
"test": "vendor/bin/phpunit tests",
"test-performance": "PERFORMANCE=1 vendor/bin/phpunit tests --filter testLargePayloadLoop",
"php-cs-fixer": "vendor/bin/php-cs-fixer fix --diff"
}
}
2 changes: 1 addition & 1 deletion modman
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Cm/Cache/Backend/* app/code/community/Cm/Cache/Backend/
Cm/Cache/Backend/Redis.php app/code/community/Cm/Cache/Backend/Redis.php
lib/* lib/
133 changes: 70 additions & 63 deletions stats.php
Original file line number Diff line number Diff line change
@@ -1,88 +1,95 @@
<?php

require __DIR__.'/vendor/autoload.php';

$server = 'tcp://127.0.0.1:6379';
$db = 0;
$limit = 20;
array_shift($argv);
while($arg = array_shift($argv)) {
switch($arg) {
case '--db': $db = intval(array_shift($argv)); break;
case '--server': $server = array_shift($argv); break;
case '--limit': $limit = array_shift($argv); break;
default: die("Unrecognized argument '$arg'.\nUsage: path/to/stats.php [--server tcp://127.0.0.1:6378] [--db 0] [--limit 20]\n");
}
while ($arg = array_shift($argv)) {
switch($arg) {
case '--db': $db = intval(array_shift($argv));
break;
case '--server': $server = array_shift($argv);
break;
case '--limit': $limit = array_shift($argv);
break;
default: die("Unrecognized argument '$arg'.\nUsage: path/to/stats.php [--server tcp://127.0.0.1:6378] [--db 0] [--limit 20]\n");
}
}

require __DIR__.'/lib/Credis/Client.php';
require './lib/Zend/Cache/Backend/Interface.php';
require './lib/Zend/Cache/Backend/ExtendedInterface.php';
require './lib/Zend/Cache/Backend.php';
require __DIR__.'/Cm/Cache/Backend/Redis.php';

$client = new Credis_Client($server);
$client->select($db);

$tagStats = array();
foreach($client->sMembers(Cm_Cache_Backend_Redis::SET_TAGS) as $tag) {
if (preg_match('/^\w{3}_MAGE$/', $tag)) continue;
$ids = $client->sMembers(Cm_Cache_Backend_Redis::PREFIX_TAG_IDS . $tag);
$tagSizes = array();
$missing = 0;
foreach ($ids as $id) {
$data = $client->hGet(Cm_Cache_Backend_Redis::PREFIX_KEY.$id, Cm_Cache_Backend_Redis::FIELD_DATA);
$size = strlen($data);
if ($size) $tagSizes[] = $size;
else $missing++;
}
if ($tagSizes) {
$tagStats[$tag] = array(
'count' => count($tagSizes),
'min' => min($tagSizes),
'max' => max($tagSizes),
'avg size' => array_sum($tagSizes) / count($tagSizes),
'total size' => array_sum($tagSizes),
'missing' => $missing,
);
}
foreach ($client->sMembers(Cm_Cache_Backend_Redis::SET_TAGS) as $tag) {
if (preg_match('/^\w{3}_MAGE$/', $tag)) {
continue;
}
$ids = $client->sMembers(Cm_Cache_Backend_Redis::PREFIX_TAG_IDS . $tag);
$tagSizes = array();
$missing = 0;
foreach ($ids as $id) {
$data = $client->hGet(Cm_Cache_Backend_Redis::PREFIX_KEY.$id, Cm_Cache_Backend_Redis::FIELD_DATA);
$size = strlen($data);
if ($size) {
$tagSizes[] = $size;
} else {
$missing++;
}
}
if ($tagSizes) {
$tagStats[$tag] = array(
'count' => count($tagSizes),
'min' => min($tagSizes),
'max' => max($tagSizes),
'avg size' => array_sum($tagSizes) / count($tagSizes),
'total size' => array_sum($tagSizes),
'missing' => $missing,
);
}
}

function _format_bytes($a_bytes)
{
if ($a_bytes < 1024) {
return $a_bytes .' B';
} elseif ($a_bytes < 1048576) {
return round($a_bytes / 1024, 4) .' KB';
} else {
return round($a_bytes / 1048576, 4) . ' MB';
}
if ($a_bytes < 1024) {
return $a_bytes .' B';
} elseif ($a_bytes < 1048576) {
return round($a_bytes / 1024, 4) .' KB';
} else {
return round($a_bytes / 1048576, 4) . ' MB';
}
}

function printStats($data, $key, $limit) {
echo "Top $limit tags by ".ucwords($key)."\n";
echo "------------------------------------------------------------------------------------\n";
$sort = array();
foreach ($data as $tag => $stats) {
$sort[$tag] = $stats[$key];
}
array_multisort($sort, SORT_DESC, $data);
$i = 0;
$fmt = "%-40s| %-8s| %-15s| %-15s\n";
printf($fmt, 'Tag', 'Count', 'Avg Size', 'Total Size');
foreach ($data as $tag => $stats) {
$tag = substr($tag, 4);
if (++$i > $limit) break;
$avg = _format_bytes($stats['avg size']);
$total = _format_bytes($stats['total size']);
printf($fmt, $tag, $stats['count'], $avg, $total);
}
echo "\n";
function printStats($data, $key, $limit)
{
echo "Top $limit tags by ".ucwords($key)."\n";
echo "------------------------------------------------------------------------------------\n";
$sort = array();
foreach ($data as $tag => $stats) {
$sort[$tag] = $stats[$key];
}
array_multisort($sort, SORT_DESC, $data);
$i = 0;
$fmt = "%-40s| %-8s| %-15s| %-15s\n";
printf($fmt, 'Tag', 'Count', 'Avg Size', 'Total Size');
foreach ($data as $tag => $stats) {
$tag = substr($tag, 4);
if (++$i > $limit) {
break;
}
$avg = _format_bytes($stats['avg size']);
$total = _format_bytes($stats['total size']);
printf($fmt, $tag, $stats['count'], $avg, $total);
}
echo "\n";
}

// Top 20 by total size
printStats($tagStats, 'total size', $limit, true);
printStats($tagStats, 'total size', $limit);

// Top 20 by average size
printStats($tagStats, 'avg size', $limit, true);
printStats($tagStats, 'avg size', $limit);

// Top 20 by count
printStats($tagStats, 'count', $limit, true);
printStats($tagStats, 'count', $limit);
185 changes: 43 additions & 142 deletions tests/CommonBackendTest.php
Original file line number Diff line number Diff line change
@@ -1,55 +1,24 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: CommonBackendTest.php 23775 2011-03-01 17:25:24Z ralph $
*/

declare(strict_types=1);
use PHPUnit\Framework\TestCase;



/**
* @category Zend
* @package Zend_Cache
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @group Zend_Cache
*/
abstract class Zend_Cache_CommonBackendTest extends PHPUnit_Framework_TestCase {

protected $_instance;
abstract class CommonBackendTest extends TestCase
{
protected Cm_Cache_Backend_Redis $_instance;
protected $_className;
protected $_root;

public function __construct($name = null, array $data = array(), $dataName = '')
{
$this->_className = $name;
$this->_root = dirname(__FILE__);
date_default_timezone_set('UTC');
parent::__construct($name, $data, $dataName);
}

public function setUp($notag = false)
public function setUp($noTag = false): void
{
$this->mkdir();
$this->_instance->setDirectives(array('logging' => true));
if ($notag) {
$this->_instance->setDirectives(array('logging' => false));
if ($noTag) {
$this->_instance->save('bar : data to cache', 'bar');
$this->_instance->save('bar2 : data to cache', 'bar2');
$this->_instance->save('bar3 : data to cache', 'bar3');
@@ -60,226 +29,158 @@ public function setUp($notag = false)
}
}

public function mkdir()
public function tearDown(): void
{
@mkdir($this->getTmpDir());
$this->_instance->clean();
}

public function rmdir()
public function testConstructorBadOption(): void
{
$tmpDir = $this->getTmpDir(false);
foreach (glob("$tmpDir*") as $dirname) {
@rmdir($dirname);
}
$this->expectException('Zend_Cache_Exception');
new Cm_Cache_Backend_Redis(array(1 => 'bar'));
}

public function getTmpDir($date = true)
public function testSetDirectivesBadArgument(): void
{
$suffix = '';
if ($date) {
$suffix = date('mdyHis');
}
if (is_writeable($this->_root)) {
return $this->_root . DIRECTORY_SEPARATOR . 'zend_cache_tmp_dir_' . $suffix;
} else {
if (getenv('TMPDIR')){
return getenv('TMPDIR') . DIRECTORY_SEPARATOR . 'zend_cache_tmp_dir_' . $suffix;
} else {
die("no writable tmpdir found");
}
}
$this->expectException('Zend_Cache_Exception');
$this->_instance->setDirectives('foo');
}

public function tearDown()
{
if ($this->_instance) {
$this->_instance->clean();
}
$this->rmdir();
}

public function testConstructorCorrectCall()
{
$this->fail('PLEASE IMPLEMENT A testConstructorCorrectCall !!!');
}

public function testConstructorBadOption()
{
try {
$class = $this->_className;
$test = new $class(array(1 => 'bar'));
} catch (Zend_Cache_Exception $e) {
return;
}
$this->fail('Zend_Cache_Exception was expected but not thrown');
}

public function testSetDirectivesCorrectCall()
{
$this->_instance->setDirectives(array('lifetime' => 3600, 'logging' => true));
}

public function testSetDirectivesBadArgument()
{
try {
$this->_instance->setDirectives('foo');
} catch (Zend_Cache_Exception $e) {
return;
}
$this->fail('Zend_Cache_Exception was expected but not thrown');
}

public function testSetDirectivesBadDirective()
public function testSetDirectivesBadDirective(): void
{
// A bad directive (not known by a specific backend) is possible
// => so no exception here
$this->expectNotToPerformAssertions();
$this->_instance->setDirectives(array('foo' => true, 'lifetime' => 3600));
}

public function testSetDirectivesBadDirective2()
public function testSetDirectivesBadDirective2(): void
{
try {
$this->_instance->setDirectives(array('foo' => true, 12 => 3600));
} catch (Zend_Cache_Exception $e) {
return;
}
$this->fail('Zend_Cache_Exception was expected but not thrown');
$this->expectException('Zend_Cache_Exception');
$this->_instance->setDirectives(array('foo' => true, 12 => 3600));
}

public function testSaveCorrectCall()
public function testSaveCorrectCall(): void
{
$res = $this->_instance->save('data to cache', 'foo', array('tag1', 'tag2'));
$this->assertTrue($res);
}

public function testSaveWithNullLifeTime()
public function testSaveWithNullLifeTime(): void
{
$this->_instance->setDirectives(array('lifetime' => null));
$res = $this->_instance->save('data to cache', 'foo', array('tag1', 'tag2'));
$this->assertTrue($res);
}

public function testSaveWithSpecificLifeTime()
public function testSaveWithSpecificLifeTime(): void
{
$this->_instance->setDirectives(array('lifetime' => 3600));
$res = $this->_instance->save('data to cache', 'foo', array('tag1', 'tag2'), 10);
$this->assertTrue($res);
}

public function testRemoveCorrectCall()
public function testRemoveCorrectCall(): void
{
$this->assertTrue($this->_instance->remove('bar'));
$this->assertFalse($this->_instance->test('bar'));
$this->assertFalse($this->_instance->remove('barbar'));
$this->assertFalse($this->_instance->test('barbar'));
}

public function testTestWithAnExistingCacheId()
public function testTestWithAnExistingCacheId(): void
{
$res = $this->_instance->test('bar');
if (!$res) {
$this->fail('test() return false');
}
if (!($res > 999999)) {
$this->fail('test() return an incorrect integer');
}
return;
$this->assertNotEmpty($res);
$this->assertGreaterThan(999999, $res);
}

public function testTestWithANonExistingCacheId()
public function testTestWithANonExistingCacheId(): void
{
$this->assertFalse($this->_instance->test('barbar'));
}

public function testTestWithAnExistingCacheIdAndANullLifeTime()
public function testTestWithAnExistingCacheIdAndANullLifeTime(): void
{
$this->_instance->setDirectives(array('lifetime' => null));
$res = $this->_instance->test('bar');
if (!$res) {
$this->fail('test() return false');
}
if (!($res > 999999)) {
$this->fail('test() return an incorrect integer');
}
return;
$this->assertNotEmpty($res);
$this->assertGreaterThan(999999, $res);
}

public function testGetWithANonExistingCacheId()
public function testGetWithANonExistingCacheId(): void
{
$this->assertFalse($this->_instance->load('barbar'));
}

public function testGetWithAnExistingCacheId()
public function testGetWithAnExistingCacheId(): void
{
$this->assertEquals('bar : data to cache', $this->_instance->load('bar'));
}

public function testGetWithAnExistingCacheIdAndUTFCharacters()
public function testGetWithAnExistingCacheIdAndUTFCharacters(): void
{
$data = '"""""' . "'" . '\n' . 'ééééé';
$this->_instance->save($data, 'foo');
$this->assertEquals($data, $this->_instance->load('foo'));
}

public function testGetWithAnExpiredCacheId()
public function testGetWithAnExpiredCacheId(): void
{
$this->_instance->___expire('bar');
$this->_instance->setDirectives(array('lifetime' => -1));
$this->assertFalse($this->_instance->load('bar'));
$this->assertEquals('bar : data to cache', $this->_instance->load('bar', true));
}

public function testCleanModeAll()
public function testCleanModeAll(): void
{
$this->assertTrue($this->_instance->clean('all'));
$this->assertFalse($this->_instance->test('bar'));
$this->assertFalse($this->_instance->test('bar2'));
}

public function testCleanModeOld()
public function testCleanModeOld(): void
{
$this->_instance->___expire('bar2');
$this->assertTrue($this->_instance->clean('old'));
$this->assertTrue($this->_instance->test('bar') > 999999);
$this->assertFalse($this->_instance->test('bar2'));
}

public function testCleanModeMatchingTags()
public function testCleanModeMatchingTags(): void
{
$this->assertTrue($this->_instance->clean('matchingTag', array('tag3')));
$this->assertFalse($this->_instance->test('bar'));
$this->assertFalse($this->_instance->test('bar2'));
}

public function testCleanModeMatchingTags2()
public function testCleanModeMatchingTags2(): void
{
$this->assertTrue($this->_instance->clean('matchingTag', array('tag3', 'tag4')));
$this->assertFalse($this->_instance->test('bar'));
$this->assertTrue($this->_instance->test('bar2') > 999999);
}

public function testCleanModeNotMatchingTags()
public function testCleanModeNotMatchingTags(): void
{
$this->assertTrue($this->_instance->clean('notMatchingTag', array('tag3')));
$this->assertTrue($this->_instance->test('bar') > 999999);
$this->assertTrue($this->_instance->test('bar2') > 999999);
}

public function testCleanModeNotMatchingTags2()
public function testCleanModeNotMatchingTags2(): void
{
$this->assertTrue($this->_instance->clean('notMatchingTag', array('tag4')));
$this->assertTrue($this->_instance->test('bar') > 999999);
$this->assertFalse($this->_instance->test('bar2'));
}

public function testCleanModeNotMatchingTags3()
public function testCleanModeNotMatchingTags3(): void
{
$this->assertTrue($this->_instance->clean('notMatchingTag', array('tag4', 'tag1')));
$this->assertTrue($this->_instance->test('bar') > 999999);
$this->assertTrue($this->_instance->test('bar2') > 999999);
$this->assertFalse($this->_instance->test('bar3'));
}

}


113 changes: 37 additions & 76 deletions tests/CommonExtendedBackendTest.php
Original file line number Diff line number Diff line change
@@ -1,76 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: CommonExtendedBackendTest.php 23775 2011-03-01 17:25:24Z ralph $
*/

/**
* @see Zend_Cache_CommonBackendTest
*/
require_once 'CommonBackendTest.php';

/**
* @category Zend
* @package Zend_Cache
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @group Zend_Cache
*/
class Zend_Cache_CommonExtendedBackendTest extends Zend_Cache_CommonBackendTest {
require_once 'vendor/autoload.php';
require_once 'CommonBackendTest.php';

abstract class CommonExtendedBackendTest extends CommonBackendTest
{
private $_capabilities;

public function __construct($name = null, array $data = array(), $dataName = '')
{
parent::__construct($name);
}

public function setUp($notag = false)
public function setUp($noTag = false): void
{
parent::setUp($notag);
parent::setUp($noTag);
$this->_capabilities = $this->_instance->getCapabilities();
}

public function testGetFillingPercentage()
public function testGetFillingPercentage(): void
{
$res = $this->_instance->getFillingPercentage();
$this->assertTrue(is_integer($res));
$this->assertTrue($res >= 0);
$this->assertTrue($res <= 100);
}

public function testGetFillingPercentageOnEmptyBackend()
public function testGetFillingPercentageOnEmptyBackend(): void
{
$this->_instance->setDirectives(array('logging' => false)); // ???
$this->_instance->clean(Zend_Cache::CLEANING_MODE_ALL);
$this->_instance->clean();
$res = $this->_instance->getFillingPercentage();
$this->_instance->setDirectives(array('logging' => true)); // ???
$this->assertTrue(is_integer($res));
$this->assertTrue($res >= 0);
$this->assertTrue($res <= 100);
}

public function testGetIds()
public function testGetIds(): void
{
if (!($this->_capabilities['get_list'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIds();
@@ -80,24 +43,24 @@ public function testGetIds()
$this->assertTrue(in_array('bar3', $res));
}

public function testGetTags()
public function testGetTags(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getTags();
$this->assertEquals(4, count($res));
$this->assertCount(4, $res);
$this->assertTrue(in_array('tag1', $res));
$this->assertTrue(in_array('tag2', $res));
$this->assertTrue(in_array('tag3', $res));
$this->assertTrue(in_array('tag4', $res));
}

public function testGetIdsMatchingTags()
public function testGetIdsMatchingTags(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsMatchingTags(array('tag3'));
@@ -107,53 +70,53 @@ public function testGetIdsMatchingTags()
$this->assertTrue(in_array('bar3', $res));
}

public function testGetIdsMatchingTags2()
public function testGetIdsMatchingTags2(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsMatchingTags(array('tag2'));
$this->assertTrue(count($res) == 1);
$this->assertTrue(in_array('bar3', $res));
}

public function testGetIdsMatchingTags3()
public function testGetIdsMatchingTags3(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsMatchingTags(array('tag9999'));
$this->assertTrue(count($res) == 0);
$this->assertEmpty($res);
}


public function testGetIdsMatchingTags4()
public function testGetIdsMatchingTags4(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsMatchingTags(array('tag3', 'tag4'));
$this->assertTrue(count($res) == 1);
$this->assertTrue(in_array('bar', $res));
}

public function testGetIdsNotMatchingTags()
public function testGetIdsNotMatchingTags(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsNotMatchingTags(array('tag3'));
$this->assertEquals(0, count($res));
$this->assertCount(0, $res);
}

public function testGetIdsNotMatchingTags2()
public function testGetIdsNotMatchingTags2(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsNotMatchingTags(array('tag1'));
@@ -162,25 +125,25 @@ public function testGetIdsNotMatchingTags2()
$this->assertTrue(in_array('bar3', $res));
}

public function testGetIdsNotMatchingTags3()
public function testGetIdsNotMatchingTags3(): void
{
if (!($this->_capabilities['tags'])) {
# unsupported by this backend
# unsupported by this backend
return;
}
$res = $this->_instance->getIdsNotMatchingTags(array('tag1', 'tag4'));
$this->assertTrue(count($res) == 1);
$this->assertTrue(in_array('bar3', $res));
}

public function testGetMetadatas($notag = false)
public function testGetMetadatas($noTag = false)
{
$res = $this->_instance->getMetadatas('bar');
$this->assertTrue(isset($res['tags']));
$this->assertTrue(isset($res['mtime']));
$this->assertTrue(isset($res['expire']));
if ($notag) {
$this->assertTrue(count($res['tags']) == 0);
if ($noTag) {
$this->assertEmpty($res['tags']);
} else {
$this->assertTrue(count($res['tags']) == 2);
$this->assertTrue(in_array('tag3', $res['tags']));
@@ -190,17 +153,18 @@ public function testGetMetadatas($notag = false)
$this->assertTrue($res['mtime'] <= time());
}

public function testTouch()
public function testTouch(): void
{
$res = $this->_instance->getMetadatas('bar');
$this->assertGreaterThan(time(), $res['expire']);
$bool = $this->_instance->touch('bar', 30);
$this->assertTrue($bool);
$res2 = $this->_instance->getMetadatas('bar');
$this->assertEquals($res2['expire'] - $res['expire'], 30);
$this->assertGreaterThanOrEqual(29, $res2['expire'] - $res['expire']);
$this->assertTrue(($res2['mtime'] >= $res['mtime']));
}

public function testGetCapabilities()
public function testGetCapabilities(): void
{
$res = $this->_instance->getCapabilities();
$this->assertTrue(isset($res['tags']));
@@ -210,7 +174,4 @@ public function testGetCapabilities()
$this->assertTrue(isset($res['infinite_lifetime']));
$this->assertTrue(isset($res['get_list']));
}

}


7 changes: 4 additions & 3 deletions tests/RedisBackendAutoExpiryTest.php
Original file line number Diff line number Diff line change
@@ -29,19 +29,20 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

require_once 'vendor/autoload.php';
require_once 'RedisBackendTest.php';

/**
* @copyright Copyright (c) 2012 Colin Mollenhour (http://colin.mollenhour.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_RedisAutoExpiryBackendTest extends Zend_Cache_RedisBackendTest {

class RedisBackendAutoExpiryTest extends RedisBackendTest
{
protected $autoExpireLifetime = 3600;

protected $autoExpireRefreshOnLoad = 1;

public function testAutoExpiry()
public function testAutoExpiry(): void
{
$id = 'REQEST';
$data = 'foo';
9 changes: 4 additions & 5 deletions tests/RedisBackendStandaloneTest.php
Original file line number Diff line number Diff line change
@@ -29,14 +29,13 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

require_once 'RedisBackendTest.php';
require_once 'vendor/autoload.php';

/**
* @copyright Copyright (c) 2012 Colin Mollenhour (http://colin.mollenhour.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_RedisStandaloneBackendTest extends Zend_Cache_RedisBackendTest {

protected $forceStandalone = TRUE;

class RedisBackendStandaloneTest extends RedisBackendTest
{
protected $forceStandalone = true;
}
112 changes: 66 additions & 46 deletions tests/RedisBackendTest.php
Original file line number Diff line number Diff line change
@@ -28,81 +28,85 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

require_once 'app/Mage.php';
require_once 'Zend/Cache.php';
require_once 'Cm/Cache/Backend/Redis.php';
require_once 'vendor/autoload.php';
require_once 'CommonExtendedBackendTest.php';

/**
* @copyright Copyright (c) 2012 Colin Mollenhour (http://colin.mollenhour.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_RedisBackendTest extends Zend_Cache_CommonExtendedBackendTest {
class RedisBackendTest extends CommonExtendedBackendTest
{
public const LUA_MAX_C_STACK = 1000;

const LUA_MAX_C_STACK = 1000;

protected $forceStandalone = FALSE;
protected $forceStandalone = false;

protected $autoExpireLifetime = 0;

protected $autoExpireRefreshOnLoad = 0;

/** @var Cm_Cache_Backend_Redis */
protected $_instance;

public function __construct($name = null, array $data = array(), $dataName = '')
{
parent::__construct('Cm_Cache_Backend_Redis', $data, $dataName);
}

public function setUp($notag = false)
public function setUp($noTag = false): void
{
$this->_instance = new Cm_Cache_Backend_Redis(array(
'server' => '127.0.0.1',
'port' => '6379',
'server' => getenv('REDIS_SERVER') ?: 'localhost',
'port' => getenv('REDIS_PORT') ?: '6379',
'database' => '1',
'notMatchingTags' => TRUE,
'notMatchingTags' => true,
'force_standalone' => $this->forceStandalone,
'compress_threshold' => 100,
'compression_lib' => 'gzip',
'use_lua' => TRUE,
'use_lua' => true,
'lua_max_c_stack' => self::LUA_MAX_C_STACK,
'auto_expire_lifetime' => $this->autoExpireLifetime,
'auto_expire_refresh_on_load' => $this->autoExpireRefreshOnLoad,
));
$this->_instance->clean(Zend_Cache::CLEANING_MODE_ALL);
$this->_instance->clean();
$this->_instance->___scriptFlush();
parent::setUp($notag);
parent::setUp($noTag);
}

public function tearDown()
public function tearDown(): void
{
parent::tearDown();
unset($this->_instance);
}

public function testConstructorCorrectCall()
{
// nah
}

public function testGetWithAnExpiredCacheId()
public function testGetWithAnExpiredCacheId(): void
{
// not supported
$this->markTestSkipped('Getting expired data is unsupported by Redis');
}

public function testCompression()
public function testCompression(): void
{
$longString = str_repeat(md5('asd')."\r\n", 50);
$this->assertTrue($this->_instance->save($longString, 'long', array('long')));
$this->assertTrue($this->_instance->load('long') == $longString);
}

public function testExpiredCleanup()
public function testLargePayloadLoop()
{
if (getenv('PERFORMANCE')) {
$longString = file_get_contents(__FILE__);
$tags = ['one','two','three','four','five','six','seven','eight','nine','ten'];
for ($i = 0; $i < 1000; $i++) {
$this->_instance->save($longString, $tags[$i % 10], $tags);
}
$this->assertTrue(true);
} else {
$this->markTestSkipped('Skipping large payload test');
}
}

public function testExpiredCleanup(): void
{
$this->assertTrue($this->_instance->clean());
$this->assertTrue($this->_instance->save('BLAH','foo', array('TAG1', 'TAG2'), 1));
$this->assertTrue($this->_instance->save('BLAH','bar', array('TAG1', 'TAG3'), 1));
$this->assertTrue($this->_instance->save('BLAH', 'foo', array('TAG1', 'TAG2'), 1));
$this->assertTrue($this->_instance->save('BLAH', 'bar', array('TAG1', 'TAG3'), 1));
$ids = $this->_instance->getIdsMatchingAnyTags(array('TAG1','TAG2','TAG3'));
sort($ids);
$this->assertEquals(array('bar','foo'), $ids);
@@ -121,90 +125,106 @@ public function testExpiredCleanup()
$this->_instance->save('bar2 : data to cache', 'bar2', array('tag3', 'tag1'));
$this->_instance->save('bar3 : data to cache', 'bar3', array('tag2', 'tag3'));
*/
public function testGetIdsMatchingAnyTags()
public function testGetIdsMatchingAnyTags(): void
{
$res = $this->_instance->getIdsMatchingAnyTags(array('tag999'));
$this->assertEquals(0, count($res));
$this->assertCount(0, $res);
}

public function testGetIdsMatchingAnyTags2()
public function testGetIdsMatchingAnyTags2(): void
{
$res = $this->_instance->getIdsMatchingAnyTags(array('tag1', 'tag999'));
$this->assertEquals(1, count($res));
$this->assertCount(1, $res);
$this->assertTrue(in_array('bar2', $res));
}

public function testGetIdsMatchingAnyTags3()
public function testGetIdsMatchingAnyTags3(): void
{
$res = $this->_instance->getIdsMatchingAnyTags(array('tag3', 'tag999'));
$this->assertEquals(3, count($res));
$this->assertCount(3, $res);
$this->assertTrue(in_array('bar', $res));
$this->assertTrue(in_array('bar2', $res));
$this->assertTrue(in_array('bar3', $res));
}

public function testGetIdsMatchingAnyTags4()
public function testGetIdsMatchingAnyTags4(): void
{
$res = $this->_instance->getIdsMatchingAnyTags(array('tag1', 'tag4'));
$this->assertEquals(2, count($res));
$this->assertCount(2, $res);
$this->assertTrue(in_array('bar', $res));
$this->assertTrue(in_array('bar2', $res));
}

public function testCleanModeMatchingAnyTags()
public function testCleanModeMatchingAnyTags(): void
{
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('tag999'));
$this->assertTrue(!!$this->_instance->load('bar'));
$this->assertTrue(!!$this->_instance->load('bar2'));
$this->assertTrue(!!$this->_instance->load('bar3'));
}

public function testCleanModeMatchingAnyTags2()
public function testCleanModeMatchingAnyTags2(): void
{
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('tag1', 'tag999'));
$this->assertTrue(!!$this->_instance->load('bar'));
$this->assertFalse(!!$this->_instance->load('bar2'));
$this->assertTrue(!!$this->_instance->load('bar3'));
}

public function testCleanModeMatchingAnyTags3()
public function testCleanModeMatchingAnyTags3(): void
{
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('tag3', 'tag999'));
$this->assertFalse(!!$this->_instance->load('bar'));
$this->assertFalse(!!$this->_instance->load('bar2'));
$this->assertFalse(!!$this->_instance->load('bar3'));
}

public function testCleanModeMatchingAnyTags4()
public function testCleanModeMatchingAnyTags4(): void
{
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('tag1', 'tag4'));
$this->assertFalse(!!$this->_instance->load('bar'));
$this->assertFalse(!!$this->_instance->load('bar2'));
$this->assertTrue(!!$this->_instance->load('bar3'));
}

public function testCleanModeMatchingAnyTags5()
public function testCleanModeMatchingAnyTags5(): void
{
$tags = array('tag1', 'tag4');
for ($i = 0; $i < self::LUA_MAX_C_STACK*5; $i++) {
$this->_instance->save('foo', 'foo'.$i, $tags);
}
$this->assertGreaterThan(self::LUA_MAX_C_STACK, count($this->_instance->getIdsMatchingAnyTags($tags)));
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, $tags);
$this->assertEquals(0, count($this->_instance->getIdsMatchingAnyTags($tags)));
$this->assertCount(0, $this->_instance->getIdsMatchingAnyTags($tags));
}

public function testCleanModeMatchingAnyTags6()
public function testCleanModeMatchingAnyTags6(): void
{
$tags = array();
for ($i = 0; $i < self::LUA_MAX_C_STACK*5; $i++) {
$tags[] = 'baz'.$i;
}
$this->_instance->save('foo', 'foo', $tags);
$_tags = array(end($tags));
$this->assertEquals(1, count($this->_instance->getIdsMatchingAnyTags($_tags)));
$this->assertCount(1, $this->_instance->getIdsMatchingAnyTags($_tags));
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, $_tags);
$this->assertEquals(0, count($this->_instance->getIdsMatchingAnyTags($_tags)));
$this->assertCount(0, $this->_instance->getIdsMatchingAnyTags($_tags));
}

public function testScriptsCaching(): void
{
$this->_instance->___scriptFlush();
$this->assertEquals([], $this->_instance->___checkScriptsExist());

$this->_instance->save('foo', 'bar', ['x','y']);
$this->assertEquals(['save'], $this->_instance->___checkScriptsExist());

$this->_instance->___scriptFlush();
$this->_instance->clean(Zend_Cache::CLEANING_MODE_OLD);
$this->assertEquals(['garbage'], $this->_instance->___checkScriptsExist());

$this->_instance->___scriptFlush();
$this->_instance->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, ['x']);
$this->assertEquals(['clean'], $this->_instance->___checkScriptsExist());
}
}