-
Notifications
You must be signed in to change notification settings - Fork 199
1.0 tck tests - Error handling #51
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
Changes from all commits
e666b27
12bd86f
b35109e
d5f0db7
28bf075
0e838f3
7b512c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ class which can be used to obtain `Driver` instances that are used for | |
from .compat import integer, string, urlparse | ||
from .connection import connect, Response, RUN, PULL_ALL | ||
from .constants import ENCRYPTED_DEFAULT, TRUST_DEFAULT, TRUST_SIGNED_CERTIFICATES | ||
from .exceptions import CypherError, ResultError | ||
from .exceptions import CypherError, ProtocolError, ResultError | ||
from .ssl_compat import SSL_AVAILABLE, SSLContext, PROTOCOL_SSLv23, OP_NO_SSLv2, CERT_REQUIRED | ||
from .types import hydrated | ||
|
||
|
@@ -107,7 +107,8 @@ def __init__(self, url, **config): | |
self.host = parsed.hostname | ||
self.port = parsed.port | ||
else: | ||
raise ValueError("Unsupported URL scheme: %s" % parsed.scheme) | ||
raise ProtocolError("Unsupported URI scheme: '%s' in url: '%s'. Currently only supported 'bolt'." % | ||
(parsed.scheme, url)) | ||
self.config = config | ||
self.max_pool_size = config.get("max_pool_size", DEFAULT_MAX_POOL_SIZE) | ||
self.session_pool = deque() | ||
|
@@ -239,7 +240,7 @@ def keys(self): | |
# Fetch messages until we have the header or a failure | ||
while self._keys is None and not self._consumed: | ||
self.connection.fetch() | ||
return self._keys | ||
return tuple(self._keys) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this previously coming through as a non-tuple? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it comes as a list There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then 👍 |
||
|
||
def buffer(self): | ||
if self.connection and not self.connection.closed: | ||
|
@@ -262,9 +263,9 @@ def single(self): | |
records = list(self) | ||
num_records = len(records) | ||
if num_records == 0: | ||
raise ResultError("No records found in stream") | ||
raise ResultError("Cannot retrieve a single record, because this result is empty.") | ||
elif num_records != 1: | ||
raise ResultError("Multiple records found in stream") | ||
raise ResultError("Expected a result with a single record, but this result contains at least one more.") | ||
else: | ||
return records[0] | ||
|
||
|
@@ -396,7 +397,6 @@ def contains_updates(self): | |
#: a list of sub-plans | ||
Plan = namedtuple("Plan", ("operator_type", "identifiers", "arguments", "children")) | ||
|
||
|
||
#: A profiled plan describes how the database executed your statement. | ||
#: | ||
#: db_hits: | ||
|
@@ -484,7 +484,12 @@ def run(self, statement, parameters=None): | |
:return: Cypher result | ||
:rtype: :class:`.StatementResult` | ||
""" | ||
if self.transaction: | ||
raise ProtocolError("Statements cannot be run directly on a session with an open transaction;" | ||
" either run from within the transaction or use a different session.") | ||
return self._run(statement, parameters) | ||
|
||
def _run(self, statement, parameters=None): | ||
# Ensure the statement is a Unicode value | ||
if isinstance(statement, bytes): | ||
statement = statement.decode("UTF-8") | ||
|
@@ -517,14 +522,18 @@ def close(self): | |
""" | ||
if self.last_result: | ||
self.last_result.buffer() | ||
if self.transaction: | ||
self.transaction.close() | ||
self.driver.recycle(self) | ||
|
||
def begin_transaction(self): | ||
""" Create a new :class:`.Transaction` within this session. | ||
|
||
:return: new :class:`.Transaction` instance. | ||
""" | ||
assert not self.transaction | ||
if self.transaction: | ||
raise ProtocolError("You cannot begin a transaction on a session with an open transaction;" | ||
" either run from within the transaction or use a different session.") | ||
self.transaction = Transaction(self) | ||
return self.transaction | ||
|
||
|
@@ -552,7 +561,7 @@ class Transaction(object): | |
|
||
def __init__(self, session): | ||
self.session = session | ||
self.session.run("BEGIN") | ||
self.session._run("BEGIN") | ||
|
||
def __enter__(self): | ||
return self | ||
|
@@ -570,7 +579,7 @@ def run(self, statement, parameters=None): | |
:return: | ||
""" | ||
assert not self.closed | ||
return self.session.run(statement, parameters) | ||
return self.session._run(statement, parameters) | ||
|
||
def commit(self): | ||
""" Mark this transaction as successful and close in order to | ||
|
@@ -591,9 +600,9 @@ def close(self): | |
""" | ||
assert not self.closed | ||
if self.success: | ||
self.session.run("COMMIT") | ||
self.session._run("COMMIT") | ||
else: | ||
self.session.run("ROLLBACK") | ||
self.session._run("ROLLBACK") | ||
self.closed = True | ||
self.session.transaction = None | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#!/usr/bin/env python | ||
# -*- encoding: utf-8 -*- | ||
|
||
# Copyright (c) 2002-2016 "Neo Technology," | ||
# Network Engine for Objects in Lund AB [http://neotechnology.com] | ||
# | ||
# This file is part of Neo4j. | ||
# | ||
# 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. | ||
|
||
from behave import * | ||
|
||
from neo4j.v1.exceptions import ProtocolError, CypherError | ||
from test.tck import tck_util | ||
|
||
from neo4j.v1 import GraphDatabase | ||
|
||
use_step_matcher("re") | ||
|
||
|
||
@given("I have a driver") | ||
def step_impl(context): | ||
context.driver = tck_util.driver | ||
|
||
|
||
@step("I start a `Transaction` through a session") | ||
def step_impl(context): | ||
context.session = context.driver.session() | ||
context.session.begin_transaction() | ||
|
||
|
||
@step("`run` a query with that same session without closing the transaction first") | ||
def step_impl(context): | ||
try: | ||
context.session.run("CREATE (:n)") | ||
except Exception as e: | ||
context.exception = e | ||
finally: | ||
context.session.close() | ||
|
||
|
||
@step("I start a new `Transaction` with the same session before closing the previous") | ||
def step_impl(context): | ||
try: | ||
context.session.begin_transaction() | ||
except Exception as e: | ||
context.exception = e | ||
finally: | ||
context.session.close() | ||
|
||
|
||
@step("I run a non valid cypher statement") | ||
def step_impl(context): | ||
try: | ||
s = context.driver.session() | ||
print(s.transaction) | ||
s.run("NOT VALID").consume() | ||
except Exception as e: | ||
context.exception = e | ||
|
||
|
||
@step("I set up a driver to an incorrect port") | ||
def step_impl(context): | ||
try: | ||
context.driver = GraphDatabase.driver("bolt://localhost:7777") | ||
context.driver.session() | ||
except Exception as e: | ||
context.exception = e | ||
|
||
|
||
@step("I set up a driver with wrong scheme") | ||
def step_impl(context): | ||
try: | ||
context.driver = GraphDatabase.driver("wrong://localhost") | ||
context.driver.session() | ||
except Exception as e: | ||
context.exception = e | ||
|
||
|
||
@step("it throws a `ClientException`") | ||
def step_impl(context): | ||
print(context.exception) | ||
assert context.exception is not None | ||
assert type(context.exception) == ProtocolError or type(context.exception) == CypherError | ||
assert isinstance(context.exception, ProtocolError) or isinstance(context.exception, CypherError) | ||
assert str(context.exception).startswith(context.table.rows[0][0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment might be useful here to highlight what errors these are.