diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..d0b733a --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,17 @@ +--- +engines: + duplication: + enabled: true + config: + languages: + - php + fixme: + enabled: true + phpmd: + enabled: true +ratings: + paths: + - "**.php" +exclude_paths: +- tests/ +- examples/ diff --git a/CHANGELOG.md b/CHANGELOG.md index cb90ae9..4ecee68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +### [0.5.1] - 2016-10-01 + + * added integration test for subscription monitor + * added configuration for codeclimate + * bug fixes + ### [0.5.0] - 2016-09-28 * added DeferredInterface diff --git a/README.md b/README.md index c9b4bcf..293c0e4 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,5 @@ WAMP router meta-events ([registration](https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-13.3.7), [subscription](https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-13.6.3), [session](https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-13.7.1)) + \ No newline at end of file diff --git a/src/Tidal/WampWatch/SubscriptionMonitor.php b/src/Tidal/WampWatch/SubscriptionMonitor.php index 426f6bb..c138d76 100644 --- a/src/Tidal/WampWatch/SubscriptionMonitor.php +++ b/src/Tidal/WampWatch/SubscriptionMonitor.php @@ -15,9 +15,7 @@ use Tidal\WampWatch\ClientSessionInterface as ClientSession; /** - * Description of SessionMonitor. - * - * @author Timo + * Class SubscriptionMonitor. */ class SubscriptionMonitor implements MonitorInterface { @@ -138,15 +136,18 @@ protected function getList() protected function getSubscriptionIdRetrievalCallback() { - return function ($res) { - $this->setList($res); + return function (\Thruway\CallResult $res) { + /** @var \Thruway\Message\ResultMessage $message */ + $message = $res->getResultMessage(); + $list = $message->getArguments()[0]; + $this->setList($list); $this->emit('list', [ $this->subscriptionIds->exact, $this->subscriptionIds->prefix, $this->subscriptionIds->wildcard, ]); - return $res; + return $list; }; } } diff --git a/tests/integration/crossbar/CrossbarTestingTrait.php b/tests/integration/crossbar/CrossbarTestingTrait.php new file mode 100644 index 0000000..12151e0 --- /dev/null +++ b/tests/integration/crossbar/CrossbarTestingTrait.php @@ -0,0 +1,75 @@ + + * * + * * For the full copyright and license information, please view the LICENSE + * * file that was distributed with this source code. + * + */ + +namespace integration\crossbar; + +use Psr\Log\NullLogger; +use Thruway\Logging\Logger; +use Thruway\Connection; +use React\EventLoop\Factory as LoopFactory; +use React\EventLoop\LoopInterface; + +trait CrossbarTestingTrait +{ + /** + * @var Connection + */ + private $connection; + + /** + * @var LoopInterface + */ + private $loop; + + /** + * @var int + */ + private $clientSessionId = -1; + + /** + * @var int + */ + private $monitoredSessionId = -2; + + private function setupConnection() + { + + $this->clientSessionId = -1; + $this->monitoredSessionId = -2; + + Logger::set(new NullLogger()); + + $this->loop = LoopFactory::create(); + + $this->connection = $this->createConnection($this->loop); + + } + + /** + * @param \React\EventLoop\LoopInterface|null $loop + * + * @return \Thruway\Connection + */ + private function createConnection(LoopInterface $loop = null) + { + if ($loop === null) { + $loop = LoopFactory::create(); + } + + return new Connection( + [ + 'realm' => self::REALM_NAME, + 'url' => self::ROUTER_URL, + ], + $loop + ); + } +} \ No newline at end of file diff --git a/tests/integration/crossbar/CrosssbarSessionMonitorTest.php b/tests/integration/crossbar/CrosssbarSessionMonitorTest.php index 28a6f58..8a8bfd6 100644 --- a/tests/integration/crossbar/CrosssbarSessionMonitorTest.php +++ b/tests/integration/crossbar/CrosssbarSessionMonitorTest.php @@ -3,59 +3,31 @@ namespace integration\crossbar; require_once realpath(__DIR__ . "/../..") . "/bootstrap.php"; +require_once __DIR__ . "/CrossbarTestingTrait.php"; - -use Psr\Log\NullLogger; -use Thruway\Logging\Logger; use Thruway\ClientSession; -use Thruway\Connection; -use React\EventLoop\Factory as LoopFactory; -use React\EventLoop\LoopInterface; use Tidal\WampWatch\SessionMonitor; use Tidal\WampWatch\Adapter\Thruway\ClientSession as Adapter; class CrosssbarSessionMonitorTest extends \PHPUnit_Framework_TestCase { + use CrossbarTestingTrait; const REALM_NAME = 'realm1'; const ROUTER_URL = 'ws://127.0.0.1:8080/ws'; /** - * @var Connection - */ - private $connection; - - /** - * @var LoopInterface + * */ - private $loop; - - /** - * @var int - */ - private $clientSessionId = -1; - - /** - * @var int - */ - private $monitoredSessionId = -2; - public function setup() { - - $this->clientSessionId = -1; - $this->monitoredSessionId = -2; - - Logger::set(new NullLogger()); - - $this->loop = LoopFactory::create(); - - $this->connection = $this->createConnection($this->loop); - + $this->setupConnection(); } - + /** + * + */ public function test_onstart() { @@ -176,19 +148,4 @@ public function test_onleave() } - private function createConnection(LoopInterface $loop = null) - { - if ($loop = null) { - $loop = LoopFactory::create(); - } - - return new Connection( - [ - 'realm' => self::REALM_NAME, - 'url' => self::ROUTER_URL, - ], - $loop - ); - } - } diff --git a/tests/integration/crossbar/CrosssbarSubscriptionMonitorTest.php b/tests/integration/crossbar/CrosssbarSubscriptionMonitorTest.php new file mode 100644 index 0000000..05a9f99 --- /dev/null +++ b/tests/integration/crossbar/CrosssbarSubscriptionMonitorTest.php @@ -0,0 +1,327 @@ + + * * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +namespace integration\crossbar; + +require_once realpath(__DIR__ . "/../..") . "/bootstrap.php"; +require_once __DIR__ . "/CrossbarTestingTrait.php"; + +use Thruway\ClientSession; +use Tidal\WampWatch\SubscriptionMonitor; +use Tidal\WampWatch\Adapter\Thruway\ClientSession as Adapter; +use Tidal\WampWatch\Util; + +class CrosssbarSubscriptionMonitorTest extends \PHPUnit_Framework_TestCase +{ + + use CrossbarTestingTrait; + + const REALM_NAME = 'realm1'; + + const ROUTER_URL = 'ws://127.0.0.1:8080/ws'; + + public function setup() + { + $this->setupConnection(); + } + + public function test_onstart() + { + + $subscriptionInfo = null; + + $this->connection->on('open', function (ClientSession $session) use (&$subscriptionInfo) { + + $subscriptionMonitor = new SubscriptionMonitor(new Adapter($session)); + + $subscriptionMonitor->on('start', function ($ids) use (&$subscriptionInfo, $subscriptionMonitor) { + + $subscriptionInfo = $ids; + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('error', function ($error) use (&$subscriptionInfo, $subscriptionMonitor) { + + var_dump($error); + + $this->connection->close(); + + die(); + }); + + $subscriptionMonitor->start(); + }); + + $this->connection->on('error', function ($reason) { + echo "The connected has closed with error: {$reason}\n"; + }); + + $this->connection->open(); + + $this->assertInstanceOf(\stdClass::class, $subscriptionInfo); + $this->assertAttributeInternalType('array', 'exact', $subscriptionInfo); + $this->assertAttributeInternalType('array', 'prefix', $subscriptionInfo); + $this->assertAttributeInternalType('array', 'wildcard', $subscriptionInfo); + } + + public function test_oncreate() + { + $subscriptionSessionId = null; + $subscriptionInfo = null; + + $this->connection->on('open', function (ClientSession $session) use (&$subscriptionInfo, &$subscriptionSessionId) { + + $subscriptionMonitor = new SubscriptionMonitor(new Adapter($session)); + + $subscriptionMonitor->on('start', function () use ($subscriptionMonitor) { + + // create an additional client session + $clientConnection = $this->createConnection(); + + $clientConnection->on('open', function (ClientSession $clientSession) use ($clientConnection) { + $this->clientSessionId = $clientSession->getSessionId(); + $clientSession->subscribe('foo', function () { + }); + $clientConnection->close(); + }); + $clientConnection->open(); + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('create', function ($sessionId, \stdClass $subInfo) use (&$subscriptionInfo, &$subscriptionSessionId, $subscriptionMonitor) { + + $subscriptionInfo = $subInfo; + $subscriptionSessionId = $sessionId; + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('error', function ($error) use (&$subscriptionInfo, $subscriptionMonitor) { + + var_dump($error); + + $this->connection->close(); + }); + + $subscriptionMonitor->start(); + + }); + + $this->connection->on('error', function ($reason) { + echo "The connected has closed with error: {$reason}\n"; + }); + + $this->connection->open(); + + $this->assertInternalType('int', $subscriptionSessionId); + $this->assertInstanceOf(\stdClass::class, $subscriptionInfo); + $this->assertAttributeEquals('foo', 'uri', $subscriptionInfo); + $this->assertAttributeEquals('exact', 'match', $subscriptionInfo); + $this->assertAttributeInternalType('int', 'id', $subscriptionInfo); + $this->assertAttributeInternalType('string', 'created', $subscriptionInfo); + } + + public function test_onsubscribe() + { + $sessionId = null; + $subscriptionId = null; + + $this->connection->on('open', function (ClientSession $session) use (&$sessionId, &$subscriptionId) { + + $subscriptionMonitor = new SubscriptionMonitor(new Adapter($session)); + + $subscriptionMonitor->on('start', function () use ($subscriptionMonitor) { + + // create an additional client session + $clientConnection = $this->createConnection(); + + $clientConnection->on('open', function (ClientSession $clientSession) use ($clientConnection) { + $this->clientSessionId = $clientSession->getSessionId(); + $clientSession->subscribe('foo', function () { + }); + $clientConnection->close(); + }); + $clientConnection->open(); + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('subscribe', function ($sesId, $subId) use (&$sessionId, &$subscriptionId, $subscriptionMonitor) { + + $sessionId = $sesId; + $subscriptionId = $subId; + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('error', function ($error) use ($subscriptionMonitor) { + + var_dump($error); + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->start(); + + }); + + $this->connection->on('error', function ($reason) { + echo "The connected has closed with error: {$reason}\n"; + }); + + $this->connection->open(); + + $this->assertInternalType('int', $sessionId); + $this->assertInternalType('int', $subscriptionId); + } + + public function test_onunsubscribe() + { + + $sessionId = null; + $subscriptionId = null; + + $this->connection->on('open', function (ClientSession $session) use (&$sessionId, &$subscriptionId) { + + $subscriptionMonitor = new SubscriptionMonitor(new Adapter($session)); + + // create an additional client session + $clientConnection = $this->createConnection(); + $clientSession = null; + + $subscriptionMonitor->on('start', function () use ($subscriptionMonitor, $clientConnection, $clientConnection) { + $clientConnection->open(); + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $clientConnection->on('open', function (ClientSession $clientSession) use ($clientConnection, &$subscriptionMonitor) { + + $this->clientSessionId = $clientSession->getSessionId(); + + $subscriptionMonitor->on('subscribe', function () use ($clientSession) { + Util::unsubscribe(new Adapter($clientSession), func_get_args()[1]); + }); + + $clientSession->subscribe('foo', function () { + }); + + $clientConnection->close(); + + }); + + $subscriptionMonitor->on('unsubscribe', function ($sesId, $subId) use (&$sessionId, &$subscriptionId, $subscriptionMonitor, $clientConnection) { + + $sessionId = $sesId; + $subscriptionId = $subId; + + $clientConnection->close(); + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('error', function ($error) use ($subscriptionMonitor) { + + var_dump($error); + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->start(); + + }); + + $this->connection->on('error', function ($reason) { + echo "The connected has closed with error: {$reason}\n"; + }); + + $this->connection->open(); + + $this->assertInternalType('int', $sessionId); + $this->assertInternalType('int', $subscriptionId); + } + + public function test_ondelete() + { + $sessionId = null; + $subscriptionId = null; + + $this->connection->on('open', function (ClientSession $session) use (&$sessionId, &$subscriptionId) { + + $subscriptionMonitor = new SubscriptionMonitor(new Adapter($session)); + + // create an additional client session + $clientConnection = $this->createConnection(); + $clientSession = null; + + $subscriptionMonitor->on('start', function () use ($subscriptionMonitor, $clientConnection, $clientConnection) { + $clientConnection->open(); + + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $clientConnection->on('open', function (ClientSession $clientSession) use ($clientConnection, &$subscriptionMonitor) { + + $topicName = "foo-bar-baz-boo"; + $this->clientSessionId = $clientSession->getSessionId(); + + $subscriptionMonitor->on('subscribe', function () use ($clientSession) { + Util::unsubscribe(new Adapter($clientSession), func_get_args()[1]); + }); + + $clientSession->subscribe($topicName, function () { + }); + + $clientConnection->close(); + + }); + + $subscriptionMonitor->on('delete', function ($sesId, $subId) use (&$sessionId, &$subscriptionId, $subscriptionMonitor, $clientConnection) { + + $sessionId = $sesId; + $subscriptionId = $subId; + + $clientConnection->close(); + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->on('error', function ($error) use ($subscriptionMonitor) { + + var_dump($error); + $subscriptionMonitor->stop(); + $this->connection->close(); + }); + + $subscriptionMonitor->start(); + + }); + + $this->connection->on('error', function ($reason) { + echo "The connected has closed with error: {$reason}\n"; + }); + + $this->connection->open(); + + $this->assertInternalType('int', $sessionId); + $this->assertInternalType('int', $subscriptionId); + } + +} diff --git a/tests/unit/SubscriptionMonitorTest.php b/tests/unit/SubscriptionMonitorTest.php index 8541833..b370b95 100644 --- a/tests/unit/SubscriptionMonitorTest.php +++ b/tests/unit/SubscriptionMonitorTest.php @@ -6,6 +6,8 @@ use Tidal\WampWatch\SubscriptionMonitor; use Tidal\WampWatch\Stub\ClientSessionStub; +use Thruway\CallResult; +use Thruway\Message\ResultMessage; class SubscriptionMonitorTest extends \PHPUnit_Framework_TestCase @@ -143,7 +145,7 @@ public function test_start_event_after_running() $stub->completeSubscription(SubscriptionMonitor::SUBSCRIPTION_SUB_TOPIC); $stub->completeSubscription(SubscriptionMonitor::SUBSCRIPTION_UNSUB_TOPIC); - $this->assertEquals($subIdMap, $response); + $this->assertEquals($subIdMap->getResultMessage()->getArguments()[0], $response); } // META SUBSCRIPTION AND CALL TESTS @@ -366,7 +368,7 @@ public function test_get_seesion_ids_returns_subscription_map() $stub->respondToCall(SubscriptionMonitor::SUBSCRIPTION_LIST_TOPIC, $subIdMap); - $this->assertSame($subIdMap, $res); + $this->assertEquals($subIdMap->getResultMessage()->getArguments()[0], $res); } public function test_2nd_get_seesion_ids_returns_subscription_map_locally() @@ -387,7 +389,7 @@ public function test_2nd_get_seesion_ids_returns_subscription_map_locally() $second = $r; }); - $this->assertSame($first, $second); + $this->assertEquals($first, $second); } @@ -403,7 +405,47 @@ private function getSubscriptionInfo() private function getSubscriptionIdMap() { - return json_decode('{"exact": [321], "prefix": [654], "wildcard": [987]}'); + return $this->getCallResultMock(); } + /** + * @return \PHPUnit_Framework_MockObject_MockObject|CallResult + */ + private function getCallResultMock() + { + $mock = $this->getMockBuilder(CallResult::class) + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->any()) + ->method('getResultMessage') + ->willReturn( + $this->getResultMessageMock() + ); + + return $mock; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject| + */ + private function getResultMessageMock() + { + $mock = $this->getMockBuilder(ResultMessage::class) + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->any()) + ->method('getArguments') + ->willReturn( + [ + json_decode('{"exact": [321], "prefix": [654], "wildcard": [987]}') + ] + ); + + return $mock; + } + + + }