Skip to content

Commit 7b512c5

Browse files
committed
Added statement result tck tests
1 parent 0e838f3 commit 7b512c5

14 files changed

+366
-146
lines changed

neo4j/v1/connection.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from socket import create_connection, SHUT_RDWR, error as SocketError
3232
from struct import pack as struct_pack, unpack as struct_unpack, unpack_from as struct_unpack_from
3333

34+
import errno
35+
3436
from .constants import DEFAULT_PORT, DEFAULT_USER_AGENT, KNOWN_HOSTS, MAGIC_PREAMBLE, \
3537
TRUST_DEFAULT, TRUST_ON_FIRST_USE
3638
from .compat import hex2
@@ -374,6 +376,8 @@ def connect(host, port=None, ssl_context=None, **config):
374376
"""
375377

376378
# Establish a connection to the host and port specified
379+
# Catches refused connections see:
380+
# https://docs.python.org/2/library/errno.html
377381
port = port or DEFAULT_PORT
378382
if __debug__: log_info("~~ [CONNECT] %s %d", host, port)
379383
try:

neo4j/v1/session.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,12 @@ class Driver(object):
103103
def __init__(self, url, **config):
104104
self.url = url
105105
parsed = urlparse(self.url)
106-
transports = ['bolt']
107-
if parsed.scheme in transports:
106+
if parsed.scheme == "bolt":
108107
self.host = parsed.hostname
109108
self.port = parsed.port
110109
else:
111-
raise ProtocolError("Unsupported transport: '%s' in url: '%s'. Supported transports are: '%s'." %
112-
(parsed.scheme, url, transports))
110+
raise ProtocolError("Unsupported URI scheme: '%s' in url: '%s'. Currently only supported 'bolt'." %
111+
(parsed.scheme, url))
113112
self.config = config
114113
self.max_pool_size = config.get("max_pool_size", DEFAULT_MAX_POOL_SIZE)
115114
self.session_pool = deque()
@@ -241,7 +240,7 @@ def keys(self):
241240
# Fetch messages until we have the header or a failure
242241
while self._keys is None and not self._consumed:
243242
self.connection.fetch()
244-
return self._keys
243+
return tuple(self._keys)
245244

246245
def buffer(self):
247246
if self.connection and not self.connection.closed:
@@ -264,9 +263,9 @@ def single(self):
264263
records = list(self)
265264
num_records = len(records)
266265
if num_records == 0:
267-
raise ResultError("No records found in stream")
266+
raise ResultError("Cannot retrieve a single record, because this result is empty.")
268267
elif num_records != 1:
269-
raise ResultError("Multiple records found in stream")
268+
raise ResultError("Expected a result with a single record, but this result contains at least one more.")
270269
else:
271270
return records[0]
272271

@@ -486,9 +485,11 @@ def run(self, statement, parameters=None):
486485
:rtype: :class:`.StatementResult`
487486
"""
488487
if self.transaction:
489-
raise ProtocolError("Please close the currently open transaction object before running more "
490-
"statements/transactions in the current session.")
488+
raise ProtocolError("Statements cannot be run directly on a session with an open transaction;"
489+
" either run from within the transaction or use a different session.")
490+
return self._run(statement, parameters)
491491

492+
def _run(self, statement, parameters=None):
492493
# Ensure the statement is a Unicode value
493494
if isinstance(statement, bytes):
494495
statement = statement.decode("UTF-8")
@@ -521,6 +522,8 @@ def close(self):
521522
"""
522523
if self.last_result:
523524
self.last_result.buffer()
525+
if self.transaction:
526+
self.transaction.close()
524527
self.driver.recycle(self)
525528

526529
def begin_transaction(self):
@@ -529,8 +532,8 @@ def begin_transaction(self):
529532
:return: new :class:`.Transaction` instance.
530533
"""
531534
if self.transaction:
532-
raise ProtocolError("Please close the currently open transaction object before running more "
533-
"statements/transactions in the current session.")
535+
raise ProtocolError("You cannot begin a transaction on a session with an open transaction;"
536+
" either run from within the transaction or use a different session.")
534537
self.transaction = Transaction(self)
535538
return self.transaction
536539

@@ -558,7 +561,7 @@ class Transaction(object):
558561

559562
def __init__(self, session):
560563
self.session = session
561-
self.session.run("BEGIN")
564+
self.session._run("BEGIN")
562565

563566
def __enter__(self):
564567
return self
@@ -576,7 +579,7 @@ def run(self, statement, parameters=None):
576579
:return:
577580
"""
578581
assert not self.closed
579-
return self.session.run(statement, parameters)
582+
return self.session._run(statement, parameters)
580583

581584
def commit(self):
582585
""" Mark this transaction as successful and close in order to
@@ -597,9 +600,9 @@ def close(self):
597600
"""
598601
assert not self.closed
599602
if self.success:
600-
self.session.run("COMMIT")
603+
self.session._run("COMMIT")
601604
else:
602-
self.session.run("ROLLBACK")
605+
self.session._run("ROLLBACK")
603606
self.closed = True
604607
self.session.transaction = None
605608

runtests.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ echo ""
8383

8484
TEST_RUNNER="coverage run -m ${UNITTEST} discover -vfs ${TEST}"
8585
EXAMPLES_RUNNER="coverage run -m ${UNITTEST} discover -vfs examples"
86-
BEHAVE_RUNNER="behave --tags=-db --tags=-in_dev test/tck"
86+
BEHAVE_RUNNER="behave --tags=-db --tags=-tls --tags=-fixed_session_pool test/tck"
8787

8888
if [ ${RUNNING} -eq 1 ]
8989
then
@@ -112,4 +112,4 @@ else
112112

113113
fi
114114

115-
fi
115+
fi

test/tck/environment.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ def after_all(context):
5959

6060

6161
def after_scenario(context, scenario):
62-
pass
6362
for runner in tck_util.runners:
6463
runner.close()
6564

test/tck/resultparser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import json
2222
import re
2323
from neo4j.v1 import Node, Relationship, Path
24-
from tck_util import TestValue
24+
from test_value import TestValue
2525

2626

2727
def parse_values_to_comparable(row):

test/tck/steps/cypher_compability_steps.py

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
from behave import *
2222

2323
from test.tck import tck_util
24-
from test.tck.tck_util import TestValue
25-
from test.tck.resultparser import parse_values, parse_values_to_comparable
24+
from test.tck.resultparser import parse_values
2625

2726
use_step_matcher("re")
2827

@@ -54,51 +53,10 @@ def step_impl(context, statement):
5453

5554
@then("result")
5655
def step_impl(context):
57-
expected = table_to_comparable_result(context.table)
56+
expected = tck_util.table_to_comparable_result(context.table)
5857
assert(len(context.results) > 0)
5958
for result in context.results:
6059
records = list(result)
61-
given = driver_result_to_comparable_result(records)
62-
if not unordered_equal(given, expected):
60+
given = tck_util.driver_result_to_comparable_result(records)
61+
if not tck_util.unordered_equal(given, expected):
6362
raise Exception("Does not match given: \n%s expected: \n%s" % (given, expected))
64-
65-
66-
def _driver_value_to_comparable(val):
67-
if isinstance(val, list):
68-
l = [_driver_value_to_comparable(v) for v in val]
69-
return l
70-
else:
71-
return TestValue(val)
72-
73-
74-
def table_to_comparable_result(table):
75-
result = []
76-
keys = table.headings
77-
for row in table:
78-
result.append(
79-
{keys[i]: parse_values_to_comparable(row[i]) for i in range(len(row))})
80-
return result
81-
82-
83-
def driver_result_to_comparable_result(result):
84-
records = []
85-
for record in result:
86-
records.append({key: _driver_value_to_comparable(record[key]) for key in record})
87-
return records
88-
89-
90-
def unordered_equal(given, expected):
91-
l1 = given[:]
92-
l2 = expected[:]
93-
assert isinstance(l1, list)
94-
assert isinstance(l2, list)
95-
assert len(l1) == len(l2)
96-
for d1 in l1:
97-
size = len(l2)
98-
for d2 in l2:
99-
if d1 == d2:
100-
l2.remove(d2)
101-
break
102-
if size == len(l2):
103-
return False
104-
return True

test/tck/steps/driver_result_api_steps.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ def step_impl(context, expected):
6363
def step_impl(context):
6464
for summary in context.summaries:
6565
for row in context.table:
66-
print(row[0].replace(" ","_"))
67-
print(getattr(summary.counters, row[0].replace(" ","_")))
6866
assert getattr(summary.counters, row[0].replace(" ","_")) == parse_values(row[1])
6967

7068

test/tck/steps/errror_reporting_steps.py renamed to test/tck/steps/error_reporting_steps.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from neo4j.v1.exceptions import ProtocolError, CypherError
2424
from test.tck import tck_util
2525

26-
from neo4j.v1 import compat, GraphDatabase, basic_auth
26+
from neo4j.v1 import GraphDatabase
2727

2828
use_step_matcher("re")
2929

@@ -45,6 +45,8 @@ def step_impl(context):
4545
context.session.run("CREATE (:n)")
4646
except Exception as e:
4747
context.exception = e
48+
finally:
49+
context.session.close()
4850

4951

5052
@step("I start a new `Transaction` with the same session before closing the previous")
@@ -53,12 +55,16 @@ def step_impl(context):
5355
context.session.begin_transaction()
5456
except Exception as e:
5557
context.exception = e
58+
finally:
59+
context.session.close()
5660

5761

5862
@step("I run a non valid cypher statement")
5963
def step_impl(context):
6064
try:
61-
context.driver.session().run("NOT VALID").consume()
65+
s = context.driver.session()
66+
print(s.transaction)
67+
s.run("NOT VALID").consume()
6268
except Exception as e:
6369
context.exception = e
6470

@@ -83,6 +89,7 @@ def step_impl(context):
8389

8490
@step("it throws a `ClientException`")
8591
def step_impl(context):
92+
print(context.exception)
8693
assert context.exception is not None
8794
assert type(context.exception) == ProtocolError or type(context.exception) == CypherError
8895
assert isinstance(context.exception, ProtocolError) or isinstance(context.exception, CypherError)

0 commit comments

Comments
 (0)