mirror of
https://github.com/silverstripe/silverstripe-versionfeed
synced 2024-10-22 11:05:31 +02:00
271 lines
11 KiB
PHP
271 lines
11 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\VersionFeed\Tests;
|
|
|
|
use Page;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use SilverStripe\CMS\Model\SiteTree;
|
|
use SilverStripe\Control\Director;
|
|
use SilverStripe\Core\Config\Config;
|
|
use SilverStripe\Core\Injector\Injector;
|
|
use SilverStripe\Dev\FunctionalTest;
|
|
use SilverStripe\SiteConfig\SiteConfig;
|
|
use SilverStripe\Versioned\Versioned;
|
|
use SilverStripe\VersionFeed\Filters\CachedContentFilter;
|
|
use SilverStripe\VersionFeed\Filters\RateLimitFilter;
|
|
use SilverStripe\VersionFeed\VersionFeed;
|
|
use SilverStripe\VersionFeed\VersionFeedController;
|
|
|
|
class VersionFeedFunctionalTest extends FunctionalTest
|
|
{
|
|
protected $usesDatabase = true;
|
|
|
|
protected $baseURI = 'http://www.fakesite.test';
|
|
|
|
protected static $required_extensions = array(
|
|
'Page' => array(VersionFeed::class),
|
|
'PageController' => array(VersionFeedController::class),
|
|
);
|
|
|
|
protected $userIP;
|
|
|
|
protected function setUp()
|
|
{
|
|
Director::config()->set('alternate_base_url', $this->baseURI);
|
|
|
|
parent::setUp();
|
|
|
|
$cache = Injector::inst()->get(
|
|
CacheInterface::class . '.VersionFeedController'
|
|
);
|
|
$cache->clear();
|
|
|
|
$this->userIP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
|
|
|
|
// Enable history by default
|
|
Config::modify()->set(VersionFeed::class, 'changes_enabled', true);
|
|
Config::modify()->set(VersionFeed::class, 'allchanges_enabled', true);
|
|
|
|
// Disable caching and locking by default
|
|
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', false);
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 0);
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', false);
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_cooldown', false);
|
|
}
|
|
|
|
protected function tearDown()
|
|
{
|
|
Director::config()->set('alternate_base_url', null);
|
|
|
|
$_SERVER['REMOTE_ADDR'] = $this->userIP;
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testPublicHistory()
|
|
{
|
|
$page = $this->createPageWithChanges(array('PublicHistory' => false));
|
|
|
|
$response = $this->get($page->RelativeLink('changes'));
|
|
$this->assertEquals(
|
|
404,
|
|
$response->getStatusCode(),
|
|
'With Page\'s "PublicHistory" disabled, `changes` action response code should be 404'
|
|
);
|
|
|
|
$response = $this->get($page->RelativeLink('allchanges'));
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$this->assertFalse(
|
|
(bool)$xml->channel->item,
|
|
'With Page\'s "PublicHistory" disabled, `allchanges` action should not have an item in the channel'
|
|
);
|
|
|
|
$page = $this->createPageWithChanges(array('PublicHistory' => true));
|
|
|
|
$response = $this->get($page->RelativeLink('changes'));
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$this->assertTrue(
|
|
(bool)$xml->channel->item,
|
|
'With Page\'s "PublicHistory" enabled, `changes` action should have an item in the channel'
|
|
);
|
|
|
|
$response = $this->get($page->RelativeLink('allchanges'));
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$this->assertTrue(
|
|
(bool)$xml->channel->item,
|
|
'With "PublicHistory" enabled, `allchanges` action should have an item in the channel'
|
|
);
|
|
}
|
|
|
|
public function testRateLimiting()
|
|
{
|
|
// Re-enable locking just for this test
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 20);
|
|
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', true);
|
|
|
|
$page1 = $this->createPageWithChanges(array('PublicHistory' => true, 'Title' => 'Page1'));
|
|
$page2 = $this->createPageWithChanges(array('PublicHistory' => true, 'Title' => 'Page2'));
|
|
|
|
// Artifically set cache lock
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
|
|
$cache = Injector::inst()->get(
|
|
CacheInterface::class . '.VersionFeedController'
|
|
);
|
|
$cache->set(RateLimitFilter::CACHE_PREFIX, time() + 10);
|
|
|
|
// Test normal hit
|
|
$response = $this->get($page1->RelativeLink('changes'));
|
|
$this->assertEquals(429, $response->getStatusCode());
|
|
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
|
|
$response = $this->get($page2->RelativeLink('changes'));
|
|
$this->assertEquals(429, $response->getStatusCode());
|
|
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
|
|
|
|
// Test page specific lock
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', true);
|
|
$key = implode('_', array(
|
|
'changes',
|
|
$page1->ID,
|
|
Versioned::get_versionnumber_by_stage(SiteTree::class, 'Live', $page1->ID, false)
|
|
));
|
|
$key = RateLimitFilter::CACHE_PREFIX . '_' . md5($key);
|
|
$cache->set($key, time() + 10);
|
|
$response = $this->get($page1->RelativeLink('changes'));
|
|
$this->assertEquals(429, $response->getStatusCode());
|
|
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
|
|
$response = $this->get($page2->RelativeLink('changes'));
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', false);
|
|
|
|
// Test rate limit hit by IP
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', true);
|
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
|
$cache->set(RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'), time() + 10);
|
|
$response = $this->get($page1->RelativeLink('changes'));
|
|
$this->assertEquals(429, $response->getStatusCode());
|
|
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
|
|
|
|
// Test rate limit doesn't hit other IP
|
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.20';
|
|
$cache->set(RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'), time() + 10);
|
|
$response = $this->get($page1->RelativeLink('changes'));
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
|
|
// Restore setting
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
|
|
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 0);
|
|
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', false);
|
|
}
|
|
|
|
public function testChangesActionContainsChangesForCurrentPageOnly()
|
|
{
|
|
$page1 = $this->createPageWithChanges(array('Title' => 'Page1'));
|
|
$page2 = $this->createPageWithChanges(array('Title' => 'Page2'));
|
|
|
|
$response = $this->get($page1->RelativeLink('changes'));
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$titles = array_map(function ($item) {
|
|
return (string)$item->title;
|
|
}, $xml->xpath('//item'));
|
|
// TODO Unclear if this should contain the original version
|
|
$this->assertContains('Changed: Page1', $titles);
|
|
$this->assertNotContains('Changed: Page2', $titles);
|
|
|
|
$response = $this->get($page2->RelativeLink('changes'));
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$titles = array_map(function ($item) {
|
|
return (string)$item->title;
|
|
}, $xml->xpath('//item'));
|
|
// TODO Unclear if this should contain the original version
|
|
$this->assertNotContains('Changed: Page1', $titles);
|
|
$this->assertContains('Changed: Page2', $titles);
|
|
}
|
|
|
|
public function testAllChangesActionContainsAllChangesForAllPages()
|
|
{
|
|
$page1 = $this->createPageWithChanges(array('Title' => 'Page1'));
|
|
$page2 = $this->createPageWithChanges(array('Title' => 'Page2'));
|
|
|
|
$response = $this->get($page1->RelativeLink('allchanges'));
|
|
$xml = simplexml_load_string($response->getBody());
|
|
$titles = array_map(function ($item) {
|
|
return str_replace('Changed: ', '', (string) $item->title);
|
|
}, $xml->xpath('//item'));
|
|
$this->assertContains('Page1', $titles);
|
|
$this->assertContains('Page2', $titles);
|
|
}
|
|
|
|
protected function createPageWithChanges($seed = null)
|
|
{
|
|
$page = new Page();
|
|
|
|
$seed = array_merge(array(
|
|
'Title' => 'My Title',
|
|
'Content' => 'My Content'
|
|
), $seed);
|
|
$page->update($seed);
|
|
$page->write();
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
$page->update(array(
|
|
'Title' => 'Changed: ' . $seed['Title'],
|
|
'Content' => 'Changed: ' . $seed['Content'],
|
|
));
|
|
$page->write();
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
$page->update(array(
|
|
'Title' => 'Changed again: ' . $seed['Title'],
|
|
'Content' => 'Changed again: ' . $seed['Content'],
|
|
));
|
|
$page->write();
|
|
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
|
|
|
$page->update(array(
|
|
'Title' => 'Unpublished: ' . $seed['Title'],
|
|
'Content' => 'Unpublished: ' . $seed['Content'],
|
|
));
|
|
$page->write();
|
|
|
|
return $page;
|
|
}
|
|
|
|
/**
|
|
* Tests response code for globally disabled feeds
|
|
*/
|
|
public function testFeedViewability()
|
|
{
|
|
|
|
// Nested loop through each configuration
|
|
foreach (array(true, false) as $publicHistory_Page) {
|
|
$page = $this->createPageWithChanges(array('PublicHistory' => $publicHistory_Page, 'Title' => 'Page'));
|
|
|
|
// Test requests to 'changes' action
|
|
foreach (array(true, false) as $publicHistory_Config) {
|
|
Config::modify()->set(VersionFeed::class, 'changes_enabled', $publicHistory_Config);
|
|
$expectedResponse = $publicHistory_Page && $publicHistory_Config ? 200 : 404;
|
|
$response = $this->get($page->RelativeLink('changes'));
|
|
$this->assertEquals($expectedResponse, $response->getStatusCode());
|
|
}
|
|
|
|
// Test requests to 'allchanges' action on each page
|
|
foreach (array(true, false) as $allChanges_Config) {
|
|
foreach (array(true, false) as $allChanges_SiteConfig) {
|
|
Config::modify()->set(VersionFeed::class, 'allchanges_enabled', $allChanges_Config);
|
|
$siteConfig = SiteConfig::current_site_config();
|
|
$siteConfig->AllChangesEnabled = $allChanges_SiteConfig;
|
|
$siteConfig->write();
|
|
|
|
$expectedResponse = $allChanges_Config && $allChanges_SiteConfig ? 200 : 404;
|
|
$response = $this->get($page->RelativeLink('allchanges'));
|
|
$this->assertEquals($expectedResponse, $response->getStatusCode());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|