Skip to content

Commit

Permalink
improved Adapter, and Listener
Browse files Browse the repository at this point in the history
  • Loading branch information
kilip committed May 15, 2014
1 parent 2c52799 commit a4ac07d
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 66 deletions.
131 changes: 130 additions & 1 deletion spec/PhpGuard/Listen/ListenerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,35 @@

namespace spec\PhpGuard\Listen;

require_once __DIR__.'/MockFileSystem.php';

use PhpGuard\Listen\Adapter\AdapterInterface;
use PhpGuard\Listen\Event\ChangeSetEvent;
use PhpGuard\Listen\Event\FilesystemEvent;
use PhpGuard\Listen\Listener;
use PhpGuard\Listen\Util\PathUtil;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

use spec\PhpGuard\Listen\MockFileSystem as mfs;

class ListenerSpec extends ObjectBehavior
{
static $tmpDir;

function let()
{
mfs::mkdir(mfs::$tmpDir);
$this->alwaysNotify(true);
}

function letgo()
{
mfs::cleanDir(mfs::$tmpDir);
}

function it_is_initializable()
{
$this->shouldHaveType('PhpGuard\Listen\Listener');
Expand Down Expand Up @@ -104,7 +124,7 @@ function it_should_implement_the_PSR_LoggerAwareInterface()
$this->shouldImplement('Psr\Log\LoggerAwareInterface');
}

function its_should_log_message_with_level_debug_as_default(LoggerInterface $logger)
function it_should_log_message_with_level_debug_as_default(LoggerInterface $logger)
{
$logger->log(LogLevel::DEBUG,'message',array())
->shouldBeCalled()
Expand All @@ -118,4 +138,113 @@ function it_throws_when_starting_without_any_paths()
$this->shouldThrow('RuntimeException')
->duringStart();
}

function its_createResource_returns_SplFileInfo_object_for_the_path()
{
mfs::mkdir($root = MFS::$tmpDir.'/root');
mfs::mkdir($dir1 = $root.'/dir1/subdir');
mfs::mkdir($dir2 = $root.'/dir2/subdir');
touch($file1 = $dir1.'/file1.php');
touch($file2 = $dir2.'/file2.php');

$this->to($root.'/dir1');
$this->to($root.'/dir2');

$spl = $this->createResource($file1);
$spl->getRelativePath()
->shouldReturn('subdir');
$spl->getRelativePathname()->shouldReturn('subdir/file1.php');

$spl = $this->createResource($file2);
$spl->getRelativePath()
->shouldReturn('subdir');
$spl->getRelativePathname()->shouldReturn('subdir/file2.php');
}

function its_createResource_returns_false_if_path_is_outside_watched_list()
{
mfs::mkdir($root = MFS::$tmpDir.'/root');
touch($file1 = mfs::$tmpDir.'/file1.php');
$this->to($root);

$this->createResource(__FILE__)->shouldReturn(false);
$this->createResource($file1)->shouldReturn(false);
}

function its_createResource_throws_when_the_path_is_invalid()
{
$this->shouldThrow()
->duringCreateResource('FooBar');
}

function its_hasPath_returns_true_if_the_path_is_watched()
{
mfs::mkdir($watched = mfs::$tmpDir.'/watched');

touch($file1 = $watched.'/foo.txt');
$this->to($watched);
$this->hasPath($file1)->shouldReturn(true);
}

function its_hasPath_returns_false_if_the_path_is_not_watched()
{
mfs::mkdir($watched = mfs::$tmpDir.'/watched');
mfs::mkdir($unwatched = mfs::$tmpDir.'/unwatched');

touch($file1 = $watched.'/foo.txt');
touch($file2 = $unwatched.'/bar.txt');

$this->to($watched);

$this->hasPath($file1)->shouldReturn(true);
$this->hasPath($file2)->shouldReturn(false);
}

function its_hasPath_should_check_against_pattern()
{
mfs::mkdir($dir = mfs::$tmpDir.'/root/subdir');
$this->to(mfs::$tmpDir.'/root');

touch($fphp = $dir.'/foobar.php');
touch($ftxt = $dir.'/foobar.txt');

$this->patterns('#.*\.php$#');

$this->hasPath($fphp)->shouldReturn(true);
$this->hasPath($ftxt)->shouldReturn(false);

$this->patterns('#^subdir\/.*\.txt$#');
$this->hasPath($fphp)->shouldReturn(true);
$this->hasPath($ftxt)->shouldReturn(true);
}

function it_should_start_evaluate_filesystem_event_properly(
AdapterInterface $adapter,
LoggerInterface $logger,
FilesystemEvent $event
)
{
$this->callback(function(ChangeSetEvent $event){
static $count=0;
$event->getListener()->stop();
$count++;
});

$adapter->setLogger($logger)
->shouldBeCalled();
$adapter->initialize($this)
->shouldBeCalled();
$adapter->evaluate()
->shouldBeCalled();
$adapter->getChangeSet()
->willReturn(array($event))
->shouldBeCalled();

$this->setLogger($logger);
$this->to(mfs::$tmpDir);
$this->setAdapter($adapter);
$this->latency(10000);
$this->start();
$this->getChangeset()->shouldContain($event);
}
}
13 changes: 6 additions & 7 deletions src/PhpGuard/Listen/Adapter/InotifyAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public function getChangeSet()
public function watch(TrackedObject $tracked)
{
$path = $tracked->getResource();

//$tracked->setID($id);
if($tracked->getResource() instanceof FileResource){
return;
Expand Down Expand Up @@ -125,28 +126,26 @@ private function translateEvent($inEvent)
$resource = $track->getResource();
$path = $resource.DIRECTORY_SEPARATOR.$wdName;

if($wdMask & IN_ISDIR){
if(0!==($wdMask & IN_ISDIR)){
if(is_dir($path)){
// directory not exists should recursive scan directory
$this->trackNewDir($path);
return;
}elseif(is_dir($resource)){
// directory exists let tracker check
$tracker->checkPath($resource);
return;
}elseif(!is_dir($resource)){
// directory is deleted let inotify unwatch
$this->unwatch($track);
return;
}

return;
}

$wdMask &= ~IN_ISDIR;
$event = 0;
switch ($wdMask) {
case IN_MODIFY:
case IN_ATTRIB:
case IN_CLOSE_WRITE:
$event = FilesystemEvent::MODIFY;
break;
case IN_CREATE:
Expand All @@ -169,7 +168,7 @@ private function translateEvent($inEvent)
$tracker->addChangeSet($path,$event);
}
}
elseif($wdMask & IN_IGNORED){
elseif(0!==($wdMask & IN_IGNORED)){
if($resource->isExists()){
$this->watch($track);
}
Expand Down Expand Up @@ -199,4 +198,4 @@ private function trackNewDir($newPath)
$tracker->checkPath($path);
}
}
}
}
83 changes: 38 additions & 45 deletions src/PhpGuard/Listen/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Listener implements LoggerAwareInterface
* Set paths to listen
* @var array
*/
private $paths;
private $paths = array();

private $patterns = array();

Expand Down Expand Up @@ -67,12 +67,7 @@ class Listener implements LoggerAwareInterface
public function __construct($paths=array())
{
$this->eventMask = FilesystemEvent::ALL;

if(!is_array($paths)){
$paths = array($paths);
}

$this->paths = $paths;
$this->to($paths);
}

public function to($paths)
Expand Down Expand Up @@ -238,29 +233,28 @@ public function addPath($path)

public function hasPath($path)
{
$absPath = $path;

$retVal = false;

foreach($this->paths as $baseDir){
$baseDirLen = strlen($baseDir);

if($baseDir!==substr($absPath,0,$baseDirLen)){
// not own this path, should continue
continue;
if(!$path instanceof SplFileInfo){
$path = $this->createResource($path);
if(false===$path){
return false;
}
}

if(!$path instanceof SplFileInfo){
$path = PathUtil::createSplFileInfo($baseDir,$absPath);
}
$retVal = $this->validateFile($path);

if($retVal){
return $retVal;
if(!empty($this->patterns) && $path->isFile()){
$retVal = false;
foreach($this->patterns as $pattern){
if(preg_match($pattern,$path->getRealPath())){
$retVal = true;
break;
}
if(preg_match($pattern,$path->getRelativePathname())){
$retVal = true;
break;
}
}
return $retVal;
}

return $retVal;
return true;
}

public function getEventMask()
Expand Down Expand Up @@ -301,11 +295,6 @@ public function alwaysNotify($value)
return $this;
}

public function setChangeSet(array $changeSet=array())
{
$this->changeSet = $changeSet;
}

public function getChangeSet()
{
return $this->changeSet;
Expand All @@ -330,22 +319,26 @@ public function log($message,$level=LogLevel::DEBUG,$context=array())
$this->logger->log($level,$message,$context);
}

private function validateFile(SplFileInfo $file)
public function createResource($path)
{
if(!empty($this->patterns) && $file->isFile()){
$retVal = false;
foreach($this->patterns as $pattern){
if(preg_match($pattern,$file->getRealPath())){
$retVal = true;
break;
}
if(preg_match($pattern,$file->getRelativePathname())){
$retVal = true;
break;
}
if(!is_readable($path)){
throw new InvalidArgumentException(sprintf(
'The path "%s" is not exists or not readable.',
$path
));
}

foreach($this->paths as $baseDir){
$baseDirLen = strlen($baseDir);

if($baseDir!==substr($path,0,$baseDirLen)){
// not own this path, should continue
continue;
}
return $retVal;
$path = PathUtil::createSplFileInfo($baseDir,$path);
return $path;
}
return true;

return false;
}
}
16 changes: 8 additions & 8 deletions tests/PhpGuard/Listen/Tests/Adapter/AdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace PhpGuard\Listen\Tests\Adapter;

use PhpGuard\Listen\Adapter\AdapterInterface;
use PhpGuard\Listen\Event\ChangeSetEvent;
use PhpGuard\Listen\Event\FilesystemEvent;
use PhpGuard\Listen\Listener;
use PhpGuard\Listen\Tests\TestCase;
Expand All @@ -20,8 +21,13 @@ class TestedListener extends Listener
{
public function start()
{
$this->getAdapter()->evaluate();
$this->setChangeSet($this->getAdapter()->getChangeSet());
$this->latency(1000);
$this->alwaysNotify(true);
$this->callback(function(ChangeSetEvent $event){
// always stop after each start
$event->getListener()->stop();
});
parent::start();
}
}

Expand Down Expand Up @@ -93,9 +99,6 @@ public function testShouldMonitorBasicFileEvent()
$this->assertCount(0,$changeSet);
}

/**
* @group current
*/
public function testShouldMonitorBasicDirectoryEvent()
{
$tmp = self::$tmpDir;
Expand Down Expand Up @@ -227,9 +230,6 @@ public function testShouldOnlyTrackFilteredPattern()
$this->assertEventHasResource($fphp2,FilesystemEvent::CREATE,$changeSet);
}

/**
* @group current
*/
public function testShouldNotTrackIgnoredDir()
{
$dir = self::$tmpDir;
Expand Down
Loading

0 comments on commit a4ac07d

Please sign in to comment.