| 1 |
<?php
|
| 2 |
// $Id: uts.environment.inc,v 1.14 2008/07/24 02:56:55 boombatower Exp $
|
| 3 |
/**
|
| 4 |
* @file
|
| 5 |
* Provide Usability Testing Suite testing environment functions.
|
| 6 |
*
|
| 7 |
* Copyright 2008 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
|
| 8 |
*/
|
| 9 |
|
| 10 |
/**
|
| 11 |
* Invoke the callback function in another process using a http request. This
|
| 12 |
* ensures that static variables that are messed up during environment create
|
| 13 |
* and destroy do no effect the user experience.
|
| 14 |
*
|
| 15 |
* @param string $op Operation to perform (create, destroy).
|
| 16 |
* @param string $prefix Environment prefix to perform opperation on.
|
| 17 |
* @param string $second If performing create opperation an environment
|
| 18 |
* be used as a base to copy from. If performing enabling or disabling
|
| 19 |
* modules then a comman separate list of modules can be specified.
|
| 20 |
* @return boolean Success.
|
| 21 |
*/
|
| 22 |
function uts_environment_invoke_callback($op, $prefix, $second = NULL) {
|
| 23 |
// Set internal request data for checking in other thread.
|
| 24 |
variable_set('uts_environment', "$op:$prefix:$second");
|
| 25 |
|
| 26 |
$header = array('User-Agent' => 'UTS-Environment-Callback');
|
| 27 |
$url = url("uts/environment/$op/$prefix/$second", array('absolute' => TRUE));
|
| 28 |
$result = drupal_http_request($url, $header);
|
| 29 |
|
| 30 |
// Fix any issues after creating environment.
|
| 31 |
uts_environment_rebuild_caches();
|
| 32 |
|
| 33 |
if ($result->data != 'success') {
|
| 34 |
return FALSE;
|
| 35 |
}
|
| 36 |
|
| 37 |
return TRUE;
|
| 38 |
}
|
| 39 |
|
| 40 |
/**
|
| 41 |
* Menu callback that allows environment opperation to be called
|
| 42 |
* in a seperate process via a http request.
|
| 43 |
*
|
| 44 |
* @param string $op Operation to perform (create, destroy).
|
| 45 |
* @param string $prefix Environment prefix to perform opperation on.
|
| 46 |
* @param string $second If performing create opperation an environment
|
| 47 |
* be used as a base to copy from. If performing enabling or disabling
|
| 48 |
* modules then a comman separate list of modules can be specified.
|
| 49 |
* @return Output status code.
|
| 50 |
*/
|
| 51 |
function uts_environment_callback($op, $prefix, $second = NULL) {
|
| 52 |
if (variable_get('uts_environment', '') != "$op:$prefix:$second" ||
|
| 53 |
$_SERVER['HTTP_USER_AGENT'] != 'UTS-Environment-Callback') {
|
| 54 |
// Invalid request.
|
| 55 |
exit('error');
|
| 56 |
}
|
| 57 |
variable_del('uts_environment');
|
| 58 |
|
| 59 |
if ($op == 'create') {
|
| 60 |
uts_environment_create($prefix, $second);
|
| 61 |
}
|
| 62 |
else if ($op == 'destroy') {
|
| 63 |
uts_environment_destroy($prefix);
|
| 64 |
}
|
| 65 |
else if ($op == 'enable_modules') {
|
| 66 |
uts_environment_modules($prefix, $second, TRUE);
|
| 67 |
}
|
| 68 |
else if ($op == 'disable_modules') {
|
| 69 |
uts_environment_modules($prefix, $second, FALSE);
|
| 70 |
}
|
| 71 |
else {
|
| 72 |
exit('error');
|
| 73 |
}
|
| 74 |
exit('success');
|
| 75 |
}
|
| 76 |
|
| 77 |
/**
|
| 78 |
* Create prefixed environment, including database and files directory.
|
| 79 |
*
|
| 80 |
* @param string $prefix Prefix to use for new environment.
|
| 81 |
* @param string $copy_prefix Prefix of environment to copy.
|
| 82 |
*/
|
| 83 |
function uts_environment_create($prefix, $copy_prefix = NULL) {
|
| 84 |
global $db_prefix;
|
| 85 |
|
| 86 |
// Retreive variables before database is changed.
|
| 87 |
$admin_name = variable_get('uts_environment_admin_name', 'admin');
|
| 88 |
$admin_pass = variable_get('uts_environment_admin_pass', 'utsadmin');
|
| 89 |
|
| 90 |
// Get max nid, and vid for use below.
|
| 91 |
$result = db_fetch_object(db_query('SELECT MAX(nid) AS max_nid, MAX(vid) AS max_vid FROM {node}'));
|
| 92 |
$max_nid = $result->max_nid;
|
| 93 |
$max_vid = $result->max_vid;
|
| 94 |
|
| 95 |
// Store necessary current values before switching to prefixed database.
|
| 96 |
$db_prefix_original = $db_prefix;
|
| 97 |
$clean_url_original = variable_get('clean_url', 0);
|
| 98 |
|
| 99 |
// Generate temporary prefixed database to ensure that test sessions have a clean starting point.
|
| 100 |
$db_prefix = $prefix;
|
| 101 |
include_once './includes/install.inc';
|
| 102 |
drupal_install_system();
|
| 103 |
|
| 104 |
$modules = drupal_verify_profile('default', 'en');
|
| 105 |
|
| 106 |
// Remove dblog to avoid extraneous errors while logging.
|
| 107 |
foreach ($modules as $key => $module) {
|
| 108 |
if ($module == 'dblog') {
|
| 109 |
unset($modules[$key]);
|
| 110 |
}
|
| 111 |
}
|
| 112 |
|
| 113 |
if ($copy_prefix && $copy_prefix != 'base') {
|
| 114 |
// Set prefix to base environment database.
|
| 115 |
$db_prefix = $copy_prefix;
|
| 116 |
|
| 117 |
// Load modules from study base environment, and override default list.
|
| 118 |
$modules = array();
|
| 119 |
$result = db_query("SELECT name
|
| 120 |
FROM {system}
|
| 121 |
WHERE status = %d
|
| 122 |
AND type = '%s'", 1, 'module');
|
| 123 |
while ($module = db_result($result)) {
|
| 124 |
$modules[] = $module;
|
| 125 |
}
|
| 126 |
|
| 127 |
// Return to installation database.
|
| 128 |
$db_prefix = $prefix;
|
| 129 |
}
|
| 130 |
else if ($copy_prefix == 'base') {
|
| 131 |
// Add proctor to base installations only. The menu hooks for proctor
|
| 132 |
// will not work for some reason.
|
| 133 |
$modules[] = 'uts_proctor';
|
| 134 |
}
|
| 135 |
|
| 136 |
drupal_install_modules($modules);
|
| 137 |
|
| 138 |
// Run default profile tasks.
|
| 139 |
$task = 'profile';
|
| 140 |
default_profile_tasks($task, '');
|
| 141 |
|
| 142 |
// Rebuild caches.
|
| 143 |
uts_environment_rebuild_caches();
|
| 144 |
|
| 145 |
// Restore necessary variables.
|
| 146 |
variable_set('install_profile', 'default');
|
| 147 |
variable_set('install_task', 'profile-finished');
|
| 148 |
variable_set('clean_url', $clean_url_original);
|
| 149 |
|
| 150 |
// Use temporary files directory with the same prefix as database.
|
| 151 |
variable_set('file_directory_path', file_directory_path() . '/' . $prefix);
|
| 152 |
file_check_directory(file_directory_path(), TRUE); // Create the files directory.
|
| 153 |
|
| 154 |
if ($copy_prefix && $copy_prefix != 'base') {
|
| 155 |
// Override database.
|
| 156 |
uts_environment_copy_database($copy_prefix, $prefix);
|
| 157 |
|
| 158 |
// Copy files.
|
| 159 |
uts_environment_copy_directory(file_directory_path() . "/../$copy_prefix", file_directory_path());
|
| 160 |
file_put_contents('output.txt', file_directory_path() . "/../$copy_prefix\n", FILE_APPEND);
|
| 161 |
file_put_contents('output.txt', file_directory_path() . "\n", FILE_APPEND);
|
| 162 |
}
|
| 163 |
else {
|
| 164 |
// Create admin user if base or no prefixed environment to copy from.
|
| 165 |
$pass_hash = md5($admin_pass);
|
| 166 |
db_query("UPDATE {users}
|
| 167 |
SET name = '%s',
|
| 168 |
pass = '%s',
|
| 169 |
created = %d,
|
| 170 |
access = %d,
|
| 171 |
login = %d,
|
| 172 |
status = %d
|
| 173 |
WHERE uid = %d", $admin_name, $pass_hash, time(), 0, 0, 1, 1);
|
| 174 |
}
|
| 175 |
|
| 176 |
// Rebuild caches.
|
| 177 |
uts_environment_rebuild_caches();
|
| 178 |
|
| 179 |
// Add required UTS variables.
|
| 180 |
variable_set('uts_db_prefix', $db_prefix_original);
|
| 181 |
|
| 182 |
// Restore original environment.
|
| 183 |
$db_prefix = $db_prefix_original;
|
| 184 |
uts_environment_rebuild_caches();
|
| 185 |
}
|
| 186 |
|
| 187 |
/**
|
| 188 |
* Copy one database to another, using the prefixes as different databases.
|
| 189 |
*
|
| 190 |
* @param string $original Original database prefix.
|
| 191 |
* @param string $new New database prefix.
|
| 192 |
*/
|
| 193 |
function uts_environment_copy_database($original, $new) {
|
| 194 |
file_put_contents('output.txt', '$copy_prefix => ' . $original . "\n");
|
| 195 |
$tables = uts_environment_get_like_tables(''); // Already in database prefix
|
| 196 |
foreach ($tables as $table) {
|
| 197 |
// Empty table and then copy data.
|
| 198 |
// Table variable has the prefix already in it. Format: $prefix$table.
|
| 199 |
db_query('TRUNCATE TABLE ' . $table . '');
|
| 200 |
if (!preg_match('/cache.*/', $table)) {
|
| 201 |
// Let cache tables be re-generated.
|
| 202 |
$table_original = $original . str_replace($new, '', $table);
|
| 203 |
if (!preg_match('/uts\d+user/', $table)) {
|
| 204 |
db_query('INSERT INTO ' . $table . '
|
| 205 |
SELECT *
|
| 206 |
FROM ' . $table_original);
|
| 207 |
}
|
| 208 |
else {
|
| 209 |
// Make special exception for user table. Don't import user ID 0 due to issues.
|
| 210 |
db_query('INSERT INTO ' . $table . '
|
| 211 |
SELECT *
|
| 212 |
FROM ' . $table_original . '
|
| 213 |
WHERE ' . $table_original . '.uid != 0');
|
| 214 |
}
|
| 215 |
}
|
| 216 |
file_put_contents('output.txt', "" . $table_original . "\n", FILE_APPEND);
|
| 217 |
}
|
| 218 |
|
| 219 |
// Make proctor as disabled so that it when enabled it will install menu items.
|
| 220 |
db_query("UPDATE {system}
|
| 221 |
SET status = %d
|
| 222 |
WHERE name = '%s'", 0, 'uts_proctor');
|
| 223 |
}
|
| 224 |
|
| 225 |
/**
|
| 226 |
* Destroy prefixed environment.
|
| 227 |
*
|
| 228 |
* @param string $prefix Prefix of environment to destroy.
|
| 229 |
*/
|
| 230 |
function uts_environment_destroy($prefix) {
|
| 231 |
global $db_prefix;
|
| 232 |
|
| 233 |
// Delete temporary files directory and reset files directory path.
|
| 234 |
uts_environment_destroy_directory(file_directory_path() . "/$prefix");
|
| 235 |
|
| 236 |
// Remove all prefixed tables (all the tables in the schema).
|
| 237 |
$tables = uts_environment_get_like_tables($prefix);
|
| 238 |
$ret = array();
|
| 239 |
foreach ($tables as $table) {
|
| 240 |
if (!preg_match('/^uts_.*$/', $table)) {
|
| 241 |
// UTS tables won't exist since they never have their hook_install() called.
|
| 242 |
db_drop_table($ret, $table);
|
| 243 |
}
|
| 244 |
}
|
| 245 |
}
|
| 246 |
|
| 247 |
/**
|
| 248 |
* Perform operations on modules, either enable or disable. Executes
|
| 249 |
* system_modules form to ensure that all caches are cleared properly.
|
| 250 |
*
|
| 251 |
* @param string $prefix Prefix of environment to enable modules in.
|
| 252 |
* @param string $modules Comma separated list of modules.
|
| 253 |
* @param boolean $enable Enable/Disable list of modules.
|
| 254 |
*/
|
| 255 |
function uts_environment_modules($prefix, $modules, $enable) {
|
| 256 |
global $db_prefix;
|
| 257 |
|
| 258 |
// Switch database.
|
| 259 |
$db_prefix_original = $db_prefix;
|
| 260 |
$db_prefix = $prefix;
|
| 261 |
uts_environment_rebuild_caches();
|
| 262 |
|
| 263 |
// Prepare form_state array.
|
| 264 |
$modules = explode(',', $modules);
|
| 265 |
$form_state = array();
|
| 266 |
foreach ($modules as $module) {
|
| 267 |
$form_state['values']["status[$module]"] = $enable;
|
| 268 |
}
|
| 269 |
|
| 270 |
$reserved_modules = module_list(TRUE, FALSE);
|
| 271 |
foreach ($reserved_modules as $module) {
|
| 272 |
$form_state['values']["status[$module]"] = TRUE;
|
| 273 |
}
|
| 274 |
|
| 275 |
// Execute system_modules form to ensure that all caches are cleared properly.
|
| 276 |
require_once drupal_get_path('module', 'system') . '/system.admin.inc';
|
| 277 |
drupal_execute('system_modules', $form_state);
|
| 278 |
|
| 279 |
// Changes don't get saved so force them.
|
| 280 |
if ($enable) {
|
| 281 |
module_enable($modules);
|
| 282 |
}
|
| 283 |
else {
|
| 284 |
module_disable($modules);
|
| 285 |
}
|
| 286 |
uts_environment_rebuild_caches();
|
| 287 |
|
| 288 |
// Restore original environment.
|
| 289 |
$db_prefix = $db_prefix_original;
|
| 290 |
uts_environment_rebuild_caches();
|
| 291 |
}
|
| 292 |
|
| 293 |
/**
|
| 294 |
* Refresh all caches to ensure that static variables reflect current environment.
|
| 295 |
*/
|
| 296 |
function uts_environment_rebuild_caches() {
|
| 297 |
global $conf;
|
| 298 |
cache_clear_all();
|
| 299 |
$conf = variable_init();
|
| 300 |
|
| 301 |
module_list(TRUE, FALSE);
|
| 302 |
module_rebuild_cache();
|
| 303 |
drupal_flush_all_caches();
|
| 304 |
menu_rebuild();
|
| 305 |
|
| 306 |
actions_synchronize();
|
| 307 |
}
|
| 308 |
|
| 309 |
/**
|
| 310 |
* Remove all files from specified directory and then remove directory.
|
| 311 |
*
|
| 312 |
* @param string $path Directory path.
|
| 313 |
*/
|
| 314 |
function uts_environment_destroy_directory($path) {
|
| 315 |
if (is_dir($path)) {
|
| 316 |
$files = scandir($path);
|
| 317 |
foreach ($files as $file) {
|
| 318 |
if ($file != '.' && $file != '..') {
|
| 319 |
$file_path = "$path/$file";
|
| 320 |
if (is_dir($file_path)) {
|
| 321 |
uts_environment_destroy_directory($file_path);
|
| 322 |
}
|
| 323 |
else {
|
| 324 |
file_delete($file_path);
|
| 325 |
}
|
| 326 |
}
|
| 327 |
}
|
| 328 |
rmdir($path);
|
| 329 |
}
|
| 330 |
}
|
| 331 |
|
| 332 |
/**
|
| 333 |
* Copy a directory recursively to another location.
|
| 334 |
*
|
| 335 |
* @param string $source Source directory location.
|
| 336 |
* @param string $destination Destination directory location.
|
| 337 |
*/
|
| 338 |
function uts_environment_copy_directory($source, $destination) {
|
| 339 |
if (is_dir($source)) {
|
| 340 |
if (!file_exists($destination)) {
|
| 341 |
mkdir($destination);
|
| 342 |
}
|
| 343 |
$files = scandir($source);
|
| 344 |
foreach ($files as $file) {
|
| 345 |
if ($file != '.' && $file != '..') {
|
| 346 |
$file_path = "$source/$file";
|
| 347 |
$new_path = str_replace($source . '/', $destination . '/', $file_path);
|
| 348 |
if (is_dir($file_path)) {
|
| 349 |
uts_environment_copy_directory($file_path, $new_path);
|
| 350 |
}
|
| 351 |
else {
|
| 352 |
copy($file_path, $new_path);
|
| 353 |
}
|
| 354 |
}
|
| 355 |
}
|
| 356 |
}
|
| 357 |
}
|
| 358 |
|
| 359 |
/**
|
| 360 |
* Find all tables that are like the specified base table name.
|
| 361 |
*
|
| 362 |
* @param string $base_table Base table name.
|
| 363 |
* @param boolean $count Return the table count instead of list of tables.
|
| 364 |
* @return mixed Array of matching tables or count of tables.
|
| 365 |
*/
|
| 366 |
function uts_environment_get_like_tables($base_table = 'uts', $count = FALSE) {
|
| 367 |
global $db_url, $db_prefix;
|
| 368 |
$url = parse_url($db_url);
|
| 369 |
$database = substr($url['path'], 1);
|
| 370 |
$select = $count ? 'COUNT(table_name)' : 'table_name';
|
| 371 |
$result = db_query("SELECT $select
|
| 372 |
FROM information_schema.tables
|
| 373 |
WHERE table_schema = '%s'
|
| 374 |
AND table_name LIKE '%s%'", $database, $db_prefix . $base_table);
|
| 375 |
|
| 376 |
if ($count) {
|
| 377 |
return db_result($result);
|
| 378 |
}
|
| 379 |
$tables = array();
|
| 380 |
while ($table = db_result($result)) {
|
| 381 |
$tables[] = $table;
|
| 382 |
}
|
| 383 |
return $tables;
|
| 384 |
}
|
| 385 |
|
| 386 |
/**
|
| 387 |
* Create table to list all the environments.
|
| 388 |
*
|
| 389 |
* @return string HTML output.
|
| 390 |
*/
|
| 391 |
function uts_environments() {
|
| 392 |
$environments = uts_environments_load();
|
| 393 |
$header = array(t('Prefix'), t('Name'), t('Description'), t('Operations'));
|
| 394 |
$rows = array();
|
| 395 |
foreach ($environments as $environment) {
|
| 396 |
$row = array();
|
| 397 |
$row[] = $environment->prefix;
|
| 398 |
$row[] = $environment->title;
|
| 399 |
$row[] = $environment->body;
|
| 400 |
$row[] = uts_render_operations(uts_environment_operations($environment));
|
| 401 |
|
| 402 |
$rows[] = $row;
|
| 403 |
}
|
| 404 |
|
| 405 |
if (empty($rows)) {
|
| 406 |
return t('No environments to display.');
|
| 407 |
}
|
| 408 |
return theme('table', $header, $rows);
|
| 409 |
}
|
| 410 |
|
| 411 |
/**
|
| 412 |
* Get an array containing the environment operation links.
|
| 413 |
*
|
| 414 |
* @param $environment Environment object.
|
| 415 |
* @return Array of links.
|
| 416 |
*/
|
| 417 |
function uts_environment_operations($environment) {
|
| 418 |
$links = array();
|
| 419 |
$links['environment_edit'] = array(
|
| 420 |
'title' => t('edit'),
|
| 421 |
'href' => "admin/uts/environments/$environment->nid/edit"
|
| 422 |
);
|
| 423 |
$links['environment_open'] = array(
|
| 424 |
'title' => t('open'),
|
| 425 |
'href' => "admin/uts/environments/$environment->nid/open"
|
| 426 |
);
|
| 427 |
$links['environment_delete'] = array(
|
| 428 |
'title' => t('delete'),
|
| 429 |
'href' => "admin/uts/environments/$environment->nid/delete"
|
| 430 |
);
|
| 431 |
|
| 432 |
return $links;
|
| 433 |
}
|
| 434 |
|
| 435 |
/**
|
| 436 |
* Load all environments.
|
| 437 |
*
|
| 438 |
* @return array List of environment objects.
|
| 439 |
*/
|
| 440 |
function uts_environments_load() {
|
| 441 |
$result = db_query('SELECT nid
|
| 442 |
FROM {uts_environment}');
|
| 443 |
|
| 444 |
$environments = array();
|
| 445 |
while ($environment = db_result($result)) {
|
| 446 |
$environments[] = node_load($environment);
|
| 447 |
}
|
| 448 |
return $environments;
|
| 449 |
}
|
| 450 |
|
| 451 |
/**
|
| 452 |
* Open the specified environment. Only to be used with base environments.
|
| 453 |
*
|
| 454 |
* @param object $environment Environment node object.
|
| 455 |
*/
|
| 456 |
function uts_environment_open($environment) {
|
| 457 |
uts_session_restore($environment->prefix);
|
| 458 |
drupal_goto();
|
| 459 |
}
|