Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

...
  • 5 commits
  • 17 files changed
  • 0 commit comments
  • 1 contributor
4 TODO
View
@@ -1,4 +1,6 @@
- improve transaction handling, return transaction id on begin and/or dont require to specify transaction id in send call
-- integration tests using node.js
+- improve unsubscribe logic as client code could remove system event listener
+- use phpunit strict mode and set timeout for integration tests
+- find a good way to test produce/consume logic
- update README and provide some documentation and install guide via composer
- investigate exceptions thrown while running examples
3  phpunit.xml.dist
View
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
+ strict = "true"
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
@@ -7,7 +8,7 @@
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
- stopOnFailure = "false"
+ stopOnFailure = "true"
syntaxCheck = "true"
bootstrap = "tests/bootstrap.php" >
<testsuites>
77 src/Stomp/Helper/PHPUnit/StompServerTrait.php
View
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp\Helper\PHPUnit;
+
+trait StompServerTrait
+{
+ private static $NO_OUTPUT = '[no output]';
+
+ private $stompServerProcess;
+ private $currentOutputFile;
+
+ // @TODO add node in travis.yml, update TODO :), write some tests :(
+ private function startStompServer()
+ {
+ $this->stopStompServer();
+
+ $this->currentOutputFile = STOMP_TEST_DIR . '/integration/fixtures/output-files/' . microtime(true) . '-' . md5(uniqid(mt_rand(), true)) . '.txt';
+
+ $cmd = 'node ' . STOMP_TEST_DIR . '/../vendor/maxbeutel/node-stomp-server/app.js';
+
+ $descriptorspec = [
+ 0 => ['pipe', 'r'],
+ 1 => ['file', $this->currentOutputFile, 'w'],
+ 2 => ['pipe', 'w'],
+ ];
+
+ $this->stompServerProcess = proc_open($cmd, $descriptorspec, $pipes, sys_get_temp_dir());
+
+ // hack: hopefully node process started within that timespan...
+ sleep(2);
+ }
+
+ private function stopStompServer()
+ {
+ if (is_resource($this->stompServerProcess)) {
+ proc_terminate($this->stompServerProcess);
+ }
+
+ foreach (glob(STOMP_TEST_DIR . '/integration/fixtures/output-files/*.txt') as $outputFile) {
+ unlink($outputFile);
+ }
+
+ exec('ps -ef | grep "/node-stomp-server/" | awk \'{print $2}\' | xargs -r kill 2>&1');
+
+ $this->stompServerProcess = $this->currentOutputFile = null;
+ }
+
+ private function getStompServerOutput()
+ {
+ if (!is_file($this->currentOutputFile)) {
+ return self::$NO_OUTPUT;
+ }
+
+ // hack: not all data might have been written to disk yet
+ sleep(1);
+
+ return file_get_contents($this->currentOutputFile);
+ }
+}
2  src/Stomp/SocketConnection.php
View
@@ -132,7 +132,7 @@ public function open()
$this->close();
}
} catch (BadMethodCallException $e) {
- throw new ConnectionException(sprintf('Could not connect to any broker', $connectionAttempts), $e->getCode(), $e);
+ throw new ConnectionException('Could not connect to any broker', $e->getCode(), $e);
} catch (InvalidArgumentException $e) {
throw new ConnectionException('Attempted to use invalid URI', $e->getCode(), $e);
}
40 src/Stomp/StompClient.php
View
@@ -67,33 +67,43 @@ public function __construct($uriString, array $options = [])
'writeTimeout' => 10,
'retryAttemptsPerUri' => 10,
'logLevel' => Logger::DEBUG,
+ 'loggerInstance' => null,
+ 'dispatcherInstance' => null,
];
$this->options = array_merge($defaultOptions, $options);
- $this->dispatcher = new EventDispatcher();
+ if ($this->options['dispatcherInstance']) {
+ $this->setDispatcher($this->options['dispatcherInstance']);
+ } else {
+ $this->setDispatcher(new EventDispatcher());
+ }
+
+ if ($this->options['loggerInstance']) {
+ $this->setLogger($this->options['loggerInstance']);
+ } else {
+ $logger = new Logger('StompClient');
+ $logger->pushHandler(new StreamHandler('php://stdout', $this->options['logLevel']));
- $this->logger = new Logger('StompClient');
- $this->logger->pushHandler(new StreamHandler('php://stdout', $this->options['logLevel']));
+ $this->setLogger($logger);
+ }
$this->socketConnection = new SocketConnection($uriString, $this->options['retryAttemptsPerUri'], $this->options['connectTimeout'], $this->logger);
}
- public function setLogger(Logger $logger)
+ public function getSessionId()
{
- $this->logger = $logger;
- return $this;
+ return $this->sessionId;
}
- public function setDispatcher(EventDispatcherInterface $dispatcher)
+ protected function setLogger(Logger $logger)
{
- $this->dispatcher = $dispatcher;
- return $this;
+ $this->logger = $logger;
}
- public function getSessionId()
+ protected function setDispatcher(EventDispatcherInterface $dispatcher)
{
- return $this->sessionId;
+ $this->dispatcher = $dispatcher;
}
protected function writeFrame(Frame $frame)
@@ -220,10 +230,8 @@ public function unsubscribe($eventName, callable $listener)
$this->dispatcher->removeListener($eventName, $listener);
if (preg_match('#^\/(queue|topic|temp-queue|temp-topic)\/#i', $eventName)) {
- foreach ($this->dataListeners as $dataListener) {
- list($theEventName, $theListener) = $dataListener;
-
- if ($theEventName !== $eventName || ($listener && $dataListener !== $listener)) {
+ foreach ($this->subscribedEventNames as $theEventName) {
+ if ($theEventName !== $eventName) {
continue;
}
@@ -359,7 +367,7 @@ protected function breakEventLoop()
event_base_loopbreak($this->base);
}
- unset($this->base);
+ $this->base = null;
}
public function disconnect()
2  src/Stomp/Value/Frame.php
View
@@ -39,7 +39,7 @@ private function __construct($command, array $headers, $body, $waitForReceipt)
{
$this->command = $command;
$this->headers = $headers;
- $this->body = $body;
+ $this->body = trim($body);
$this->waitForReceipt = $waitForReceipt;
}
2  tests/bootstrap.php
View
@@ -20,4 +20,6 @@
error_reporting(E_ALL);
+define('STOMP_TEST_DIR', __DIR__);
+
require_once __DIR__ . '/../autoload.php';
165 tests/integration/Stomp/CommonFunctionalityTest.php
View
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp;
+
+use PHPUnit_Framework_TestCase;
+use Stomp\StompClient;
+use Stomp\Helper\PHPUnit\StompServerTrait;
+
+class CommonFunctionalityTest extends PHPUnit_Framework_TestCase
+{
+ use StompServerTrait;
+
+ private $loggerMock;
+
+ public function setUp()
+ {
+ $this->startStompServer();
+
+ $this->loggerMock = $this->getMockBuilder('Monolog\Logger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function tearDown()
+ {
+ $this->stopStompServer();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testBasicConnectDisconnect()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"","passcode":"","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testBasicConnectDisconnectWithCredentials()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['username' => 'user', 'password' => 'secret', 'loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"user","passcode":"secret","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testMultipleDisconnectsDontSendMultipleCommands()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+ $client->__destruct();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"","passcode":"","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testConnectedClientHasSessionId()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $this->assertNull($client->getSessionId());
+ $client->connect();
+ $this->assertNotNull($client->getSessionId());
+ $client->disconnect();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testSend()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+
+ $client->send('/queue/test', 'message 1');
+ $client->send('/queue/test', 'message 2');
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('SEND {"destination":"/queue/test","content-length":9} "message 1"', $output);
+ $this->assertContains('SEND {"destination":"/queue/test","content-length":9} "message 2"', $output);
+
+ $client->disconnect();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testSubscribe()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+
+ $client->subscribe('/queue/test', function() {});
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('SUBSCRIBE {"ack":"client","destination":"/queue/test","activemq.prefetchSize":"1","content-length":0}', $output);
+
+ $client->disconnect();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testUnsubscribe()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+
+ $client->subscribe('/queue/test', function() {});
+ $client->unsubscribe('/queue/test', function() {});
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('UNSUBSCRIBE {"destination":"/queue/test","content-length":0}', $output);
+
+ $client->disconnect();
+ }
+}
58 tests/integration/Stomp/ErrorHandlingTest.php
View
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp;
+
+use PHPUnit_Framework_TestCase;
+use Stomp\StompClient;
+use Stomp\Helper\PHPUnit\StompServerTrait;
+
+class ErrorHandlingTest extends PHPUnit_Framework_TestCase
+{
+ use StompServerTrait;
+
+ private $loggerMock;
+
+ public function setUp()
+ {
+ $this->startStompServer();
+
+ $this->loggerMock = $this->getMockBuilder('Monolog\Logger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function tearDown()
+ {
+ $this->stopStompServer();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testBasicConnectDisconnect()
+ {
+ $client = new StompClient('tcp://localhost:1', ['loggerInstance' => $this->loggerMock]);
+
+ $this->setExpectedException('Stomp\Exception\ConnectionException', 'Could not connect to any broker');
+ $client->connect();
+ }
+}
94 tests/integration/Stomp/FailoverTest.php
View
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp;
+
+use PHPUnit_Framework_TestCase;
+use Stomp\StompClient;
+use Stomp\Helper\PHPUnit\StompServerTrait;
+
+class FailoverTest extends PHPUnit_Framework_TestCase
+{
+ use StompServerTrait;
+
+ private $loggerMock;
+
+ public function setUp()
+ {
+ $this->startStompServer();
+
+ $this->loggerMock = $this->getMockBuilder('Monolog\Logger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function tearDown()
+ {
+ $this->stopStompServer();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testFailoverMultipleUris()
+ {
+ $client = new StompClient('failover://(tcp://localhost:1,tcp://localhost:61613)', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"","passcode":"","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testFailoverMultipleUrisRandomized()
+ {
+ $client = new StompClient('failover://(tcp://localhost:1,tcp://localhost:61613)?randomize=true', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"","passcode":"","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testFailoverSyntaxSingleUriValid()
+ {
+ $client = new StompClient('failover://(tcp://localhost:61613)', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+ $client->disconnect();
+
+ $output = $this->getStompServerOutput();
+
+ $this->assertContains('CONNECT {"login":"","passcode":"","content-length":0}', $output);
+ $this->assertContains('DISCONNECT {"content-length":0', $output);
+ }
+}
87 tests/integration/Stomp/ProduceConsumeTest.php
View
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp;
+
+use PHPUnit_Framework_TestCase;
+use Stomp\StompClient;
+use Stomp\Event\FrameEvent;
+use Stomp\Helper\PHPUnit\StompServerTrait;
+
+class ProduceConsumeTest extends PHPUnit_Framework_TestCase
+{
+ use StompServerTrait;
+
+ private $loggerMock;
+
+ public function setUp()
+ {
+ $this->startStompServer();
+
+ $this->loggerMock = $this->getMockBuilder('Monolog\Logger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function tearDown()
+ {
+ $this->stopStompServer();
+ }
+
+ /**
+ * @group integration
+ * @large
+ */
+ /*public function testProduceConsumeSnyc()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock, 'waitForReceipt' => true]);
+ $client->connect();
+
+ $client->subscribe('/queue/test', function(FrameEvent $event) {
+ $event->getConnection()->ack($event->getFrame());
+ $event->getConnection()->disconnect();
+ $this->assertSame('message 1', $event->getFrame()->getBody());
+ });
+
+ $client->send('/queue/test', 'message 1');
+
+ $client->listen();
+ }*/
+
+ /**
+ * @group integration
+ * @large
+ */
+ public function testProduceConsume()
+ {
+ $client = new StompClient('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->connect();
+
+ $client->subscribe('/queue/test', function(FrameEvent $event) {
+ $event->getConnection()->ack($event->getFrame());
+ $event->getConnection()->disconnect();
+ $this->assertSame('message 1', $event->getFrame()->getBody());
+ });
+
+ $client->send('/queue/test', 'message 1');
+
+ $client->listen();
+ }
+}
0  tests/integration/StompFailoverTest.php → tests/integration/StompFailoverTest.old
View
File renamed without changes
0  tests/integration/StompSslTest.php → tests/integration/StompSslTest.old
View
File renamed without changes
0  tests/integration/StompTest.php → tests/integration/StompTest.old
View
File renamed without changes
0  tests/integration/fixtures/output-files/.gitadd
View
No changes.
2  tests/unit/Stomp/Event/FrameEventTest.php
View
@@ -30,7 +30,7 @@ public function setUp()
{
$this->connectionMock = $this->getMockBuilder('Stomp\StompClient')
->disableOriginalConstructor()
- // hack - mock only certain methods as PHPUnit cant cope with callable typehint yet
+ // hack: mock only certain methods as PHPUnit cant cope with callable typehint yet
->setMethods(['connect', 'disconnect'])
->getMock();
80 tests/unit/Stomp/StompClientTest.php
View
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ *
+ * Copyright 2012 Max Beutel <me@maxbeutel.de>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Stomp;
+
+use PHPUnit_Framework_TestCase;
+use Stomp\Value\Frame;
+
+class ConnectedStompClientDummy extends StompClient
+{
+ public function __construct($uriString, array $options = [])
+ {
+ parent::__construct($uriString, $options);
+ $this->connected = true;
+ }
+
+ protected function writeFrame(Frame $frame)
+ {
+ // do nothing
+ }
+
+ public function disconnect()
+ {
+ // do nothing
+ }
+}
+
+class StompClientTest extends PHPUnit_Framework_TestCase
+{
+ private $loggerMock;
+
+ public function setUp()
+ {
+ $this->loggerMock = $this->getMockBuilder('Monolog\Logger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testSubscribeNotConnected()
+ {
+ $this->setExpectedException('BadMethodCallException', 'Cant subscribe before connecting');
+
+ $client = new StompClient('tcp://localhost:61613');
+ $client->subscribe('/queue/test', function() {});
+ }
+
+ public function testSubscribeWithInvalidEventName()
+ {
+ $this->setExpectedException('InvalidArgumentException', 'Event name must begin with one of /queue /topic /temp-queue /temp-topic, got "/foo/bar"');
+
+ $client = new ConnectedStompClientDummy('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->subscribe('/foo/bar', function() {});
+ }
+
+ public function testSubcribe()
+ {
+ $client = new ConnectedStompClientDummy('tcp://localhost:61613', ['loggerInstance' => $this->loggerMock]);
+ $client->subscribe('/queue/test', function() {});
+ $client->subscribe('/temp-queue/test', function() {});
+ $client->subscribe('/topic/test', function() {});
+ $client->subscribe('/temp-topic/test', function() {});
+ }
+}

No commit comments for this range

Something went wrong with that request. Please try again.