/**
  * Virtual "sleep" that doesn't actually slow execution, only advances DBDateTime::now()
  *
  * @param int $minutes
  */
 protected function sleep($minutes)
 {
     $now = DBDatetime::now();
     $date = DateTime::createFromFormat('Y-m-d H:i:s', $now->getValue());
     $date->modify("+{$minutes} minutes");
     DBDatetime::set_mock_now($date->format('Y-m-d H:i:s'));
 }
 public function testAgoInFuture()
 {
     DBDatetime::set_mock_now('2000-12-31 00:00:00');
     $this->assertEquals('in 10 years', DBField::create_field('Date', '2010-12-31')->Ago(), 'Exact past match on years');
     $this->assertEquals('in 1 day', DBField::create_field('Date', '2001-01-01')->Ago(true, 1), 'Approximate past match on minutes');
     $this->assertEquals('in 24 hours', DBField::create_field('Date', '2001-01-01')->Ago(), 'Approximate past match on minutes');
     DBDatetime::clear_mock_now();
 }
 /**
  * Test that objects are correctly published recursively
  */
 public function testRecursivePublish()
 {
     /** @var VersionedOwnershipTest_Subclass $parent */
     $parent = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass1_published');
     $parentID = $parent->ID;
     $banner1 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany1_published');
     $banner2 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany2_published');
     $banner2ID = $banner2->ID;
     // Modify, Add, and Delete banners on stage
     $banner1->Title = 'Renamed Banner 1';
     $banner1->write();
     $banner2->delete();
     $banner4 = new VersionedOwnershipTest_RelatedMany();
     $banner4->Title = 'New Banner';
     $parent->Banners()->add($banner4);
     // Check state of objects before publish
     $oldLiveBanners = [['Title' => 'Related Many 1'], ['Title' => 'Related Many 2']];
     $newBanners = [['Title' => 'Renamed Banner 1'], ['Title' => 'Related Many 3'], ['Title' => 'New Banner']];
     $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)->byID($parentID);
     $this->assertDOSEquals($newBanners, $parentDraft->Banners());
     $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)->byID($parentID);
     $this->assertDOSEquals($oldLiveBanners, $parentLive->Banners());
     // On publishing of owner, all children should now be updated
     $now = DBDatetime::now();
     DBDatetime::set_mock_now($now);
     // Lock 'now' to predictable time
     $parent->publishRecursive();
     // Now check each object has the correct state
     $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)->byID($parentID);
     $this->assertDOSEquals($newBanners, $parentDraft->Banners());
     $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)->byID($parentID);
     $this->assertDOSEquals($newBanners, $parentLive->Banners());
     // Check that the deleted banner hasn't actually been deleted from the live stage,
     // but in fact has been unlinked.
     $banner2Live = Versioned::get_by_stage('VersionedOwnershipTest_RelatedMany', Versioned::LIVE)->byID($banner2ID);
     $this->assertEmpty($banner2Live->PageID);
     // Test that a changeset was created
     /** @var ChangeSet $changeset */
     $changeset = ChangeSet::get()->sort('"ChangeSet"."ID" DESC')->first();
     $this->assertNotEmpty($changeset);
     // Test that this changeset is inferred
     $this->assertTrue((bool) $changeset->IsInferred);
     $this->assertEquals("Generated by publish of 'Subclass 1' at " . $now->Nice(), $changeset->getTitle());
     // Test that this changeset contains all items
     $this->assertDOSContains([['ObjectID' => $parent->ID, 'ObjectClass' => $parent->baseClass(), 'Added' => ChangeSetItem::EXPLICITLY], ['ObjectID' => $banner1->ID, 'ObjectClass' => $banner1->baseClass(), 'Added' => ChangeSetItem::IMPLICITLY], ['ObjectID' => $banner4->ID, 'ObjectClass' => $banner4->baseClass(), 'Added' => ChangeSetItem::IMPLICITLY]], $changeset->Changes());
     // Objects that are unlinked should not need to be a part of the changeset
     $this->assertNotDOSContains([['ObjectID' => $banner2ID, 'ObjectClass' => $banner2->baseClass()]], $changeset->Changes());
 }
 public function testArchiveRelatedDataWithoutVersioned()
 {
     DBDatetime::set_mock_now('2009-01-01 00:00:00');
     $relatedData = new VersionedTest_RelatedWithoutVersion();
     $relatedData->Name = 'Related Data';
     $relatedDataId = $relatedData->write();
     $testData = new VersionedTest_DataObject();
     $testData->Title = 'Test';
     $testData->Content = 'Before Content';
     $testData->Related()->add($relatedData);
     $id = $testData->write();
     DBDatetime::set_mock_now('2010-01-01 00:00:00');
     $testData->Content = 'After Content';
     $testData->write();
     Versioned::reading_archived_date('2009-01-01 19:00:00');
     $fetchedData = VersionedTest_DataObject::get()->byId($id);
     $this->assertEquals('Before Content', $fetchedData->Content, 'We see the correct content of the older version');
     $relatedData = VersionedTest_RelatedWithoutVersion::get()->byId($relatedDataId);
     $this->assertEquals(1, $relatedData->Related()->count(), 'We have a relation, with no version table, querying it still works');
 }
 public function testDefaultAdminLockOut()
 {
     Config::inst()->update('SilverStripe\\Security\\Member', 'lock_out_after_incorrect_logins', 1);
     Config::inst()->update('SilverStripe\\Security\\Member', 'lock_out_delay_mins', 10);
     DBDatetime::set_mock_now('2016-04-18 00:00:00');
     $controller = new Security();
     $form = new Form($controller, 'Form', new FieldList(), new FieldList());
     // Test correct login
     MemberAuthenticator::authenticate(array('Email' => 'admin', 'Password' => 'wrongpassword'), $form);
     $this->assertTrue(Member::default_admin()->isLockedOut());
     $this->assertEquals(Member::default_admin()->LockedOutUntil, '2016-04-18 00:10:00');
 }
 public function testAgoInFuture()
 {
     DBDatetime::set_mock_now('2000-12-31 00:00:00');
     $this->assertEquals('in 10 years', DBField::create_field('Datetime', '2010-12-31 12:00:00')->Ago(), 'Exact past match on years');
     $this->assertEquals('in 1 hour', DBField::create_field('Datetime', '2000-12-31 1:01:05')->Ago(true, 1), 'Approximate past match on minutes, significance=1');
     $this->assertEquals('in 61 mins', DBField::create_field('Datetime', '2000-12-31 1:01:05')->Ago(), 'Approximate past match on minutes');
     DBDatetime::clear_mock_now();
 }