public function tearDown() { $_SERVER['HTTP_HOST'] = $this->oldhost; Config::unnest(); Email::set_mailer(new Mailer()); parent::tearDown(); }
public function tearDown() { Injector::unnest(); SS_Datetime::clear_mock_now(); Config::unnest(); parent::tearDown(); }
public function testPermissionFailureSetsCorrectFormMessages() { Config::nest(); // Controller that doesn't attempt redirections $controller = new SecurityTest_NullController(); $controller->response = new SS_HTTPResponse(); Security::permissionFailure($controller, array('default' => 'Oops, not allowed')); $this->assertEquals('Oops, not allowed', Session::get('Security.Message.message')); // Test that config values are used correctly Config::inst()->update('Security', 'default_message_set', 'stringvalue'); Security::permissionFailure($controller); $this->assertEquals('stringvalue', Session::get('Security.Message.message'), 'Default permission failure message value was not present'); Config::inst()->remove('Security', 'default_message_set'); Config::inst()->update('Security', 'default_message_set', array('default' => 'arrayvalue')); Security::permissionFailure($controller); $this->assertEquals('arrayvalue', Session::get('Security.Message.message'), 'Default permission failure message value was not present'); // Test that non-default messages work. // NOTE: we inspect the response body here as the session message has already // been fetched and output as part of it, so has been removed from the session $this->logInWithPermission('EDITOR'); Config::inst()->update('Security', 'default_message_set', array('default' => 'default', 'alreadyLoggedIn' => 'You are already logged in!')); Security::permissionFailure($controller); $this->assertContains('You are already logged in!', $controller->response->getBody(), 'Custom permission failure message was ignored'); Security::permissionFailure($controller, array('default' => 'default', 'alreadyLoggedIn' => 'One-off failure message')); $this->assertContains('One-off failure message', $controller->response->getBody(), "Message set passed to Security::permissionFailure() didn't override Config values"); Config::unnest(); }
public function tearDown() { AssetStoreTest_SpyStore::reset(); SS_Filesystem::removeFolder($this->getBasePath()); parent::tearDown(); Config::unnest(); }
public function tearDown() { while ($this->nestingLevel > 0) { $this->nestingLevel--; Config::unnest(); } parent::tearDown(); }
function getCustomerNote() { Config::nest(); Config::inst()->update('SSViewer', 'theme_enabled', true); $html = $this->renderWith("LogDispatchPhysicalOrderCustomerNote"); Config::unnest(); return $html; }
public function tearDown() { if ($this->oldProcessor) { SearchUpdater::$processor = $this->oldProcessor; } Config::unnest(); Injector::inst()->unregisterNamedObject('QueuedJobService'); FullTextSearch::force_index_list(); parent::tearDown(); }
/** * Render the object using SSViewer * @return string */ public function forPDF($variables = array()) { Config::nest(); Config::inst()->update('Director', 'alternate_base_url', static::get_render_host()); $file = $this->owner->getPDFTemplate(); $viewer = new SSViewer($file); $output = $viewer->process($this->owner, $variables); Config::unnest(); return $output; }
function testCustomGetVar() { Config::nest(); Config::inst()->update('MultiForm', 'get_var', 'SuperSessionID'); $form = $this->controller->Form(); $this->assertContains('SuperSessionID', $form::$ignored_fields, "GET var wasn't added to ignored fields"); $this->assertContains('SuperSessionID', $form->FormAction(), "Form action doesn't contain correct session \n\t\t\tID parameter"); $this->assertContains('SuperSessionID', $form->getCurrentStep()->Link(), "Form step doesn't contain correct \n\t\t\tsession ID parameter"); Config::unnest(); }
public function tearDown() { if ($this->securityWasEnabled) { SecurityToken::enable(); } else { SecurityToken::disable(); } Injector::unnest(); Config::unnest(); parent::tearDown(); }
public function testTruncatesByMaxLength() { Config::nest(); Config::inst()->update('FileTextCache_Database', 'max_content_length', 5); $cache = new FileTextCache_Database(); $file = $this->getMock('File', array('write')); $content = '0123456789'; $cache->save($file, $content); $this->assertEquals($cache->load($file), '01234'); Config::unnest(); }
public function testFieldPosition() { Config::nest(); Config::inst()->update('MetaTitleExtension', 'InsertBefore', 'MetaDescription'); $testObject = new MetaTitleExtensionTest_DataObject(); $fields = $testObject->getCMSFields(); $descriptionPosition = $fields->fieldPosition('MetaDescription'); $this->assertEquals($descriptionPosition - 1, $fields->fieldPosition('MetaTitle')); Config::inst()->update('MetaTitleExtension', 'InsertBefore', 'URLSegment'); $fields = $testObject->getCMSFields(); $urlSegmentPosition = $fields->fieldPosition('URLSegment'); $this->assertEquals($urlSegmentPosition - 1, $fields->fieldPosition('MetaTitle')); Config::unnest(); }
function getTableTitle() { $tableTitle = _t("Product.UNKNOWN", "Unknown Product"); if ($product = $this->Product()) { Config::nest(); Config::inst()->update('SSViewer', 'theme_enabled', true); $tableTitle = strip_tags($product->renderWith("ProductTableTitle")); Config::unnest(); } $updatedTableTitle = $this->extend('updateTableTitle', $tableTitle); if ($updatedTableTitle !== null && is_array($updatedTableTitle) && count($updatedTableTitle)) { $tableTitle = implode($updatedTableTitle); } return $tableTitle; }
public function testDefaultClasses() { Config::nest(); Config::inst()->update('FormField', 'default_classes', array('class1')); $field = new FormField('MyField'); $this->assertContains('class1', $field->extraClass(), 'Class list does not contain expected class'); Config::inst()->update('FormField', 'default_classes', array('class1', 'class2')); $field = new FormField('MyField'); $this->assertContains('class1 class2', $field->extraClass(), 'Class list does not contain expected class'); Config::inst()->update('FormField', 'default_classes', array('class3')); $field = new FormField('MyField'); $this->assertContains('class3', $field->extraClass(), 'Class list does not contain expected class'); $field->removeExtraClass('class3'); $this->assertNotContains('class3', $field->extraClass(), 'Class list contains unexpected class'); Config::inst()->update('TextField', 'default_classes', array('textfield-class')); $field = new TextField('MyField'); //check default classes inherit $this->assertContains('class3', $field->extraClass(), 'Class list does not contain inherited class'); $this->assertContains('textfield-class', $field->extraClass(), 'Class list does not contain expected class'); Config::unnest(); }
/** * @param string $identifier Unique identifier for this fixture type * @param array $data Map of property names to their values. * @param array $fixtures Map of fixture names to an associative array of their in-memory * identifiers mapped to their database IDs. Used to look up * existing fixtures which might be referenced in the $data attribute * via the => notation. * @return DataObject * @throws Exception */ public function createObject($identifier, $data = null, $fixtures = null) { // We have to disable validation while we import the fixtures, as the order in // which they are imported doesnt guarantee valid relations until after the import is complete. // Also disable filesystem manipulations Config::nest(); Config::inst()->update('SilverStripe\\ORM\\DataObject', 'validation_enabled', false); Config::inst()->update('File', 'update_filesystem', false); $this->invokeCallbacks('beforeCreate', array($identifier, &$data, &$fixtures)); try { $class = $this->class; $obj = DataModel::inst()->{$class}->newObject(); // If an ID is explicitly passed, then we'll sort out the initial write straight away // This is just in case field setters triggered by the population code in the next block // Call $this->write(). (For example, in FileTest) if (isset($data['ID'])) { $obj->ID = $data['ID']; // The database needs to allow inserting values into the foreign key column (ID in our case) $conn = DB::get_conn(); $baseTable = DataObject::getSchema()->baseDataTable($class); if (method_exists($conn, 'allowPrimaryKeyEditing')) { $conn->allowPrimaryKeyEditing($baseTable, true); } $obj->write(false, true); if (method_exists($conn, 'allowPrimaryKeyEditing')) { $conn->allowPrimaryKeyEditing($baseTable, false); } } // Populate defaults if ($this->defaults) { foreach ($this->defaults as $fieldName => $fieldVal) { if (isset($data[$fieldName]) && $data[$fieldName] !== false) { continue; } if (is_callable($fieldVal)) { $obj->{$fieldName} = $fieldVal($obj, $data, $fixtures); } else { $obj->{$fieldName} = $fieldVal; } } } // Populate overrides if ($data) { foreach ($data as $fieldName => $fieldVal) { // Defer relationship processing if ($obj->manyManyComponent($fieldName) || $obj->hasManyComponent($fieldName) || $obj->hasOneComponent($fieldName)) { continue; } $this->setValue($obj, $fieldName, $fieldVal, $fixtures); } } $obj->write(); // Save to fixture before relationship processing in case of reflexive relationships if (!isset($fixtures[$class])) { $fixtures[$class] = array(); } $fixtures[$class][$identifier] = $obj->ID; // Populate all relations if ($data) { foreach ($data as $fieldName => $fieldVal) { if ($obj->manyManyComponent($fieldName) || $obj->hasManyComponent($fieldName)) { $obj->write(); $parsedItems = array(); if (is_array($fieldVal)) { // handle lists of many_many relations. Each item can // specify the many_many_extraFields against each // related item. foreach ($fieldVal as $relVal) { $item = key($relVal); $id = $this->parseValue($item, $fixtures); $parsedItems[] = $id; array_shift($relVal); $obj->getManyManyComponents($fieldName)->add($id, $relVal); } } else { $items = preg_split('/ *, */', trim($fieldVal)); foreach ($items as $item) { // Check for correct format: =><relationname>.<identifier>. // Ignore if the item has already been replaced with a numeric DB identifier if (!is_numeric($item) && !preg_match('/^=>[^\\.]+\\.[^\\.]+/', $item)) { throw new InvalidArgumentException(sprintf('Invalid format for relation "%s" on class "%s" ("%s")', $fieldName, $class, $item)); } $parsedItems[] = $this->parseValue($item, $fixtures); } if ($obj->hasManyComponent($fieldName)) { $obj->getComponents($fieldName)->setByIDList($parsedItems); } elseif ($obj->manyManyComponent($fieldName)) { $obj->getManyManyComponents($fieldName)->setByIDList($parsedItems); } } } else { $hasOneField = preg_replace('/ID$/', '', $fieldName); if ($className = $obj->hasOneComponent($hasOneField)) { $obj->{$hasOneField . 'ID'} = $this->parseValue($fieldVal, $fixtures, $fieldClass); // Inject class for polymorphic relation if ($className === 'SilverStripe\\ORM\\DataObject') { $obj->{$hasOneField . 'Class'} = $fieldClass; } } } } } $obj->write(); // If LastEdited was set in the fixture, set it here if ($data && array_key_exists('LastEdited', $data)) { $this->overrideField($obj, 'LastEdited', $data['LastEdited'], $fixtures); } } catch (Exception $e) { Config::unnest(); throw $e; } Config::unnest(); $this->invokeCallbacks('afterCreate', array($obj, $identifier, &$data, &$fixtures)); return $obj; }
public function tearDown() { parent::tearDown(); Config::unnest(); }
/** * Uses {@link Director::test()} to perform in-memory HTTP requests * on the passed-in URLs. * * @param array $urls Relative URLs * @return array Result, keyed by URL. Keys: * - "statuscode": The HTTP status code * - "redirect": A redirect location (if applicable) * - "path": The filesystem path where the cache has been written */ public function publishPages($urls) { $result = array(); //nest the config so we can make changes to the config and revert easily Config::nest(); // Do we need to map these? // Detect a numerically indexed arrays if (is_numeric(join('', array_keys($urls)))) { $urls = $this->urlsToPaths($urls); } // This can be quite memory hungry and time-consuming // @todo - Make a more memory efficient publisher increase_time_limit_to(); increase_memory_limit_to(); // Set the appropriate theme for this publication batch. // This may have been set explicitly via StaticPublisher::static_publisher_theme, // or we can use the last non-null theme. $customTheme = Config::inst()->get('StaticPublisher', 'static_publisher_theme'); if ($customTheme) { Config::inst()->update('SSViewer', 'theme', $customTheme); } // Ensure that the theme that is set gets used. Config::inst()->update('SSViewer', 'theme_enabled', true); $staticBaseUrl = Config::inst()->get('FilesystemPublisher', 'static_base_url'); if ($staticBaseUrl) { Config::inst()->update('Director', 'alternate_base_url', $staticBaseUrl); } if ($this->fileExtension == 'php') { Config::inst()->update('SSViewer', 'rewrite_hash_links', 'php'); } if (Config::inst()->get('StaticPublisher', 'echo_progress')) { echo $this->class . ": Publishing to " . $staticBaseUrl . "\n"; } $files = array(); $i = 0; $totalURLs = sizeof($urls); foreach ($urls as $url => $path) { $origUrl = $url; $result[$origUrl] = array('statuscode' => null, 'redirect' => null, 'path' => null); $i++; if ($url && !is_string($url)) { user_error("Bad url:" . var_export($url, true), E_USER_WARNING); continue; } if (Config::inst()->get('StaticPublisher', 'echo_progress')) { echo " * Publishing page {$i}/{$totalURLs}: {$url}\n"; flush(); } Requirements::clear(); if ($url == "") { $url = "/"; } if (Director::is_relative_url($url)) { $url = Director::absoluteURL($url); } $response = Director::test(str_replace('+', ' ', $url)); if (!$response) { continue; } if ($response) { $result[$origUrl]['statuscode'] = $response->getStatusCode(); } Requirements::clear(); singleton('DataObject')->flushCache(); // Check for ErrorPages generating output - we want to handle this in a special way below. $isErrorPage = false; $pageObject = null; if ($response && is_object($response) && (int) $response->getStatusCode() >= 400) { $pageObject = SiteTree::get_by_link($url); if ($pageObject && $pageObject instanceof ErrorPage) { $isErrorPage = true; } } // Skip any responses with a 404 status code unless it's the ErrorPage itself. if (!$isErrorPage && is_object($response) && $response->getStatusCode() == '404') { continue; } // Generate file content // PHP file caching will generate a simple script from a template if ($this->fileExtension == 'php') { if (is_object($response)) { if ($response->getStatusCode() == '301' || $response->getStatusCode() == '302') { $content = $this->generatePHPCacheRedirection($response->getHeader('Location')); } else { $content = $this->generatePHPCacheFile($response->getBody(), HTTP::get_cache_age(), date('Y-m-d H:i:s'), $response->getHeader('Content-Type')); } } else { $content = $this->generatePHPCacheFile($response . '', HTTP::get_cache_age(), date('Y-m-d H:i:s'), $response->getHeader('Content-Type')); } // HTML file caching generally just creates a simple file } else { if (is_object($response)) { if ($response->getStatusCode() == '301' || $response->getStatusCode() == '302') { $absoluteURL = Director::absoluteURL($response->getHeader('Location')); $result[$origUrl]['redirect'] = $response->getHeader('Location'); $content = "<meta http-equiv=\"refresh\" content=\"2; URL={$absoluteURL}\">"; } else { $content = $response->getBody(); } } else { $content = $response . ''; } } if (Config::inst()->get('StaticPublisher', 'include_caching_metadata')) { $content = str_replace('</html>', sprintf("</html>\n\n<!-- %s -->", implode(" ", $this->getMetadata($url))), $content); } if (!$isErrorPage) { $files[$origUrl] = array('Content' => $content, 'Folder' => dirname($path) . '/', 'Filename' => basename($path)); } else { // Generate a static version of the error page with a standardised name, so they can be plugged // into catch-all webserver statements such as Apache's ErrorDocument. $code = (int) $response->getStatusCode(); $files[$origUrl] = array('Content' => $content, 'Folder' => dirname($path) . '/', 'Filename' => "error-{$code}.html"); } } //return config to its previous state Config::unnest(); $base = BASE_PATH . "/{$this->destFolder}"; foreach ($files as $origUrl => $file) { Filesystem::makeFolder("{$base}/{$file['Folder']}"); $path = "{$base}/{$file['Folder']}{$file['Filename']}"; $result[$origUrl]['path'] = $path; if (isset($file['Content'])) { $fh = fopen($path, "w"); fwrite($fh, $file['Content']); fclose($fh); } else { if (isset($file['Copy'])) { copy($file['Copy'], $path); } } } return $result; }
/** * Test against a theme. * * @param $themeBaseDir string - themes directory * @param $theme string - theme name * @param $callback Closure */ protected function useTestTheme($themeBaseDir, $theme, $callback) { Config::nest(); global $project; $manifest = new SS_TemplateManifest($themeBaseDir, $project, true, true); SS_TemplateLoader::instance()->pushManifest($manifest); Config::inst()->update('SSViewer', 'theme', $theme); $e = null; try { $callback(); } catch (Exception $e) { /* NOP for now, just save $e */ } // Remove all the test themes we created SS_TemplateLoader::instance()->popManifest(); Config::unnest(); if ($e) { throw $e; } }
public function tearDown() { Config::unnest(); Injector::unnest(); parent::tearDown(); }
public function testDefaultClasses() { Config::nest(); Config::inst()->update('Form', 'default_classes', array('class1')); $form = $this->getStubForm(); $this->assertContains('class1', $form->extraClass(), 'Class list does not contain expected class'); Config::inst()->update('Form', 'default_classes', array('class1', 'class2')); $form = $this->getStubForm(); $this->assertContains('class1 class2', $form->extraClass(), 'Class list does not contain expected class'); Config::inst()->update('Form', 'default_classes', array('class3')); $form = $this->getStubForm(); $this->assertContains('class3', $form->extraClass(), 'Class list does not contain expected class'); $form->removeExtraClass('class3'); $this->assertNotContains('class3', $form->extraClass(), 'Class list contains unexpected class'); Config::unnest(); }
public function testShortCodeParsedInTemplateHelpers() { $parser = ShortcodeParser::get('HTMLTextTest'); $parser->register('shortcode', function ($arguments, $content, $parser, $tagName, $extra) { return 'Replaced short code with this. <a href="home">home</a>'; }); ShortcodeParser::set_active('HTMLTextTest'); /** @var HTMLText $field */ $field = DBField::create_field('HTMLText', '<p>[shortcode]</p>'); $this->assertEquals('<p>Replaced short code with this. <a href="home">home</a></p>', $field->HTMLATT()); $this->assertEquals('%3Cp%3EReplaced+short+code+with+this.+%3Ca+href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', $field->URLATT()); $this->assertEquals('%3Cp%3EReplaced%20short%20code%20with%20this.%20%3Ca%20href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', $field->RAWURLATT()); $this->assertEquals('<p>Replaced short code with this. <a href="home">home</a></p>', $field->ATT()); $this->assertEquals('<p>Replaced short code with this. <a href="home">home</a></p>', $field->RAW()); $this->assertEquals('\\x3cp\\x3eReplaced short code with this. \\x3ca href=\\"home\\"\\x3ehome\\x3c/a\\x3e\\x3c/p\\x3e', $field->JS()); $this->assertEquals('<p>Replaced short code with this. <a href="home">home</a></p>', $field->HTML()); $this->assertEquals('<p>Replaced short code with this. <a href="home">home</a></p>', $field->XML()); $this->assertEquals('Repl...', $field->LimitCharacters(4, '...')); $this->assertEquals('Replaced...', $field->LimitCharactersToClosestWord(10, '...')); $this->assertEquals('Replaced...', $field->LimitWordCount(1, '...')); $this->assertEquals('<p>replaced short code with this. <a href="home">home</a></p>', $field->LowerCase()); $this->assertEquals('<P>REPLACED SHORT CODE WITH THIS. <A HREF="HOME">HOME</A></P>', $field->UpperCase()); $this->assertEquals('Replaced short code with this. home', $field->NoHTML()); Config::nest(); Config::inst()->update('Director', 'alternate_base_url', 'http://example.com/'); $this->assertEquals('<p>Replaced short code with this. <a href="http://example.com/home">home</a></p>', $field->AbsoluteLinks()); Config::unnest(); $this->assertEquals('Replaced short code with this.', $field->LimitSentences(1)); $this->assertEquals('Replaced short code with this.', $field->FirstSentence()); $this->assertEquals('Replaced short...', $field->Summary(2)); $this->assertEquals('Replaced short code with...', $field->BigSummary(4)); $this->assertEquals('Replaced short code with this. home[home]', $field->FirstParagraph()); $this->assertEquals('Replaced <span class="highlight">short</span> <span class="highlight">code</span> with this. home', $field->ContextSummary(500, 'short code')); ShortcodeParser::set_active('default'); }
/** * Converts the Order into HTML, based on the Order Template. * @return HTML Object **/ public function ConvertToHTML() { Config::nest(); Config::inst()->update('SSViewer', 'theme_enabled', true); $html = $this->renderWith("Order"); Config::unnest(); $html = preg_replace('/(\\s)+/', ' ', $html); return DBField::create_field('HTMLText', $html); }
public function testGetAllowedMaxFileSize() { Config::nest(); // Check the max file size uses the config values $configMaxFileSizes = array('[image]' => '1k', 'txt' => 1000); Config::inst()->update('Upload_Validator', 'default_max_file_size', $configMaxFileSizes); $v = new UploadTest_Validator(); $retrievedSize = $v->getAllowedMaxFileSize('[image]'); $this->assertEquals(1024, $retrievedSize, 'Max file size check on default values failed (config category set check)'); $retrievedSize = $v->getAllowedMaxFileSize('txt'); $this->assertEquals(1000, $retrievedSize, 'Max file size check on default values failed (config extension set check)'); // Check instance values for max file size $maxFileSizes = array('[document]' => 2000, 'txt' => '4k'); $v = new UploadTest_Validator(); $v->setAllowedMaxFileSize($maxFileSizes); $retrievedSize = $v->getAllowedMaxFileSize('[document]'); $this->assertEquals(2000, $retrievedSize, 'Max file size check on instance values failed (instance category set check)'); // Check that the instance values overwrote the default values // ie. The max file size will not exist for [image] $retrievedSize = $v->getAllowedMaxFileSize('[image]'); $this->assertFalse($retrievedSize, 'Max file size check on instance values failed (config overridden check)'); // Check a category that has not been set before $retrievedSize = $v->getAllowedMaxFileSize('[archive]'); $this->assertFalse($retrievedSize, 'Max file size check on instance values failed (category not set check)'); // Check a file extension that has not been set before $retrievedSize = $v->getAllowedMaxFileSize('mp3'); $this->assertFalse($retrievedSize, 'Max file size check on instance values failed (extension not set check)'); $retrievedSize = $v->getAllowedMaxFileSize('txt'); $this->assertEquals(4096, $retrievedSize, 'Max file size check on instance values failed (instance extension set check)'); Config::unnest(); }
public function testNest() { // Check basic config $this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo')); $this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar')); // Test nest copies data Config::nest(); $this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo')); $this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar')); // Test nested data can be updated Config::inst()->update('ConfigTest_TestNest', 'foo', 4); $this->assertEquals(4, Config::inst()->get('ConfigTest_TestNest', 'foo')); $this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar')); // Test unnest restores data Config::unnest(); $this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo')); $this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar')); }
/** * Start the actual execution of a job. * The assumption is the jobID refers to a {@link QueuedJobDescriptor} that is status set as "Queued". * * This method will continue executing until the job says it's completed * * @param int $jobId * The ID of the job to start executing * @return boolean */ public function runJob($jobId) { // first retrieve the descriptor $jobDescriptor = DataObject::get_by_id('QueuedJobDescriptor', (int) $jobId); if (!$jobDescriptor) { throw new Exception("{$jobId} is invalid"); } // now lets see whether we have a current user to run as. Typically, if the job is executing via the CLI, // we want it to actually execute as the RunAs user - however, if running via the web (which is rare...), we // want to ensure that the current user has admin privileges before switching. Otherwise, we just run it // as the currently logged in user and hope for the best // We need to use $_SESSION directly because SS ties the session to a controller that no longer exists at // this point of execution in some circumstances $originalUserID = isset($_SESSION['loggedInAs']) ? $_SESSION['loggedInAs'] : 0; $originalUser = $originalUserID ? DataObject::get_by_id('Member', $originalUserID) : null; $runAsUser = null; if (Director::is_cli() || !$originalUser || Permission::checkMember($originalUser, 'ADMIN')) { $runAsUser = $jobDescriptor->RunAs(); if ($runAsUser && $runAsUser->exists()) { // the job runner outputs content way early in the piece, meaning there'll be cookie errors // if we try and do a normal login, and we only want it temporarily... if (Controller::has_curr()) { Session::set('loggedInAs', $runAsUser->ID); } else { $_SESSION['loggedInAs'] = $runAsUser->ID; } // this is an explicit coupling brought about by SS not having // a nice way of mocking a user, as it requires session // nastiness if (class_exists('SecurityContext')) { singleton('SecurityContext')->setMember($runAsUser); } } } // set up a custom error handler for this processing $errorHandler = new JobErrorHandler(); $job = null; $broken = false; // Push a config context onto the stack for the duration of this job run. Config::nest(); if ($this->grabMutex($jobDescriptor)) { try { $job = $this->initialiseJob($jobDescriptor); // get the job ready to begin. if (!$jobDescriptor->JobStarted) { $jobDescriptor->JobStarted = date('Y-m-d H:i:s'); } else { $jobDescriptor->JobRestarted = date('Y-m-d H:i:s'); } $jobDescriptor->JobStatus = QueuedJob::STATUS_RUN; $jobDescriptor->write(); $lastStepProcessed = 0; // have we stalled at all? $stallCount = 0; if ($job->SubsiteID && class_exists('Subsite')) { Subsite::changeSubsite($job->SubsiteID); // lets set the base URL as far as Director is concerned so that our URLs are correct $subsite = DataObject::get_by_id('Subsite', $job->SubsiteID); if ($subsite && $subsite->exists()) { $domain = $subsite->domain(); $base = rtrim(Director::protocol() . $domain, '/') . '/'; Config::inst()->update('Director', 'alternate_base_url', $base); } } // while not finished while (!$job->jobFinished() && !$broken) { // see that we haven't been set to 'paused' or otherwise by another process $jobDescriptor = DataObject::get_by_id('QueuedJobDescriptor', (int) $jobId); if (!$jobDescriptor || !$jobDescriptor->exists()) { $broken = true; SS_Log::log(array('errno' => 0, 'errstr' => 'Job descriptor ' . $jobId . ' could not be found', 'errfile' => __FILE__, 'errline' => __LINE__, 'errcontext' => array()), SS_Log::ERR); break; } if ($jobDescriptor->JobStatus != QueuedJob::STATUS_RUN) { // we've been paused by something, so we'll just exit $job->addMessage(sprintf(_t('QueuedJobs.JOB_PAUSED', "Job paused at %s"), date('Y-m-d H:i:s'))); $broken = true; } if (!$broken) { try { $job->process(); } catch (Exception $e) { // okay, we'll just catch this exception for now $job->addMessage(sprintf(_t('QueuedJobs.JOB_EXCEPT', 'Job caused exception %s in %s at line %s'), $e->getMessage(), $e->getFile(), $e->getLine()), 'ERROR'); SS_Log::log($e, SS_Log::ERR); $jobDescriptor->JobStatus = QueuedJob::STATUS_BROKEN; } // now check the job state $data = $job->getJobData(); if ($data->currentStep == $lastStepProcessed) { $stallCount++; } if ($stallCount > Config::inst()->get(__CLASS__, 'stall_threshold')) { $broken = true; $job->addMessage(sprintf(_t('QueuedJobs.JOB_STALLED', "Job stalled after %s attempts - please check"), $stallCount), 'ERROR'); $jobDescriptor->JobStatus = QueuedJob::STATUS_BROKEN; } // now we'll be good and check our memory usage. If it is too high, we'll set the job to // a 'Waiting' state, and let the next processing run pick up the job. if ($this->isMemoryTooHigh()) { $job->addMessage(sprintf(_t('QueuedJobs.MEMORY_RELEASE', 'Job releasing memory and waiting (%s used)'), $this->humanReadable($this->getMemoryUsage()))); $jobDescriptor->JobStatus = QueuedJob::STATUS_WAIT; $broken = true; } // Also check if we are running too long if ($this->hasPassedTimeLimit()) { $job->addMessage(_t('QueuedJobs.TIME_LIMIT', 'Queue has passed time limit and will restart before continuing')); $jobDescriptor->JobStatus = QueuedJob::STATUS_WAIT; $broken = true; } } if ($jobDescriptor) { $this->copyJobToDescriptor($job, $jobDescriptor); $jobDescriptor->write(); } else { SS_Log::log(array('errno' => 0, 'errstr' => 'Job descriptor has been set to null', 'errfile' => __FILE__, 'errline' => __LINE__, 'errcontext' => array()), SS_Log::WARN); $broken = true; } } // a last final save. The job is complete by now if ($jobDescriptor) { $jobDescriptor->write(); } if (!$broken) { $job->afterComplete(); $jobDescriptor->cleanupJob(); } } catch (Exception $e) { // okay, we'll just catch this exception for now SS_Log::log($e, SS_Log::ERR); $jobDescriptor->JobStatus = QueuedJob::STATUS_BROKEN; $jobDescriptor->write(); $broken = true; } } $errorHandler->clear(); Config::unnest(); // okay let's reset our user if we've got an original if ($runAsUser && $originalUser) { Session::clear("loggedInAs"); if ($originalUser) { Session::set("loggedInAs", $originalUser->ID); } } return !$broken; }
/** * many_many_extraFields is allowed to have an array value, so shouldn't throw an exception */ public function testValidateModelDefinitionsPassesWithExtraFields() { Config::nest(); $object = new DataObjectTest_Team(); $method = $this->makeAccessible($object, 'validateModelDefinitions'); Config::inst()->update('DataObjectTest_Team', 'many_many_extraFields', array('Relations' => array('Price' => 'Int'))); try { $method->invoke($object); } catch (Exception $e) { Config::unnest(); $this->fail('Exception should not be thrown'); throw $e; } Config::unnest(); }
/** * Test a URL request, returning a response object. This method is the counterpart of * Director::direct() that is used in functional testing. It will execute the URL given, and * return the result as an SS_HTTPResponse object. * * @uses getControllerForURL() The rule-lookup logic is handled by this. * @uses Controller::run() Handles the page logic for a Director::direct() call. * * @param string $url The URL to visit. * @param array $postVars The $_POST & $_FILES variables. * @param array|Session $session The {@link Session} object representing the current session. * By passing the same object to multiple calls of Director::test(), you can simulate a persisted * session. * @param string $httpMethod The HTTP method, such as GET or POST. It will default to POST if * postVars is set, GET otherwise. Overwritten by $postVars['_method'] if present. * @param string $body The HTTP body. * @param array $headers HTTP headers with key-value pairs. * @param array|Cookie_Backend $cookies to populate $_COOKIE. * @param HTTP_Request $request The {@see HTTP_Request} object generated as a part of this request. * * @return SS_HTTPResponse * * @throws SS_HTTPResponse_Exception */ public static function test($url, $postVars = null, $session = array(), $httpMethod = null, $body = null, $headers = array(), $cookies = array(), &$request = null) { Config::nest(); Injector::nest(); // These are needed so that calling Director::test() does not muck with whoever is calling it. // Really, it's some inappropriate coupling and should be resolved by making less use of statics. $oldReadingMode = Versioned::get_reading_mode(); $getVars = array(); if (!$httpMethod) { $httpMethod = $postVars || is_array($postVars) ? "POST" : "GET"; } if (!$session) { $session = Injector::inst()->create('Session', array()); } $cookieJar = $cookies instanceof Cookie_Backend ? $cookies : Injector::inst()->createWithArgs('Cookie_Backend', array($cookies ?: array())); // Back up the current values of the superglobals $existingRequestVars = isset($_REQUEST) ? $_REQUEST : array(); $existingGetVars = isset($_GET) ? $_GET : array(); $existingPostVars = isset($_POST) ? $_POST : array(); $existingSessionVars = isset($_SESSION) ? $_SESSION : array(); $existingCookies = isset($_COOKIE) ? $_COOKIE : array(); $existingServer = isset($_SERVER) ? $_SERVER : array(); $existingRequirementsBackend = Requirements::backend(); Config::inst()->update('Cookie', 'report_errors', false); Requirements::set_backend(Injector::inst()->create('Requirements_Backend')); // Set callback to invoke prior to return $onCleanup = function () use($existingRequestVars, $existingGetVars, $existingPostVars, $existingSessionVars, $existingCookies, $existingServer, $existingRequirementsBackend, $oldReadingMode) { // Restore the super globals $_REQUEST = $existingRequestVars; $_GET = $existingGetVars; $_POST = $existingPostVars; $_SESSION = $existingSessionVars; $_COOKIE = $existingCookies; $_SERVER = $existingServer; Requirements::set_backend($existingRequirementsBackend); // These are needed so that calling Director::test() does not muck with whoever is calling it. // Really, it's some inappropriate coupling and should be resolved by making less use of statics Versioned::set_reading_mode($oldReadingMode); Injector::unnest(); // Restore old CookieJar, etc Config::unnest(); }; if (strpos($url, '#') !== false) { $url = substr($url, 0, strpos($url, '#')); } // Handle absolute URLs if (parse_url($url, PHP_URL_HOST)) { $bits = parse_url($url); // If a port is mentioned in the absolute URL, be sure to add that into the HTTP host if (isset($bits['port'])) { $_SERVER['HTTP_HOST'] = $bits['host'] . ':' . $bits['port']; } else { $_SERVER['HTTP_HOST'] = $bits['host']; } } // Ensure URL is properly made relative. // Example: url passed is "/ss31/my-page" (prefixed with BASE_URL), this should be changed to "my-page" $url = self::makeRelative($url); $urlWithQuerystring = $url; if (strpos($url, '?') !== false) { list($url, $getVarsEncoded) = explode('?', $url, 2); parse_str($getVarsEncoded, $getVars); } // Replace the super globals with appropriate test values $_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars); $_GET = (array) $getVars; $_POST = (array) $postVars; $_SESSION = $session ? $session->inst_getAll() : array(); $_COOKIE = $cookieJar->getAll(false); Injector::inst()->registerService($cookieJar, 'Cookie_Backend'); $_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring; $request = new SS_HTTPRequest($httpMethod, $url, $getVars, $postVars, $body); if ($headers) { foreach ($headers as $k => $v) { $request->addHeader($k, $v); } } // Pre-request filtering // @see issue #2517 $model = DataModel::inst(); $output = Injector::inst()->get('RequestProcessor')->preRequest($request, $session, $model); if ($output === false) { $onCleanup(); throw new SS_HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400); } // TODO: Pass in the DataModel $result = Director::handleRequest($request, $session, $model); // Ensure that the result is an SS_HTTPResponse object if (is_string($result)) { if (substr($result, 0, 9) == 'redirect:') { $response = new SS_HTTPResponse(); $response->redirect(substr($result, 9)); $result = $response; } else { $result = new SS_HTTPResponse($result); } } $output = Injector::inst()->get('RequestProcessor')->postRequest($request, $result, $model); if ($output === false) { $onCleanup(); throw new SS_HTTPResponse_Exception("Invalid response"); } // Return valid response $onCleanup(); return $result; }
public function tearDown() { Versioned::set_reading_mode($this->oldMode); Config::unnest(); parent::tearDown(); }
public function tearDown() { // restores the config variables Config::unnest(); parent::tearDown(); }
/** * Test against a theme. * * @param $themeBaseDir string - themes directory * @param $theme string - theme name * @param $callback Closure */ protected function useTestTheme($themeBaseDir, $theme, $callback) { Config::nest(); if (strpos($themeBaseDir, BASE_PATH) === 0) { $themeBaseDir = substr($themeBaseDir, strlen(BASE_PATH)); } SSViewer::set_themes([$themeBaseDir . '/themes/' . $theme, '$default']); $e = null; try { $callback(); } catch (Exception $e) { /* NOP for now, just save $e */ } Config::unnest(); if ($e) { throw $e; } }