TestUtil.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\util;
12 
20 
21 /**
22  * TestUtil provides helper methods for testing wCMF functionality.
23  *
24  * @author ingo herwig <ingo@wemove.com>
25  */
26 class TestUtil {
27 
28  /**
29  * Set up the wcmf framework. The method makes the following assumptions
30  * about file locations:
31  * - main configuration in $configPath.'config.ini'
32  * - optional additional configuration in $configPath.'test.ini'
33  * - logging configuration in $configPath.'log.ini'
34  * @param $configPath The path to the configuration directory
35  */
36  public static function initFramework($configPath) {
37  if (!file_exists($configPath) || is_file($configPath)) {
38  throw new \Exception('Configuration path '.$configPath.' is not a directory. '.
39  'Did you forget to generate code from the model?');
40  }
41 
42  // setup logging
43  $logger = new MonologFileLogger('main', $configPath.'log.ini');
44  LogManager::configure($logger);
45 
46  // setup configuration
47  $configuration = new InifileConfiguration($configPath);
48  $configuration->addConfiguration('config.ini');
49  $configuration->addConfiguration('test.ini');
50 
51  // setup object factory
52  ObjectFactory::configure(new DefaultFactory($configuration));
53  ObjectFactory::registerInstance('configuration', $configuration);
54 
55  $cache = ObjectFactory::getInstance('cache');
56  $cache->clearAll();
57  }
58 
59  /**
60  * Create the test database, if sqlite is configured
61  * @return Associative array with connection parameters and key 'connection'
62  */
63  public static function createDatabase() {
64  // get connection from first entity type
65  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
66  $types = $persistenceFacade->getKnownTypes();
67  $mapper = $persistenceFacade->getMapper($types[0]);
68  $pdo = $mapper->getConnection()->getConnection();
69 
70  // create sqlite db
71  $params = $mapper->getConnectionParams();
72  if ($params['dbType'] == 'sqlite') {
73  $numTables = $pdo->query('SELECT count(*) FROM sqlite_master WHERE type = "table"')->fetchColumn();
74  if ($numTables == 0) {
75  $schema = file_get_contents(WCMF_BASE.'install/tables_sqlite.sql');
76  $pdo->exec($schema);
77  }
78  }
79  $params['connection'] = $pdo;
80  return $params;
81  }
82 
83  /**
84  * Start the built-in webserver
85  * @param $documentRoot Document root directory
86  * @param $router Router script filename (optional)
87  */
88  public static function startServer($documentRoot, $router='') {
89  if (!is_dir($documentRoot)) {
90  throw new \Exception('Document root '.$documentRoot.' does not exist');
91  }
92  define('SERVER_HOST', 'localhost');
93  define('SERVER_PORT', 8500);
94  $cmd = sprintf('php -S %s:%d -t %s %s', SERVER_HOST, SERVER_PORT, $documentRoot, $router);
95 
96  $descriptorspec = array(
97  0 => array('pipe', 'r'), // stdin
98  1 => array('pipe', 'w'), // stdout
99  2 => array('pipe', 'a') // stderr
100  );
101  $pipes = null;
102  if (self::isWindows()) {
103  $resource = proc_open("start /B ".$cmd, $descriptorspec, $pipes);
104  }
105  else {
106  $resource = proc_open("nohup ".$cmd, $descriptorspec, $pipes);
107  }
108  if (!is_resource($resource)) {
109  throw new \Exception("Failed to execute ".$cmd);
110  }
111 
112  // kill the web server when the process ends
113  register_shutdown_function(function() use ($resource) {
114  $status = proc_get_status($resource);
115  $pid = $status['pid'];
116  if (TestUtil::isWindows()) {
117  $output = array_filter(explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$pid\"")));
118  array_pop($output);
119  $pid = end($output);
120  exec("taskkill /F /T /PID $pid");
121  }
122  else {
123  $pid = $pid+1;
124  exec("kill -9 $pid");
125  }
126  });
127  }
128 
129  /**
130  * Process a request as if it was sent to main.php
131  * @param $request The Request instance
132  * @return The Response instance (result of the last ActionMapper::processAction() call)
133  */
134  public static function simulateRequest($request) {
135  // set format
136  $request->setFormat('null');
137  $request->setResponseFormat('null');
138 
139  // reset the action mapper, because otherwise all requests would be cumulated
140  $actionMapper = ObjectFactory::getInstance('actionMapper');
141  $actionMapper->reset();
142  $response = $actionMapper->processAction($request);
143  return $response;
144  }
145 
146  /**
147  * Start a session. This is usefull for simulateRequest calls
148  * @param $user The name of the user
149  * @param $password The password of the user
150  * @return The session id. Use this as data['sid'] parameter for
151  * subsequent simulateRequest calls
152  */
153  public static function startSession($user, $password) {
154  $session = ObjectFactory::getInstance('session');
155  $authManager = ObjectFactory::getInstance('authenticationManager');
156  $authUser = $authManager->login($user, $password);
157  if ($authUser) {
158  $session->clear();
159  $session->setAuthUser($authUser);
160  }
161  else {
162  throw new \RuntimeException("Session could not be started for user '$user'");
163  }
164  return $session->getID();
165  }
166 
167  /**
168  * End a session.
169  */
170  public static function endSession() {
171  $session = ObjectFactory::getInstance('session');
172  $session->destroy();
173  $session->__destruct();
174  }
175 
176  /**
177  * Set a configuration value
178  * @see Configuration::setValue()
179  */
180  public static function setConfigValue($key, $value, $section) {
181  $config = ObjectFactory::getInstance('configuration');
182  $config->setValue($key, $value, $section);
183  }
184 
185  /**
186  * Call a protected/private method of an instance (PHP >= 5.3.2)
187  * @param $instance The instance
188  * @param $methodName The method name
189  * @param $args An array of method arguments
190  */
191  public static function callProtectedMethod($instance, $methodName, $args=null) {
192  $className = get_class($instance);
193  $class = new \ReflectionClass($className);
194  $method = $class->getMethod($methodName);
195  $method->setAccessible(true);
196 
197  if ($args != null) {
198  return $method->invokeArgs($instance, $args);
199  }
200  else {
201  return $method->invoke($instance);
202  }
203  }
204 
205  public static function getSizeof($var) {
206  $startMemory = memory_get_usage();
207  $var = unserialize(serialize($var));
208  return memory_get_usage() - $startMemory - PHP_INT_SIZE * 8;
209  }
210 
211  /**
212  * Enable the Zend_Db_Profiler for a given entity type.
213  * @param $type The entity type
214  */
215  public static function enableProfiler($type) {
216  $mapper = ObjectFactory::getInstance('persistenceFacade')->getMapper($type);
217  if ($mapper instanceof RDBMapper) {
218  $mapper->enableProfiler();
219  }
220  }
221 
222  /**
223  * Print the profile of the operations on a given entity type.
224  * The profiler must have been enabled first
225  * @param $type The entity type
226  */
227  public static function printProfile($type) {
228  $mapper = ObjectFactory::getInstance('persistenceFacade')->getMapper($type);
229  $profiler = $mapper->getProfiler();
230 
231  echo "\n";
232  foreach ($profiler->getQueryProfiles() as $query) {
233  echo $query->getElapsedSecs()."s: ".$query->getQuery()."\n";
234  }
235 
236  $totalTime = $profiler->getTotalElapsedSecs();
237  $queryCount = $profiler->getTotalNumQueries();
238  $longestTime = 0;
239  $longestQuery = null;
240  foreach ($profiler->getQueryProfiles() as $query) {
241  if ($query->getElapsedSecs() > $longestTime) {
242  $longestTime = $query->getElapsedSecs();
243  $longestQuery = $query->getQuery();
244  }
245  }
246  echo "\n";
247  echo 'Executed '.$queryCount.' queries in '.$totalTime.' seconds'."\n";
248  echo 'Average query length: '.$totalTime/$queryCount.' seconds'."\n";
249  echo 'Queries per second: '.$queryCount/$totalTime."\n";
250  echo 'Longest query length: '.$longestTime."\n";
251  echo "Longest query: \n".$longestQuery."\n";
252  }
253 
254  public static function isWindows() {
255  return (substr(php_uname(), 0, 7) == "Windows");
256  }
257 }
258 ?>
DefaultFactory is used to create service instances.
static getSizeof($var)
Definition: TestUtil.php:205
RDBMapper maps objects of one type to a relational database schema.
Definition: RDBMapper.php:49
Utility classes.
Definition: namespaces.php:97
static callProtectedMethod($instance, $methodName, $args=null)
Call a protected/private method of an instance (PHP >= 5.3.2)
Definition: TestUtil.php:191
static enableProfiler($type)
Enable the Zend_Db_Profiler for a given entity type.
Definition: TestUtil.php:215
static getInstance($name, $dynamicConfiguration=array())
static setConfigValue($key, $value, $section)
Set a configuration value.
Definition: TestUtil.php:180
static createDatabase()
Create the test database, if sqlite is configured.
Definition: TestUtil.php:63
static startServer($documentRoot, $router='')
Start the built-in webserver.
Definition: TestUtil.php:88
static startSession($user, $password)
Start a session.
Definition: TestUtil.php:153
static registerInstance($name, $instance)
static endSession()
End a session.
Definition: TestUtil.php:170
static printProfile($type)
Print the profile of the operations on a given entity type.
Definition: TestUtil.php:227
static simulateRequest($request)
Process a request as if it was sent to main.php.
Definition: TestUtil.php:134
static initFramework($configPath)
Set up the wcmf framework.
Definition: TestUtil.php:36
InifileConfiguration reads the application configuraiton from ini files.
TestUtil provides helper methods for testing wCMF functionality.
Definition: TestUtil.php:26
MonologFileLogger is a wrapper for the Monolog library that logs to files.
static configure(Factory $factory)
Configure the factory.
static configure(Logger $logger)
Configure the manager.
Definition: LogManager.php:26