Skip to content

Commit 98ae0e7

Browse files
committed
Added step file for Cypher compatibility suite. Also refactured test code
1 parent 63167cf commit 98ae0e7

File tree

7 files changed

+372
-368
lines changed

7 files changed

+372
-368
lines changed

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +0,0 @@
1-
[submodule "neokit"]
2-
path = neokit
3-
url = https://github.com/nigelsmall/neokit.git

neokit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit db7ab3580be3f0e09fcb2352408750f45c14a70e
1+
Subproject commit 23ffc81c7a1a1f16369aa1cea71d77d256e57c8d

runtests.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ echo "Running tests with $(python --version)"
6262
pip install --upgrade -r ${DRIVER_HOME}/test_requirements.txt
6363
echo ""
6464
TEST_RUNNER="coverage run -m ${UNITTEST} discover -vfs ${TEST}"
65-
EXAMPLES_RUNNER="coverage run -m ${UNITTEST} discover -vfs examples"
66-
BEHAVE_RUNNER="behave test/tck"
65+
BEHAVE_RUNNER="behave --tags=-db,-in_dev test/tck"
6766
if [ ${RUNNING} -eq 1 ]
6867
then
6968
${TEST_RUNNER}

test/tck/environment.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,18 @@
2323
from behave.log_capture import capture
2424
from test.tck import tck_util
2525

26+
2627
def before_all(context):
2728
context.config.setup_logging()
2829

29-
def before_scenario(context,scenario):
30-
#Empty database
31-
tck_util.send_string("MATCH (n) DETACH DELETE n")
30+
31+
def before_feature(context, feature):
32+
# Workaround. Behave has a different way of tagging than cucumber
33+
if "reset_database" in feature.tags:
34+
for scenario in feature.scenarios:
35+
scenario.tags.append("reset_database")
3236

3337

34-
@capture
35-
def after_scenario(context, scenario):
36-
for step in scenario.steps:
37-
if step.status == 'failed':
38-
logging.error("Scenario :'%s' at step: '%s' failed! ", scenario.name, step.name)
39-
if step.status == 'skipped':
40-
logging.warn("Scenario :'%s' at step: '%s' was skipped! ", scenario.name, step.name)
41-
if step.status == 'passed':
42-
logging.debug("Scenario :'%s' at step: '%s' was passed! ", scenario.name, step.name)
38+
def before_scenario(context, scenario):
39+
if "reset_database" in scenario.tags:
40+
tck_util.send_string("MATCH (n) DETACH DELETE n")

test/tck/steps/bolt_type_steps.py renamed to test/tck/steps/bolt_compability_steps.py

Lines changed: 107 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
# See the License for the specific language governing permissions and
1919
# limitations under the License.
2020

21+
import random
22+
import string
23+
2124
from behave import *
22-
import json
2325

2426
from neo4j.v1 import GraphDatabase
2527
from test.tck import tck_util
28+
from test.tck.tck_util import to_unicode
2629

30+
from neo4j.v1 import compat
2731
use_step_matcher("re")
2832

2933

@@ -34,17 +38,17 @@ def step_impl(context):
3438

3539
@given("a value (?P<input>.+) of type (?P<bolt_type>.+)")
3640
def step_impl(context, input, bolt_type):
37-
context.expected = tck_util.get_bolt_value(bolt_type, input)
41+
context.expected = get_bolt_value(bolt_type, input)
3842

3943

4044
@given("a value of type (?P<bolt_type>.+)")
4145
def step_impl(context, bolt_type):
42-
context.expected = tck_util.get_bolt_value(bolt_type, u' ')
46+
context.expected = get_bolt_value(bolt_type, u' ')
4347

4448

4549
@given("a list value (?P<input>.+) of type (?P<bolt_type>.+)")
4650
def step_impl(context, input, bolt_type):
47-
context.expected = tck_util.get_list_from_feature_file(input, bolt_type)
51+
context.expected = get_list_from_feature_file(input, bolt_type)
4852

4953

5054
@given("an empty list L")
@@ -59,35 +63,35 @@ def step_impl(context):
5963

6064
@given("a String of size (?P<size>\d+)")
6165
def step_impl(context, size):
62-
context.expected = tck_util.get_random_string(int(size))
66+
context.expected = get_random_string(int(size))
6367

6468

6569
@given("a List of size (?P<size>\d+) and type (?P<type>.+)")
6670
def step_impl(context, size, type):
67-
context.expected = tck_util.get_list_of_random_type(int(size), type)
71+
context.expected = get_list_of_random_type(int(size), type)
6872

6973

7074
@given("a Map of size (?P<size>\d+) and type (?P<type>.+)")
7175
def step_impl(context, size, type):
72-
context.expected = tck_util.get_dict_of_random_type(int(size), type)
76+
context.expected = get_dict_of_random_type(int(size), type)
7377

7478

7579
@step("adding a table of lists to the list L")
7680
def step_impl(context):
7781
for row in context.table:
78-
context.L.append(tck_util.get_list_from_feature_file(row[1], row[0]))
82+
context.L.append(get_list_from_feature_file(row[1], row[0]))
7983

8084

8185
@step("adding a table of values to the list L")
8286
def step_impl(context):
8387
for row in context.table:
84-
context.L.append(tck_util.get_bolt_value(row[0], row[1]))
88+
context.L.append(get_bolt_value(row[0], row[1]))
8589

8690

8791
@step("adding a table of values to the map M")
8892
def step_impl(context):
8993
for row in context.table:
90-
context.M['a%d' % len(context.M)] = tck_util.get_bolt_value(row[0], row[1])
94+
context.M['a%d' % len(context.M)] = get_bolt_value(row[0], row[1])
9195

9296

9397
@step("adding map M to list L")
@@ -98,7 +102,7 @@ def step_impl(context):
98102
@when("adding a table of lists to the map M")
99103
def step_impl(context):
100104
for row in context.table:
101-
context.M['a%d' % len(context.M)] = tck_util.get_list_from_feature_file(row[1], row[0])
105+
context.M['a%d' % len(context.M)] = get_list_from_feature_file(row[1], row[0])
102106

103107

104108
@step("adding a copy of map M to map M")
@@ -109,34 +113,26 @@ def step_impl(context):
109113
@when("the driver asks the server to echo this value back")
110114
def step_impl(context):
111115
context.results = {}
112-
context.results["as_string"] = tck_util.send_string("RETURN " + tck_util.as_cypher_text(context.expected))
116+
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
113117
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
114118

115119

116120
@when("the driver asks the server to echo this list back")
117121
def step_impl(context):
118122
context.expected = context.L
119123
context.results = {}
120-
context.results["as_string"] = tck_util.send_string("RETURN " + tck_util.as_cypher_text(context.expected))
124+
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
121125
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
122126

123127

124128
@when("the driver asks the server to echo this map back")
125129
def step_impl(context):
126130
context.expected = context.M
127131
context.results = {}
128-
context.results["as_string"] = tck_util.send_string("RETURN " + tck_util.as_cypher_text(context.expected))
132+
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
129133
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
130134

131135

132-
@then("the result returned from the server should be a single record with a single value")
133-
def step_impl(context):
134-
assert context.results
135-
for result in context.results.values():
136-
assert len(result) == 1
137-
assert len(result[0]) == 1
138-
139-
140136
@step("the value given in the result should be the same as what was sent")
141137
def step_impl(context):
142138
assert len(context.results) > 0
@@ -181,83 +177,96 @@ def step_impl(context):
181177
assert True
182178

183179

184-
@given("init: (?P<statement>.+);")
185-
def step_impl(context, statement):
186-
tck_util.send_string(statement)
187-
188-
189-
@when("running: (?P<statement>.+);")
190-
def step_impl(context, statement):
191-
context.results = {"as_string": tck_util.send_string(statement)}
192-
193-
194-
@given("an empty database")
195-
def step_impl(context):
196-
tck_util.send_string("MATCH (n) DETACH DELETE n")
197-
198-
199-
@then("result should be a path p containing")
200-
def step_impl(context):
201-
result = context.results["as_string"]
202-
given = tck_util.result_to_set(result)
203-
expected = tck_util.text_path_to_set(context.table)
204-
if given != expected:
205-
raise Exception("Path does not match given: %s expected: %s" % (given, expected))
206-
207-
208-
@then("result should be integer\(s\)")
209-
def step_impl(context):
210-
result = context.results["as_string"]
211-
given = tck_util.result_to_set(result)
212-
expected = tck_util.text_int_to_set(context.table)
213-
if given != expected:
214-
raise Exception("Integers does not match given: %s expected: %s" % (given, expected))
215-
216-
217-
@then("result should be node\(s\)")
218-
def step_impl(context):
219-
result = context.results["as_string"]
220-
given = tck_util.result_to_set(result)
221-
expected = tck_util.text_node_to_set(context.table)
222-
if given != expected:
223-
raise Exception("Nodes does not match given: %s expected: %s" % (given, expected))
224-
225-
226-
@then("result should be string\(s\)")
227-
def step_impl(context):
228-
result = context.results["as_string"]
229-
given = tck_util.result_to_set(result)
230-
expected = tck_util.text_string_to_set(context.table)
231-
if given != expected:
232-
raise Exception("Strings does not match given: %s expected: %s" % (given, expected))
233-
234-
235-
@then("result should be relationship\(s\)")
236-
def step_impl(context):
237-
result = context.results["as_string"]
238-
given = tck_util.result_to_set(result)
239-
expected = tck_util.text_relationship_to_set(context.table)
240-
if given != expected:
241-
raise Exception("Relationship does not match given: %s expected: %s" % (given, expected))
242-
243-
244-
@then("result should be empty")
245-
def step_impl(context):
246-
assert context.results
247-
for result in context.results.values():
248-
assert len(result) == 0
180+
def get_bolt_value(type, value):
181+
if type == 'Integer':
182+
return int(value)
183+
if type == 'Float':
184+
return float(value)
185+
if type == 'String':
186+
return to_unicode(value)
187+
if type == 'Null':
188+
return None
189+
if type == 'Boolean':
190+
return bool(value)
191+
raise ValueError('No such type : %s' % type)
192+
193+
194+
def as_cypher_text(expected):
195+
if expected is None:
196+
return "Null"
197+
if isinstance(expected, (str, compat.string)):
198+
return '"' + expected + '"'
199+
if isinstance(expected, float):
200+
return repr(expected).replace('+', '')
201+
if isinstance(expected, list):
202+
l = u'['
203+
for i, val in enumerate(expected):
204+
l += as_cypher_text(val)
205+
if i < len(expected) - 1:
206+
l += u','
207+
l += u']'
208+
return l
209+
if isinstance(expected, dict):
210+
d = u'{'
211+
for i, (key, val) in enumerate(expected.items()):
212+
d += to_unicode(key) + ':'
213+
d += as_cypher_text(val)
214+
if i < len(expected.items()) - 1:
215+
d += u','
216+
d += u'}'
217+
return d
218+
else:
219+
return to_unicode(expected)
220+
221+
222+
def get_list_from_feature_file(string_list, bolt_type):
223+
inputs = string_list.strip('[]')
224+
inputs = inputs.split(',')
225+
list_to_return = []
226+
for value in inputs:
227+
list_to_return.append(get_bolt_value(bolt_type, value))
228+
return list_to_return
229+
230+
231+
def get_random_string(size):
232+
return u''.join(
233+
random.SystemRandom().choice(list(string.ascii_uppercase + string.digits + string.ascii_lowercase)) for _ in
234+
range(size))
235+
236+
237+
def get_random_bool():
238+
return bool(random.randint(0, 1))
239+
240+
241+
def _get_random_func(type):
242+
def get_none():
243+
return None
244+
245+
if type == 'Integer':
246+
fu = random.randint
247+
args = [-9223372036854775808, 9223372036854775808]
248+
elif type == 'Float':
249+
fu = random.random
250+
args = []
251+
elif type == 'String':
252+
fu = get_random_string
253+
args = [3]
254+
elif type == 'Null':
255+
fu = get_none
256+
args = []
257+
elif type == 'Boolean':
258+
fu = get_random_bool
259+
args = []
260+
else:
261+
raise ValueError('No such type : %s' % type)
262+
return (fu, args)
249263

250264

251-
@then('result should be node "(?P<n1>.+)" node "(?P<n2>.+)" and int "(?P<len>\d+)"')
252-
def step_impl(context, n1, n2, len):
253-
result = context.results["as_string"]
254-
given = tck_util.result_to_set(result)
255-
expected = tck_util.node_node_int_to_values(n1, n2, len)
256-
if given != expected:
257-
raise Exception("Mixed response does not match given: %s expected: %s" % (given, expected))
265+
def get_list_of_random_type(size, type):
266+
fu, args = _get_random_func(type)
267+
return [fu(*args) for _ in range(size)]
258268

259269

260-
@when('running "(?P<parameters>.+)": (?P<statement>.+);')
261-
def step_impl(context, parameters, statement):
262-
parameters = json.loads(parameters)
263-
context.results = {"as_string": tck_util.send_parameters(statement, parameters)}
270+
def get_dict_of_random_type(size, type):
271+
fu, args = _get_random_func(type)
272+
return {'a%d' % i: fu(*args) for i in range(size)}

0 commit comments

Comments
 (0)