/** * Ensures that we can put objects of various types in shared memory and * retrieve them unchanged (between processes). */ public function testInterProcessUsage() { $mem = new SharedMemory(self::$_mutex, SharedMemory::getRequiredBytes(array_values(self::$_testValues))); $bootstrapFile = realpath(__DIR__ . '/../classLoader.inc.php'); $this->assertNotFalse($bootstrapFile); $cmd = 'env phpunit --no-configuration --bootstrap=' . $bootstrapFile . ' --filter=testPutValues ' . __FILE__ . ' > /dev/null'; pclose(popen($cmd, 'r')); $this->_runTests($mem); }
/** * Handles certain setup tasks. This is the kind of thing that a * constructor would handle, but since this is an abstract class and I want * child classes to be free to accept any arguments they want, I'm not * using a constructor here. */ private function _setupInstance() { if (!self::$_testedGenericSettings) { \PFXUtils::validateSettings(self::$_SETTINGS, self::$_SETTING_TESTS); self::_buildDefaultHTTPActionMap(); self::$_validator = new \Validator(); } /* If there is an exception type configured, validate that it really exists. Otherwise default to RuntimeException. */ if ($this->_EXCEPTION_TYPE) { if (!class_exists($this->_EXCEPTION_TYPE) || !is_a($this->_EXCEPTION_TYPE, 'Exception', true)) { throw new \Exception('Exception types registered in descendants of this ' . 'class must be valid Exception subclasses.'); } } else { $this->_EXCEPTION_TYPE = 'RuntimeException'; } if ($this->_responseFormat && array_key_exists($this->_responseFormat, self::$_STANDARD_PARSE_CALLBACKS)) { $callbackData = self::$_STANDARD_PARSE_CALLBACKS[$this->_responseFormat]; $callback = array_shift($callbackData); $this->_registerParseCallback($callback, $callbackData); } self::$_validator->number($this->_responseTries, 'The number of attempts to use when connecting to API URLs ' . 'must be a non-zero integer.', \Validator::ASSERT_INT_DEFAULT); self::$_validator->number($this->_repeatPauseInterval, 'The number of seconds to wait before repeating an API ' . 'request must be a positive integer.', \Validator::ASSERT_INT | \Validator::ASSERT_POSITIVE); if ($this->_requestDelayInterval !== null) { self::$_validator->number($this->_requestDelayInterval, 'Delay intervals must be positive integers.', \Validator::ASSERT_INT | \Validator::ASSERT_POSITIVE); /* In order to observe this delay across processes, we need to have a mutex and use shared memory. */ try { if (!$this->_mutex) { $this->_mutex = new \Mutex($this); } /* We will be keeping track of a millisecond timestamp, which means 13 digits. */ $allocBytes = \SharedMemory::getRequiredBytes(array(1000000000000)); $this->_shmSegment = new \SharedMemory($this->_mutex, $allocBytes); } catch (\Exception $e) { throw new $this->_EXCEPTION_TYPE('Caught error while configuring shared memory segment.', null, $e); } /* Not only do we need to keep track of the delay interval, but we also need a variable name that reflects the specific subclass for which we are tracking this interval. */ $this->_lastRequestTimeVarName = 'req' . get_class($this); } foreach (self::$_HTTP_RESPONSE_DEFAULT_MAP as $code => $action) { /* If the child has already registered certain actions in any of these positions, skip them. */ if (!array_key_exists($code, $this->_httpResponseActionMap)) { $this->_httpResponseActionMap[$code] = $action; } } $this->_instanceSetupComplete = true; }