Skip to content

Improve Exception messages for connection issues #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@
});
}, function (Exception $error) {
echo 'CONNECTION ERROR: ' . $error->getMessage() . PHP_EOL;
if ($error->getPrevious()) {
echo $error->getPrevious()->getMessage() . PHP_EOL;
}
exit(1);
});


$loop->run();
6 changes: 6 additions & 0 deletions examples/incr.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@

$client->get('test')->then(function ($result) {
var_dump($result);
}, function (Exception $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
if ($e->getPrevious()) {
echo $e->getPrevious()->getMessage() . PHP_EOL;
}
exit(1);
});

$client->end();
Expand Down
8 changes: 7 additions & 1 deletion examples/publish.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@

$client = $factory->createLazyClient('localhost');
$client->publish($channel, $message)->then(function ($received) {
echo 'successfully published. Received by ' . $received . PHP_EOL;
echo 'Successfully published. Received by ' . $received . PHP_EOL;
}, function (Exception $e) {
echo 'Unable to publish: ' . $e->getMessage() . PHP_EOL;
if ($e->getPrevious()) {
echo $e->getPrevious()->getMessage() . PHP_EOL;
}
exit(1);
});

$client->end();
Expand Down
24 changes: 20 additions & 4 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function createClient($target)
$connecting = $this->connector->connect($parts['authority']);
$deferred = new Deferred(function ($_, $reject) use ($connecting) {
// connection cancelled, start with rejecting attempt, then clean up
$reject(new \RuntimeException('Connection to database server cancelled'));
$reject(new \RuntimeException('Connection to Redis server cancelled'));

// either close successful connection or cancel pending connection attempt
$connecting->then(function (ConnectionInterface $connection) {
Expand All @@ -67,6 +67,12 @@ public function createClient($target)
$protocol = $this->protocol;
$promise = $connecting->then(function (ConnectionInterface $stream) use ($protocol) {
return new StreamingClient($stream, $protocol->createResponseParser(), $protocol->createSerializer());
}, function (\Exception $e) {
throw new \RuntimeException(
'Connection to Redis server failed because underlying transport connection failed',
0,
$e
);
});

if (isset($parts['auth'])) {
Expand All @@ -77,7 +83,12 @@ function () use ($client) {
},
function ($error) use ($client) {
$client->close();
throw $error;

throw new \RuntimeException(
'Connection to Redis server failed because AUTH command failed',
0,
$error
);
}
);
});
Expand All @@ -91,7 +102,12 @@ function () use ($client) {
},
function ($error) use ($client) {
$client->close();
throw $error;

throw new \RuntimeException(
'Connection to Redis server failed because SELECT command failed',
0,
$error
);
}
);
});
Expand All @@ -108,7 +124,7 @@ function ($error) use ($client) {
return \React\Promise\Timer\timeout($deferred->promise(), $timeout, $this->loop)->then(null, function ($e) {
if ($e instanceof TimeoutException) {
throw new \RuntimeException(
'Connection to database server timed out after ' . $e->getTimeout() . ' seconds'
'Connection to Redis server timed out after ' . $e->getTimeout() . ' seconds'
);
}
throw $e;
Expand Down
107 changes: 103 additions & 4 deletions tests/FactoryStreamingClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,43 @@ public function testWillWriteAuthCommandIfRedisUnixUriContainsUserInfo()
$this->factory->createClient('redis+unix://hello:world@/tmp/redis.sock');
}

public function testWillResolveWhenAuthCommandReceivesOkResponseIfRedisUriContainsUserInfo()
{
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('write'))->getMock();
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nworld\r\n");

$this->connector->expects($this->once())->method('connect')->willReturn(Promise\resolve($stream));
$promise = $this->factory->createClient('redis://:world@localhost');

$stream->emit('data', array("+OK\r\n"));

$promise->then($this->expectCallableOnceWith($this->isInstanceOf('Clue\React\Redis\Client')));
}

public function testWillRejectAndCloseAutomaticallyWhenAuthCommandReceivesErrorResponseIfRedisUriContainsUserInfo()
{
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('write', 'close'))->getMock();
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nworld\r\n");
$stream->expects($this->once())->method('close');

$this->connector->expects($this->once())->method('connect')->willReturn(Promise\resolve($stream));
$promise = $this->factory->createClient('redis://:world@localhost');

$stream->emit('data', array("-ERR invalid password\r\n"));

$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to Redis server failed because AUTH command failed';
}),
$this->callback(function (\Exception $e) {
return $e->getPrevious()->getMessage() === 'ERR invalid password';
})
)
));
}

public function testWillWriteSelectCommandIfRedisUnixUriContainsDbQueryParameter()
{
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
Expand All @@ -140,19 +177,63 @@ public function testWillWriteSelectCommandIfRedisUnixUriContainsDbQueryParameter
$this->factory->createClient('redis+unix:///tmp/redis.sock?db=demo');
}

public function testWillResolveWhenSelectCommandReceivesOkResponseIfRedisUriContainsPath()
{
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('write'))->getMock();
$stream->expects($this->once())->method('write')->with("*2\r\n$6\r\nselect\r\n$3\r\n123\r\n");

$this->connector->expects($this->once())->method('connect')->willReturn(Promise\resolve($stream));
$promise = $this->factory->createClient('redis://localhost/123');

$stream->emit('data', array("+OK\r\n"));

$promise->then($this->expectCallableOnceWith($this->isInstanceOf('Clue\React\Redis\Client')));
}

public function testWillRejectAndCloseAutomaticallyWhenSelectCommandReceivesErrorResponseIfRedisUriContainsPath()
{
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('write', 'close'))->getMock();
$stream->expects($this->once())->method('write')->with("*2\r\n$6\r\nselect\r\n$3\r\n123\r\n");
$stream->expects($this->once())->method('close');

$this->connector->expects($this->once())->method('connect')->willReturn(Promise\resolve($stream));
$promise = $this->factory->createClient('redis://localhost/123');

$stream->emit('data', array("-ERR DB index is out of range\r\n"));

$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to Redis server failed because SELECT command failed';
}),
$this->callback(function (\Exception $e) {
return $e->getPrevious()->getMessage() === 'ERR DB index is out of range';
})
)
));
}

public function testWillRejectIfConnectorRejects()
{
$this->connector->expects($this->once())->method('connect')->with('127.0.0.1:2')->willReturn(Promise\reject(new \RuntimeException()));
$promise = $this->factory->createClient('redis://127.0.0.1:2');

$this->expectPromiseReject($promise);
$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to Redis server failed because underlying transport connection failed';
})
)
));
}

public function testWillRejectIfTargetIsInvalid()
{
$promise = $this->factory->createClient('http://invalid target');

$this->expectPromiseReject($promise);
$promise->then(null, $this->expectCallableOnceWith($this->isInstanceOf('InvalidArgumentException')));
}

public function testCancelWillRejectPromise()
Expand All @@ -173,6 +254,15 @@ public function testCancelWillCancelConnectorWhenConnectionIsPending()

$promise = $this->factory->createClient('redis://127.0.0.1:2');
$promise->cancel();

$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to Redis server cancelled';
})
)
));
}

public function testCancelWillCloseConnectionWhenConnectionWaitsForSelect()
Expand All @@ -185,6 +275,15 @@ public function testCancelWillCloseConnectionWhenConnectionWaitsForSelect()

$promise = $this->factory->createClient('redis://127.0.0.1:2/123');
$promise->cancel();

$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to Redis server cancelled';
})
)
));
}

public function testCreateClientWithTimeoutParameterWillStartTimerAndRejectOnExplicitTimeout()
Expand All @@ -205,9 +304,9 @@ public function testCreateClientWithTimeoutParameterWillStartTimerAndRejectOnExp

$promise->then(null, $this->expectCallableOnceWith(
$this->logicalAnd(
$this->isInstanceOf('Exception'),
$this->isInstanceOf('RuntimeException'),
$this->callback(function (\Exception $e) {
return $e->getMessage() === 'Connection to database server timed out after 0 seconds';
return $e->getMessage() === 'Connection to Redis server timed out after 0 seconds';
})
)
));
Expand Down