diff --git a/.travis.yml b/.travis.yml index 2217eca46f..c0a0d66628 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,13 +16,14 @@ matrix: #- LOWEST_DEPS="" #- LOWEST_DEPS="--prefer-lowest" -#services: +services: + - memcached # - mysql # - postgres sudo: required dist: trusty -# this myy fix hhvm builds according to https://docs.travis-ci.com/user/languages/php#HHVM-versions-on-Trusty +# this fixes hhvm builds according to https://docs.travis-ci.com/user/languages/php#HHVM-versions-on-Trusty group: edge before_script: diff --git a/api/src/Cache/Base.php b/api/src/Cache/Base.php index 83f2b5e0c4..1055933ced 100644 --- a/api/src/Cache/Base.php +++ b/api/src/Cache/Base.php @@ -13,6 +13,10 @@ namespace EGroupware\Api\Cache; +/*if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) +{ + require_once dirname(__DIR__).'/loader/common.php'; +}*/ use EGroupware\Api; /** @@ -183,7 +187,9 @@ abstract class Base implements Provider if (isset($_SERVER['HTTP_HOST'])) echo "
\n";
 
 	foreach(array(
+		'EGroupware\Api\Cache\Apcu' => array(),
 		'EGroupware\Api\Cache\Apc' => array(),
+		'EGroupware\Api\Cache\Memcached' => array('localhost'),
 		'EGroupware\Api\Cache\Memcache' => array('localhost'),
 		'EGroupware\Api\Cache\Files' => array('/tmp'),
 	) as $class => $param)
@@ -199,7 +205,7 @@ abstract class Base implements Provider
 			}
 			printf("$failed checks failed, $n iterations took %5.3f sec\n\n", microtime(true)-$start);
 		}
-		catch (Exception $e) {
+		catch (\Exception $e) {
 			printf($e->getMessage()."\n\n");
 		}
 	}
diff --git a/api/src/Cache/Files.php b/api/src/Cache/Files.php
index 6d4f075c5c..ee802ab7e8 100644
--- a/api/src/Cache/Files.php
+++ b/api/src/Cache/Files.php
@@ -69,7 +69,7 @@ class Files extends Base implements Provider
 	function add(array $keys,$data,$expiration=0)
 	{
 		// open only if file does NOT exist
-		if (!($ret = fopen($fname=$this->filename($keys,true), 'x')))
+		if (!($ret = @fopen($fname=$this->filename($keys,true), 'x')))
 		{
 			// if file exists, check if it is expired
 			if (file_exists($fname_expiration=$fname.self::EXPIRATION_EXTENSION) &&
diff --git a/api/src/test/CacheTest.php b/api/src/test/CacheTest.php
new file mode 100644
index 0000000000..3b0dcf946b
--- /dev/null
+++ b/api/src/test/CacheTest.php
@@ -0,0 +1,146 @@
+
+ * @copyright (c) 2016 by Ralf Becker 
+ * @author Stylite AG 
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @version $Id$
+ */
+
+namespace EGroupware\Api;
+
+require_once realpath(__DIR__.'/../loader/common.php');	// autoloader & check_load_extension
+
+use EGroupware\Api;
+use PHPUnit_Framework_TestCase as TestCase;
+use ReflectionClass;
+
+/**
+ * Mail account credentials tests
+ *
+ * Only testing en&decryption of mail passwords so far.
+ * Further tests would need database.
+ */
+class CacheTest extends TestCase
+{
+	/**
+	 * Test a caching provider
+	 *
+	 * @param string $class
+	 * @param string $params
+	 * @dataProvider cachingProvider
+	 */
+	public function testCache($class, $params=array())
+	{
+		// set us up as provider for Api\Cache class
+		$GLOBALS['egw_info']['server']['install_id'] = md5(microtime(true).__FILE__);
+		unset($GLOBALS['egw_info']['server']['cache_provider_instance']);
+		unset($GLOBALS['egw_info']['server']['cache_provider_tree']);
+		Api\Cache::$default_provider = $class;
+
+		try {
+			$provider = new $class($params);
+			$refclass = new ReflectionClass($class);
+			$methods = array();
+			foreach(array('get','set','add','mget','delete') as $name)
+			{
+				if ($name != 'mget' || is_a($provider, 'EGroupware\Api\Cache\ProviderMultiple'))
+				{
+					$methods[$name] = $refclass->getMethod($name);
+					$methods[$name]->setAccessible(true);
+				}
+			}
+
+			foreach(array(
+				Api\Cache::TREE => 'tree',
+				Api\Cache::INSTANCE => 'instance',
+			) as $level => $label)
+			{
+				$locations = array();
+				foreach(array('string',123,true,false,null,array(),array(1,2,3)) as $data)
+				{
+					$location = md5(microtime(true).$label.serialize($data));
+					$this->assertNull($methods['get']->invokeArgs($provider, array(array($level,__CLASS__,$location))),
+						"$class: $label: get_before_set");
+
+					$this->assertTrue($methods['set']->invokeArgs($provider, array(array($level,__CLASS__,$location), $data, 10)),
+						"$class: $label: set");
+
+					$this->assertEquals($data, $methods['get']->invokeArgs($provider, array(array($level,__CLASS__,$location))),
+						"$class: $label: get_after_set");
+
+					if (is_a($provider, 'EGroupware\Api\Cache\ProviderMultiple'))
+					{
+						$this->assertEquals(array($location => $data),
+							$methods['mget']->invokeArgs($provider, array(array($level,__CLASS__,array($location)))),
+							"$class: $label: mget_after_set");
+					}
+					$this->assertNotTrue($methods['add']->invokeArgs($provider, array(array($level,__CLASS__,$location), 'other-data')),
+						"$class: $label: add_after_set");
+
+					$this->assertTrue($methods['delete']->invokeArgs($provider, array(array($level,__CLASS__,$location))),
+						"$class: $label: delete");
+
+					$this->assertNull($methods['get']->invokeArgs($provider, array(array($level,__CLASS__,$location))),
+						"$class: $label: get_after_delete");
+
+					// prepare for mget of everything
+					if (is_a($provider, 'EGroupware\Api\Cache\ProviderMultiple'))
+					{
+						$locations[$location] = $data;
+						$mget_after_delete = $methods['mget']->invokeArgs($provider, array(array($level,__CLASS__,array($location))));
+						$this->assertNotTrue(isset($mget_after_delete[$location]),
+							"$class: $label: mget_after_delete['$location']");
+					}
+					elseif (!is_null($data))	// emulation can NOT distinquish between null and not set
+					{
+						$locations[$location] = $data;
+					}
+					$this->assertTrue($methods['add']->invokeArgs($provider, array(array($level,__CLASS__,$location), $data, 10)),
+						"$class: $label: add_after_delete");
+
+					$this->assertEquals($data, $methods['get']->invokeArgs($provider, array(array($level,__CLASS__,$location))),
+						"$class: $label: get_after_add");
+				}
+				// get all above in one request
+				$keys = array_keys($locations);
+				$keys_bogus = array_merge(array('not-set'),array_keys($locations),array('not-set-too'));
+				if (is_a($provider, 'EGroupware\Api\Cache\ProviderMultiple'))
+				{
+					$this->assertEquals($locations, $methods['mget']->invokeArgs($provider, array(array($level,__CLASS__,$keys))),
+						"$class: $label: mget_all");
+					$this->assertEquals($locations, $methods['mget']->invokeArgs($provider, array(array($level,__CLASS__,$keys_bogus))),
+						"$class: $label: mget_with_bogus_key");
+				}
+			}
+		}
+		catch (\Exception $e) {
+			error_log($e->getMessage());
+		}
+	}
+
+	/**
+	 * Caching provides to set with constructor parameters
+	 *
+	 * @return array of array
+	 */
+	public static function cachingProvider()
+	{
+		// create empty temp. directory
+		unlink($tmp_dir = tempnam('/tmp', 'tmp'));
+		mkdir($tmp_dir);
+
+		return array(
+			array(__NAMESPACE__.'\\Cache\\Apcu'),
+			array(__NAMESPACE__.'\\Cache\\Apc'),
+			array(__NAMESPACE__.'\\Cache\\Memcache', array('localhost')),
+			array(__NAMESPACE__.'\\Cache\\Memcached', array('localhost')),
+			array(__NAMESPACE__.'\\Cache\\Files', array($tmp_dir)),
+		);
+	}
+}
diff --git a/doc/test-cli.php b/doc/test-cli.php
index 31d047a2ef..f196bf8750 100755
--- a/doc/test-cli.php
+++ b/doc/test-cli.php
@@ -1,4 +1,4 @@
-#!/usr/bin/env php
+#!/usr/bin/env php -dapc.enable_cli=1