Mark DBDatetimeTest skipped on wrong offsets, rather than error out.

While well-intentioned, this test keeps causing problems
due to wrong timezone settings in test mode.
It shouldn't completely abort test execution,
since its more of an environment sanity check than a failed test.

Refactored to mark test skipped (regardless of offset, as long as
its greater than 5 seconds). And skipping tests altogether
on SQLite3 with new supportsTimezoneOverride() check.
SapphireTest->setUp() sets the PHP timezone to UTC (see 59547745),
but SQLite doesn't support this for a DB connection.
Since changing it on a global UNIX system level is infeasible,
the tests need to be skipped.
This commit is contained in:
Ingo Schommer 2012-07-05 16:20:18 +02:00
parent 683d420247
commit 664903433d

View File

@ -6,20 +6,16 @@ class DbDatetimeTest extends FunctionalTest {
protected $extraDataObjects = array('DbDatetimeTest_Team'); protected $extraDataObjects = array('DbDatetimeTest_Team');
private static $offset = 0; // number of seconds of php and db time are out of sync protected $offset;
private static $offset_thresholds = array( // throw an error if the offset exceeds 30 minutes
E_USER_ERROR => 1800,
E_USER_NOTICE => 5,
);
private $adapter; protected $adapter;
/** /**
* Check if dates match more or less. This takes into the account the db query * Check if dates match more or less. This takes into the account the db query
* can overflow to the next second giving offset readings. * can overflow to the next second giving offset readings.
*/ */
private function matchesRoughly($date1, $date2, $comment = '') { private function matchesRoughly($date1, $date2, $comment = '', $offset) {
$allowedDifference = 5 + abs(self::$offset); // seconds $allowedDifference = 5 + abs($offset); // seconds
$time1 = is_numeric($date1) ? $date1 : strtotime($date1); $time1 = is_numeric($date1) ? $date1 : strtotime($date1);
$time2 = is_numeric($date2) ? $date2 : strtotime($date2); $time2 = is_numeric($date2) ? $date2 : strtotime($date2);
@ -32,63 +28,67 @@ class DbDatetimeTest extends FunctionalTest {
return DB::query($query)->value(); return DB::query($query)->value();
} }
function setUpOnce() { /**
parent::setUpOnce(); * Needs to be run within a test*() context.
*
* @return Int Offset in seconds
*/
private function checkPreconditions() {
// number of seconds of php and db time are out of sync
$offset = time() - strtotime(DB::query('SELECT ' . DB::getConn()->now())->value());
$threshold = 5; // seconds
self::$offset = time() - strtotime(DB::query('SELECT ' . DB::getConn()->now())->value()); if($offset > 5) {
foreach(self::$offset_thresholds as $code => $offset) { $this->markTestSkipped('The time of the database is out of sync with the webserver by ' . abs($offset) . ' seconds.');
if(abs(self::$offset) > $offset) {
if($code == E_USER_NOTICE) {
Debug::show('The time of the database is out of sync with the webserver by ' . abs(self::$offset) . ' seconds.');
} else {
trigger_error('The time of the database is out of sync with the webserver by ' . abs(self::$offset) . ' seconds.', $code);
}
break;
} }
if(method_exists($this->adapter, 'supportsTimezoneOverride') && !$this->adapter->supportsTimezoneOverride()) {
$this->markTestSkipped("Database doesn't support timezone overrides");
} }
return $offset;
} }
function setUp() { function setUp() {
parent::setUp(); parent::setUp();
$this->adapter = DB::getConn(); $this->adapter = DB::getConn();
$this->supportDbDatetime = method_exists($this->adapter, 'datetimeIntervalClause');
} }
function testCorrectNow() { function testCorrectNow() {
if($this->supportDbDatetime) { $offset = $this->checkPreconditions();
$clause = $this->adapter->formattedDatetimeClause('now', '%U'); $clause = $this->adapter->formattedDatetimeClause('now', '%U');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->assertRegExp('/^\d*$/', (string) $result); $this->assertRegExp('/^\d*$/', (string) $result);
$this->assertTrue($result>0); $this->assertTrue($result>0);
} }
}
function testDbDatetimeFormat() { function testDbDatetimeFormat() {
if($this->supportDbDatetime) { $offset = $this->checkPreconditions();
$clause = $this->adapter->formattedDatetimeClause('1973-10-14 10:30:00', '%H:%i, %d/%m/%Y'); $clause = $this->adapter->formattedDatetimeClause('1973-10-14 10:30:00', '%H:%i, %d/%m/%Y');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, date('H:i, d/m/Y', strtotime('1973-10-14 10:30:00')), 'nice literal time'); $this->matchesRoughly($result, date('H:i, d/m/Y', strtotime('1973-10-14 10:30:00')), 'nice literal time', $offset);
$clause = $this->adapter->formattedDatetimeClause('now', '%d'); $clause = $this->adapter->formattedDatetimeClause('now', '%d');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, date('d', $this->getDbNow()), 'todays day'); $this->matchesRoughly($result, date('d', $this->getDbNow()), 'todays day', $offset);
$clause = $this->adapter->formattedDatetimeClause('"Created"', '%U') . ' AS test FROM "DbDateTimeTest_Team"'; $clause = $this->adapter->formattedDatetimeClause('"Created"', '%U') . ' AS test FROM "DbDateTimeTest_Team"';
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, strtotime(DataObject::get_one('DbDateTimeTest_Team')->Created), 'fixture ->Created as timestamp'); $this->matchesRoughly($result, strtotime(DataObject::get_one('DbDateTimeTest_Team')->Created), 'fixture ->Created as timestamp', $offset);
}
} }
function testDbDatetimeInterval() { function testDbDatetimeInterval() {
if($this->supportDbDatetime) { $offset = $this->checkPreconditions();
$clause = $this->adapter->datetimeIntervalClause('1973-10-14 10:30:00', '+18 Years'); $clause = $this->adapter->datetimeIntervalClause('1973-10-14 10:30:00', '+18 Years');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, '1991-10-14 10:30:00', 'add 18 years'); $this->matchesRoughly($result, '1991-10-14 10:30:00', 'add 18 years', $offset);
$clause = $this->adapter->datetimeIntervalClause('now', '+1 Day'); $clause = $this->adapter->datetimeIntervalClause('now', '+1 Day');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime('+1 Day', $this->getDbNow())), 'tomorrow'); $this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime('+1 Day', $this->getDbNow())), 'tomorrow', $offset);
$query = new SQLQuery(); $query = new SQLQuery();
$query->setSelect(array()); $query->setSelect(array());
@ -97,25 +97,23 @@ class DbDatetimeTest extends FunctionalTest {
->setLimit(1); ->setLimit(1);
$result = $query->execute()->value(); $result = $query->execute()->value();
$this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime(DataObject::get_one('DbDateTimeTest_Team')->Created) - 900), '15 Minutes before creating fixture'); $this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime(DataObject::get_one('DbDateTimeTest_Team')->Created) - 900), '15 Minutes before creating fixture', $offset);
}
} }
function testDbDatetimeDifference() { function testDbDatetimeDifference() {
if($this->supportDbDatetime) { $offset = $this->checkPreconditions();
$clause = $this->adapter->datetimeDifferenceClause('1974-10-14 10:30:00', '1973-10-14 10:30:00'); $clause = $this->adapter->datetimeDifferenceClause('1974-10-14 10:30:00', '1973-10-14 10:30:00');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result/86400, 365, '1974 - 1973 = 365 * 86400 sec'); $this->matchesRoughly($result/86400, 365, '1974 - 1973 = 365 * 86400 sec', $offset);
$clause = $this->adapter->datetimeDifferenceClause(date('Y-m-d H:i:s', strtotime('-15 seconds')), 'now'); $clause = $this->adapter->datetimeDifferenceClause(date('Y-m-d H:i:s', strtotime('-15 seconds')), 'now');
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, -15, '15 seconds ago - now'); $this->matchesRoughly($result, -15, '15 seconds ago - now', $offset);
$clause = $this->adapter->datetimeDifferenceClause('now', $this->adapter->datetimeIntervalClause('now', '+45 Minutes')); $clause = $this->adapter->datetimeDifferenceClause('now', $this->adapter->datetimeIntervalClause('now', '+45 Minutes'));
$result = DB::query('SELECT ' . $clause)->value(); $result = DB::query('SELECT ' . $clause)->value();
$this->matchesRoughly($result, -45 * 60, 'now - 45 minutes ahead'); $this->matchesRoughly($result, -45 * 60, 'now - 45 minutes ahead', $offset);
$query = new SQLQuery(); $query = new SQLQuery();
$query->setSelect(array()); $query->setSelect(array());
@ -126,9 +124,7 @@ class DbDatetimeTest extends FunctionalTest {
$result = $query->execute()->value(); $result = $query->execute()->value();
$lastedited = Dataobject::get_one('DbDateTimeTest_Team')->LastEdited; $lastedited = Dataobject::get_one('DbDateTimeTest_Team')->LastEdited;
$created = Dataobject::get_one('DbDateTimeTest_Team')->Created; $created = Dataobject::get_one('DbDateTimeTest_Team')->Created;
$this->matchesRoughly($result, strtotime($lastedited) - strtotime($created), 'age of HomePage record in seconds since unix epoc'); $this->matchesRoughly($result, strtotime($lastedited) - strtotime($created), 'age of HomePage record in seconds since unix epoc', $offset);
}
} }
} }