Skip to content

Commit 5e9b071

Browse files
fixed error throws in protocol versions. updated errors coverage.
1 parent 267cd00 commit 5e9b071

File tree

10 files changed

+154
-65
lines changed

10 files changed

+154
-65
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Bolt
22
Bolt protocol library over TCP socket. Bolt protocol is primary used for communication with [Neo4j](https://neo4j.com/) Graph database. The documentation is available at [https://7687.org/](https://7687.org/).
33

4-
![](https://img.shields.io/badge/phpunit-passed-success) ![](https://img.shields.io/badge/coverage-77%25-green) ![](https://img.shields.io/github/stars/stefanak-michal/Bolt) ![](https://img.shields.io/packagist/dt/stefanak-michal/bolt) ![](https://img.shields.io/github/v/release/stefanak-michal/bolt) ![](https://img.shields.io/github/commits-since/stefanak-michal/bolt/latest)
4+
![](https://img.shields.io/badge/phpunit-passed-success) ![](https://img.shields.io/badge/coverage-86%25-green) ![](https://img.shields.io/github/stars/stefanak-michal/Bolt) ![](https://img.shields.io/packagist/dt/stefanak-michal/bolt) ![](https://img.shields.io/github/v/release/stefanak-michal/bolt) ![](https://img.shields.io/github/commits-since/stefanak-michal/bolt/latest)
55

66
## Version support
77
Bolt <= 4.1

src/Bolt.php

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ final class Bolt
5252
*/
5353
private $version;
5454

55-
/**
56-
* @var int
57-
*/
58-
private $packStreamVersion = 1;
59-
6055
/**
6156
* @var string
6257
*/
@@ -76,18 +71,7 @@ final class Bolt
7671
public function __construct(IConnection $connection)
7772
{
7873
$this->connection = $connection;
79-
80-
$packerClass = "\\Bolt\\PackStream\\v" . $this->packStreamVersion . "\\Packer";
81-
if (!class_exists($packerClass)) {
82-
throw new PackException('Requested PackStream version (' . $this->packStreamVersion . ') not yet implemented');
83-
}
84-
$this->packer = new $packerClass();
85-
86-
$unpackerClass = "\\Bolt\\PackStream\\v" . $this->packStreamVersion . "\\Unpacker";
87-
if (!class_exists($unpackerClass)) {
88-
throw new UnpackException('Requested PackStream version (' . $this->packStreamVersion . ') not yet implemented');
89-
}
90-
$this->unpacker = new $unpackerClass();
74+
$this->setPackStreamVersion();
9175
}
9276

9377
/**
@@ -103,10 +87,22 @@ public function setProtocolVersions(...$v): Bolt
10387
/**
10488
* @param int $version
10589
* @return Bolt
90+
* @throws Exception
10691
*/
10792
public function setPackStreamVersion(int $version = 1)
10893
{
109-
$this->packStreamVersion = $version;
94+
$packerClass = "\\Bolt\\PackStream\\v" . $version . "\\Packer";
95+
if (!class_exists($packerClass)) {
96+
throw new PackException('Requested PackStream version (' . $version . ') not yet implemented');
97+
}
98+
$this->packer = new $packerClass();
99+
100+
$unpackerClass = "\\Bolt\\PackStream\\v" . $version . "\\Unpacker";
101+
if (!class_exists($unpackerClass)) {
102+
throw new UnpackException('Requested PackStream version (' . $version . ') not yet implemented');
103+
}
104+
$this->unpacker = new $unpackerClass();
105+
110106
return $this;
111107
}
112108

src/connection/StreamSocket.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public function connect(): bool
5050
'ssl' => $this->sslContextOptions
5151
]);
5252

53-
$this->stream = stream_socket_client( 'tcp://' . $this->ip . ':' . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
53+
$this->stream = @stream_socket_client( 'tcp://' . $this->ip . ':' . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
5454

5555
if ($this->stream === false) {
5656
throw new ConnectException($errstr, $errno);

src/protocol/V1.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function init(...$args): bool
3737
if ($signature == self::FAILURE) {
3838
//AckFailure after init do not respond with any message
3939
$this->write($this->packer->pack(0x0E));
40-
throw new MessageException($output['message']);
40+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
4141
}
4242

4343
return $signature == self::SUCCESS;
@@ -59,7 +59,7 @@ public function run(...$args)
5959

6060
if ($signature == self::FAILURE) {
6161
$this->ackFailure();
62-
throw new MessageException($output['message']);
62+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
6363
}
6464

6565
return $signature == self::SUCCESS ? $output : [];
@@ -82,7 +82,8 @@ public function pullAll(...$args)
8282

8383
if ($signature == self::FAILURE) {
8484
$this->ackFailure();
85-
throw new MessageException($output['message']);
85+
$last = array_pop($output);
86+
throw new MessageException($last['message'] . ' (' . $last['code'] . ')');
8687
}
8788

8889
return $signature == self::SUCCESS ? $output : [];

src/protocol/V3.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ public function hello(...$args): bool
4646
$output = $this->read($signature);
4747

4848
if ($signature == self::FAILURE) {
49-
$this->write($this->packer->pack(0x0E));
50-
throw new MessageException($output['message']);
49+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
5150
}
5251

5352
return $signature == self::SUCCESS;
@@ -74,7 +73,7 @@ public function run(...$args)
7473

7574
if ($signature == self::FAILURE) {
7675
$this->reset();
77-
throw new MessageException($output['message']);
76+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
7877
}
7978

8079
return $signature == self::SUCCESS ? $output : [];
@@ -103,7 +102,7 @@ public function begin(...$args): bool
103102

104103
if ($signature == self::FAILURE) {
105104
$this->reset();
106-
throw new MessageException($output['message']);
105+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
107106
}
108107

109108
return $signature == self::SUCCESS;
@@ -121,7 +120,7 @@ public function commit(...$args): bool
121120

122121
if ($signature == self::FAILURE) {
123122
$this->reset();
124-
throw new MessageException($output['message']);
123+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
125124
}
126125

127126
return $signature == self::SUCCESS;
@@ -139,7 +138,7 @@ public function rollback(...$args): bool
139138

140139
if ($signature == self::FAILURE) {
141140
$this->reset();
142-
throw new MessageException($output['message']);
141+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
143142
}
144143

145144
return $signature == self::SUCCESS;

src/protocol/V4.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ public function pull(...$args)
4141
} while ($signature == self::RECORD);
4242

4343
if ($signature == self::FAILURE) {
44-
$this->reset();
45-
throw new MessageException($output['message']);
44+
$last = array_pop($output);
45+
throw new MessageException($last['message'] . ' (' . $last['code'] . ')');
4646
}
4747

4848
return $output;

src/protocol/V4_1.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ public function hello(...$args): bool
3939
$output = $this->read($signature);
4040

4141
if ($signature == self::FAILURE) {
42-
$this->write($this->packer->pack(0x0E));
43-
throw new MessageException($output['message']);
42+
throw new MessageException($output['message'] . ' (' . $output['code'] . ')');
4443
}
4544

4645
return $signature == self::SUCCESS;

tests/BoltTest.php

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Bolt\tests;
44

55
use Bolt\Bolt;
6+
use Exception;
67

78
/**
89
* Class BoltTest
@@ -11,6 +12,7 @@
1112
* @link https://github.com/stefanak-michal/Bolt
1213
*
1314
* @covers \Bolt\Bolt
15+
* @covers \Bolt\connection\AConnection
1416
* @covers \Bolt\connection\Socket
1517
* @covers \Bolt\connection\StreamSocket
1618
* @covers \Bolt\PackStream\v1\Packer
@@ -21,7 +23,7 @@
2123
* @requires extension sockets
2224
* @requires extension mbstring
2325
*/
24-
class BoltTest extends \Bolt\tests\ATest
26+
class BoltTest extends ATest
2527
{
2628

2729
/**
@@ -46,7 +48,7 @@ public function testHello(): ?Bolt
4648
$this->assertTrue($bolt->hello('Test/1.0', $GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
4749

4850
return $bolt;
49-
} catch (\Exception $e) {
51+
} catch (Exception $e) {
5052
$this->markTestSkipped($e->getMessage());
5153
}
5254

@@ -59,13 +61,17 @@ public function testHello(): ?Bolt
5961
*/
6062
public function testPull(Bolt $bolt)
6163
{
62-
$res = $bolt->run('RETURN 1 AS num, 2 AS cnt');
63-
$this->assertIsArray($res);
64-
$this->assertArrayHasKey('fields', $res);
65-
66-
$res = $bolt->pull();
67-
$this->assertEquals(1, $res[0][0] ?? 0);
68-
$this->assertEquals(2, $res[0][1] ?? 0);
64+
try {
65+
$res = $bolt->run('RETURN 1 AS num, 2 AS cnt');
66+
$this->assertIsArray($res);
67+
$this->assertArrayHasKey('fields', $res);
68+
69+
$res = $bolt->pull();
70+
$this->assertEquals(1, $res[0][0] ?? 0);
71+
$this->assertEquals(2, $res[0][1] ?? 0);
72+
} catch (Exception $e) {
73+
$this->markTestSkipped($e->getMessage());
74+
}
6975
}
7076

7177
/**
@@ -74,8 +80,12 @@ public function testPull(Bolt $bolt)
7480
*/
7581
public function testDiscard(Bolt $bolt)
7682
{
77-
$this->assertNotFalse($bolt->run('MATCH (a:Test) RETURN *'));
78-
$this->assertTrue($bolt->discard());
83+
try {
84+
$this->assertNotFalse($bolt->run('MATCH (a:Test) RETURN *'));
85+
$this->assertTrue($bolt->discard());
86+
} catch (Exception $e) {
87+
$this->markTestSkipped($e->getMessage());
88+
}
7989
}
8090

8191
/**
@@ -84,16 +94,20 @@ public function testDiscard(Bolt $bolt)
8494
*/
8595
public function testNode(Bolt $bolt)
8696
{
87-
$this->assertNotFalse($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
97+
try {
98+
$this->assertNotFalse($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
8899

89-
$created = $bolt->pull();
90-
$this->assertIsArray($created);
91-
$this->assertInstanceOf(\Bolt\structures\Node::class, $created[0][0]);
100+
$created = $bolt->pull();
101+
$this->assertIsArray($created);
102+
$this->assertInstanceOf(\Bolt\structures\Node::class, $created[0][0]);
92103

93-
$this->assertNotFalse($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' DELETE a', [
94-
'a' => $created[0][1]
95-
]));
96-
$this->assertEquals(1, $bolt->pull()[0]['stats']['nodes-deleted'] ?? 0);
104+
$this->assertNotFalse($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' DELETE a', [
105+
'a' => $created[0][1]
106+
]));
107+
$this->assertEquals(1, $bolt->pull()[0]['stats']['nodes-deleted'] ?? 0);
108+
} catch (Exception $e) {
109+
$this->markTestSkipped($e->getMessage());
110+
}
97111
}
98112

99113
/**
@@ -107,18 +121,22 @@ public function testTransaction(Bolt $bolt)
107121
return;
108122
}
109123

110-
$this->assertTrue($bolt->begin());
111-
$this->assertNotFalse($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
112-
$created = $bolt->pull();
113-
$this->assertIsArray($created);
114-
$this->assertTrue($bolt->rollback());
115-
116-
$this->assertNotFalse($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' RETURN COUNT(a)', [
117-
'a' => $created[0][1]
118-
]));
119-
$res = $bolt->pull();
120-
$this->assertIsArray($res);
121-
$this->assertEquals(0, $res[0][0]);
124+
try {
125+
$this->assertTrue($bolt->begin());
126+
$this->assertNotFalse($bolt->run('CREATE (a:Test) RETURN a, ID(a)'));
127+
$created = $bolt->pull();
128+
$this->assertIsArray($created);
129+
$this->assertTrue($bolt->rollback());
130+
131+
$this->assertNotFalse($bolt->run('MATCH (a:Test) WHERE ID(a) = ' . $this->formatParameter($bolt, 'a') . ' RETURN COUNT(a)', [
132+
'a' => $created[0][1]
133+
]));
134+
$res = $bolt->pull();
135+
$this->assertIsArray($res);
136+
$this->assertEquals(0, $res[0][0]);
137+
} catch (Exception $e) {
138+
$this->markTestSkipped($e->getMessage());
139+
}
122140
}
123141

124142
/**
@@ -131,6 +149,7 @@ public function testTransaction(Bolt $bolt)
131149
* @param Bolt $bolt
132150
* @param string $name
133151
* @return string
152+
* @throws Exception
134153
*/
135154
private function formatParameter(Bolt $bolt, string $name): string
136155
{

tests/ErrorsTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace Bolt\tests;
4+
5+
/**
6+
* Class ErrorsTest
7+
*
8+
* @author Michal Stefanak
9+
* @link https://github.com/stefanak-michal/Bolt
10+
*
11+
* @covers \Bolt\error\ConnectException
12+
* @covers \Bolt\error\MessageException
13+
* @covers \Bolt\error\PackException
14+
* @covers \Bolt\error\UnpackException
15+
*
16+
* @package Bolt\tests
17+
* @requires PHP >= 7.1
18+
* @requires extension sockets
19+
* @requires extension mbstring
20+
*/
21+
class ErrorsTest extends ATest
22+
{
23+
public function testConnectException()
24+
{
25+
$this->expectException(\Bolt\error\ConnectException::class);
26+
ini_set('default_socket_timeout', 1000);
27+
$conn = new \Bolt\connection\StreamSocket('1.1.1.1', 7687, 1);
28+
$this->assertInstanceOf(\Bolt\connection\StreamSocket::class, $conn);
29+
$conn->connect();
30+
}
31+
32+
public function testMessageException()
33+
{
34+
$conn = new \Bolt\connection\StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', $GLOBALS['NEO_PORT'] ?? 7687);
35+
$this->assertInstanceOf(\Bolt\connection\StreamSocket::class, $conn);
36+
37+
$bolt = null;
38+
try {
39+
$bolt = new \Bolt\Bolt($conn);
40+
$this->assertInstanceOf(\Bolt\Bolt::class, $bolt);
41+
} catch (\Exception $e) {
42+
$this->markTestIncomplete($e->getMessage());
43+
return;
44+
}
45+
46+
$this->expectException(\Bolt\error\MessageException::class);
47+
$bolt->hello('Test/1.0', $GLOBALS['NEO_USER'], 'wrong password');
48+
}
49+
50+
public function testPackException1()
51+
{
52+
$this->expectException(\Bolt\error\PackException::class);
53+
$packer = new \Bolt\PackStream\v1\Packer();
54+
$this->assertInstanceOf(\Bolt\PackStream\v1\Packer::class, $packer);
55+
$packer->pack(0x00, fopen('php://input', 'r'));
56+
}
57+
58+
public function testPackException2()
59+
{
60+
$conn = new \Bolt\connection\StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', $GLOBALS['NEO_PORT'] ?? 7687);
61+
$this->assertInstanceOf(\Bolt\connection\StreamSocket::class, $conn);
62+
63+
$bolt = null;
64+
try {
65+
$bolt = new \Bolt\Bolt($conn);
66+
$this->assertInstanceOf(\Bolt\Bolt::class, $bolt);
67+
} catch (\Exception $e) {
68+
$this->markTestIncomplete($e->getMessage());
69+
return;
70+
}
71+
72+
$this->expectException(\Bolt\error\PackException::class);
73+
$bolt->setPackStreamVersion(2);
74+
}
75+
}

tests/protocol/V3Test.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public function testReset(V3 $cls)
9696
self::$readArray = [1, 2, 0];
9797
self::$writeBuffer = [hex2bin('0002b00f0000')];
9898

99-
$this->assertNull($cls->reset());
99+
$this->assertTrue($cls->reset());
100100
}
101101

102102
/**

0 commit comments

Comments
 (0)