TestUtil.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 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 
19 
20 /**
21  * TestUtil provides helper methods for testing wCMF functionality.
22  *
23  * @author ingo herwig <ingo@wemove.com>
24  */
25 class TestUtil {
26 
27  /**
28  * Set up the wcmf framework. The method makes the following assumptions
29  * about file locations:
30  * - main configuration in $configPath.'backend.ini'
31  * - optional additional configuration in $configPath.'test.ini'
32  * - logging configuration in $configPath.'log.ini'
33  * @param $configPath The path to the configuration directory
34  */
35  public static function initFramework($configPath) {
36  if (!file_exists($configPath) || is_file($configPath)) {
37  throw new \Exception('Configuration path '.$configPath.' is not a directory. '.
38  'Did you forget to generate code from the model?');
39  }
41 
42  // setup logging
43  $logger = new MonologFileLogger('main', $configPath.'log.ini');
44  LogManager::configure($logger);
45 
46  // setup configuration
47  $cachePath = dirname($configPath).'/cache/static/config/';
48  $configuration = new InifileConfiguration($configPath, $cachePath);
49 
50  // setup object factory
51  ObjectFactory::configure(new DefaultFactory($configuration));
52  ObjectFactory::registerInstance('configuration', $configuration);
53 
54  // add configurations
55  $configuration->addConfiguration('backend.ini');
56  $configuration->addConfiguration('test.ini');
57 
58  ObjectFactory::getInstance('dynamicCache')->clearAll();
59  }
60 
61  /**
62  * Create the test database, if sqlite is configured
63  * @return Associative array with connection parameters and key 'connection'
64  */
65  public static function createDatabase() {
66  // get connection from first entity type
67  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
68  $types = $persistenceFacade->getKnownTypes();
69  $mapper = $persistenceFacade->getMapper($types[0]);
70  $pdo = $mapper->getConnection();
71 
72  // create db
73  $params = $mapper->getConnectionParams();
74  switch($params['dbType']) {
75  case 'sqlite':
76  $numTables = $pdo->query('SELECT count(*) FROM sqlite_master WHERE type = "table"')->fetchColumn();
77  if ($numTables == 0) {
78  $schema = file_get_contents(WCMF_BASE.'install/tables_sqlite.sql');
79  $pdo->exec($schema);
80  }
81  break;
82  case 'mysql':
83  $numTables = $pdo->query('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = "'.$params['dbName'].'"')->fetchColumn();
84  if ($numTables == 0) {
85  $schema = file_get_contents(WCMF_BASE.'install/tables_mysql.sql');
86  $pdo->exec($schema);
87  }
88  break;
89  }
90  $params['connection'] = $pdo;
91  return $params;
92  }
93 
94  /**
95  * Start the built-in webserver that serves the application under test
96  * @param $documentRoot Document root directory
97  * @param $router Router script filename (optional)
98  * @param $killOnExit Boolean, whether to kill the server process after script execution or not (optional, default: false)
99  */
100  public static function startServer($documentRoot, $router='', $killOnExit=false) {
101  if (!is_dir($documentRoot)) {
102  throw new \Exception('Document root '.$documentRoot.' does not exist');
103  }
104  if (!defined('TEST_SERVER')) {
105  throw new \RuntimeException("Constant TEST_SERVER not defined, e.g. define(TEST_SERVER, 'localhost:8500')");
106  }
107  $cmd = sprintf('php -S %s -t %s %s', TEST_SERVER, $documentRoot, $router);
108 
109  $descriptorspec = [
110  0 => ['pipe', 'r'], // stdin
111  1 => ['pipe', 'w'], // stdout
112  2 => ['pipe', 'a'] // stderr
113  ];
114  $pipes = null;
115  if (self::isWindows()) {
116  $resource = proc_open("start /B ".$cmd, $descriptorspec, $pipes);
117  }
118  else {
119  $resource = proc_open("nohup ".$cmd, $descriptorspec, $pipes);
120  }
121  if (!is_resource($resource)) {
122  throw new \Exception("Failed to execute ".$cmd);
123  }
124 
125  if ($killOnExit) {
126  // kill the web server when the process ends
127  register_shutdown_function(function() use ($resource) {
128  $status = proc_get_status($resource);
129  $pid = $status['pid'];
130  if (self::isWindows()) {
131  $output = array_filter(explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$pid\"")));
132  array_pop($output);
133  $pid = end($output);
134  exec("taskkill /F /T /PID $pid");
135  }
136  else {
137  $pid = $pid+1;
138  exec("kill -9 $pid");
139  }
140  });
141  }
142 
143  sleep(1);
144  }
145 
146  /**
147  * Process a request as if it was sent to main.php
148  * @param $request The Request instance
149  * @return The Response instance (result of the last ActionMapper::processAction call)
150  */
151  public static function simulateRequest($request) {
152  // set format
153  $request->setFormat('null');
154  $request->setResponseFormat('null');
155 
156  // run request
157  $actionMapper = ObjectFactory::getInstance('actionMapper');
158  $response = ObjectFactory::getNewInstance('response');
159  $actionMapper->processAction($request, $response);
160  return $response;
161  }
162 
163  /**
164  * Start a session. This is useful for simulateRequest calls
165  * @param $user The name of the user
166  * @param $password The password of the user
167  * @return The session id. Use this as data['sid'] parameter for
168  * subsequent simulateRequest calls
169  */
170  public static function startSession($user, $password) {
171  $session = ObjectFactory::getInstance('session');
172  $authManager = ObjectFactory::getInstance('authenticationManager');
173  $authUser = $authManager->login([
174  'login' => $user,
175  'password' => $password
176  ]);
177  if ($authUser) {
178  $session->clear();
179  $session->setAuthUser($authUser->getLogin());
180  }
181  else {
182  throw new \RuntimeException("Session could not be started for user '$user'");
183  }
184  return $session->getID();
185  }
186 
187  /**
188  * End a session.
189  */
190  public static function endSession() {
191  $session = ObjectFactory::getInstance('session');
192  $session->destroy();
193  $session->__destruct();
194  }
195 
196  /**
197  * Set a configuration value
198  * @see Configuration::setValue()
199  */
200  public static function setConfigValue($key, $value, $section) {
201  $config = ObjectFactory::getInstance('configuration');
202  $config->setValue($key, $value, $section);
203  }
204 
205  /**
206  * Call a protected/private method of an instance (PHP >= 5.3.2)
207  * @param $instance The instance
208  * @param $methodName The method name
209  * @param $args An array of method arguments
210  */
211  public static function callProtectedMethod($instance, $methodName, $args=null) {
212  $className = get_class($instance);
213  $class = new \ReflectionClass($className);
214  $method = $class->getMethod($methodName);
215  $method->setAccessible(true);
216 
217  if ($args != null) {
218  return $method->invokeArgs($instance, $args);
219  }
220  else {
221  return $method->invoke($instance);
222  }
223  }
224 
225  public static function getSizeof($var) {
226  $startMemory = memory_get_usage();
227  $var = unserialize(serialize($var));
228  return memory_get_usage() - $startMemory - PHP_INT_SIZE * 8;
229  }
230 
231  public static function isWindows() {
232  return (substr(php_uname(), 0, 7) == "Windows");
233  }
234 }
235 ?>
static endSession()
End a session.
Definition: TestUtil.php:190
MonologFileLogger is a wrapper for the Monolog library that logs to files.
static setConfigValue($key, $value, $section)
Set a configuration value.
Definition: TestUtil.php:200
InifileConfiguration reads the application configuration from ini files.
static startServer($documentRoot, $router='', $killOnExit=false)
Start the built-in webserver that serves the application under test.
Definition: TestUtil.php:100
Implementations of Configuration give access to the application configuration.
static getSizeof($var)
Definition: TestUtil.php:225
static configure(Logger $logger)
Configure the manager.
Definition: LogManager.php:28
static callProtectedMethod($instance, $methodName, $args=null)
Call a protected/private method of an instance (PHP >= 5.3.2)
Definition: TestUtil.php:211
static initFramework($configPath)
Set up the wcmf framework.
Definition: TestUtil.php:35
static getNewInstance($name, $dynamicConfiguration=[])
static getInstance($name, $dynamicConfiguration=[])
Utility classes.
Definition: namespaces.php:97
static createDatabase()
Create the test database, if sqlite is configured.
Definition: TestUtil.php:65
static configure(Factory $factory)
Configure the factory.
LogManager is used to retrieve Logger instances.
Definition: LogManager.php:20
DefaultFactory is used to create service instances.
TestUtil provides helper methods for testing wCMF functionality.
Definition: TestUtil.php:25
static simulateRequest($request)
Process a request as if it was sent to main.php.
Definition: TestUtil.php:151
ObjectFactory implements the service locator pattern by wrapping a Factory instance and providing sta...
static startSession($user, $password)
Start a session.
Definition: TestUtil.php:170
static registerInstance($name, $instance)