Skip to content
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
6 changes: 6 additions & 0 deletions runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ echo "Running tests with $(python --version)"
pip install --upgrade -r ${DRIVER_HOME}/test_requirements.txt
echo ""
TEST_RUNNER="coverage run -m ${UNITTEST} discover -vfs ${TEST}"
BEHAVE_RUNNER="behave test/tck"
if [ ${RUNNING} -eq 1 ]
then
${TEST_RUNNER}
Expand All @@ -73,6 +74,11 @@ else
then
coverage report --show-missing
fi
python -c 'from test.tck.configure_feature_files import *; set_up()'
echo "Feature files downloaded"
neokit/neorun ${NEORUN_OPTIONS} "${BEHAVE_RUNNER}" ${VERSIONS}
python -c 'from test.tck.configure_feature_files import *; clean_up()'
echo "Feature files removed"
fi

# Exit correctly
Expand Down
Empty file added test/tck/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions test/tck/configure_feature_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os
import tarfile

def clean_up():
dir_path = (os.path.dirname(os.path.realpath(__file__)))
files = os.listdir(dir_path)
for f in files:
if not os.path.isdir(f) and ".feature" in f:
os.remove(os.path.join(dir_path, f))


def set_up():
dir_path = (os.path.dirname(os.path.realpath(__file__)))
url = "https://s3-eu-west-1.amazonaws.com/remoting.neotechnology.com/driver-compliance/tck.tar.gz"
file_name = url.split('/')[-1]
_download_tar(url,file_name)

tar = tarfile.open(file_name)
tar.extractall(dir_path)
tar.close()
os.remove(file_name)


def _download_tar(url, file_name):
try:
import urllib2
tar = open(file_name, 'w')
response = urllib2.urlopen(url)
block_sz = 1024
while True:
buffer = response.read(block_sz)
if not buffer:
break
tar.write(buffer)
tar.close()
except ImportError:
from urllib import request
request.urlretrieve(url, file_name)
23 changes: 23 additions & 0 deletions test/tck/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import logging

from test.tck import tck_util
from behave.log_capture import capture


def before_all(context):
# -- SET LOG LEVEL: behave --logging-level=ERROR ...
# on behave command-line or in "behave.ini".
context.config.setup_logging()


@capture
def after_scenario(context, scenario):
for step in scenario.steps:
if step.status == 'failed':
logging.error("Scenario :'%s' at step: '%s' failed! ", scenario.name, step.name)
logging.debug("Expected result: %s", tck_util.as_cypher_text(context.expected))
logging.debug("Actual result: %s", tck_util.as_cypher_text(context.results))
if step.status == 'skipped':
logging.warn("Scenario :'%s' at step: '%s' was skipped! ", scenario.name, step.name)
if step.status == 'passed':
logging.debug("Scenario :'%s' at step: '%s' was passed! ", scenario.name, step.name)
124 changes: 124 additions & 0 deletions test/tck/steps/bolt_type_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from behave import *

from test.tck import tck_util

use_step_matcher("re")


@given("A running database")
def step_impl(context):
return None
# check if running


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


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


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


@given("an empty list L")
def step_impl(context):
context.L = []


@given("an empty map M")
def step_impl(context):
context.M = {}


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


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


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


@step("adding a table of lists to the list L")
def step_impl(context):
for row in context.table:
context.L.append(tck_util.get_list_from_feature_file(row[1], row[0]))


@step("adding a table of values to the list L")
def step_impl(context):
for row in context.table:
context.L.append(tck_util.get_bolt_value(row[0], row[1]))


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


@step("adding map M to list L")
def step_impl(context):
context.L.append(context.M)


@when("adding a table of lists to the map M")
def step_impl(context):
for row in context.table:
context.M['a%d' % len(context.M)] = tck_util.get_list_from_feature_file(row[1], row[0])


@step("adding a copy of map M to map M")
def step_impl(context):
context.M['a%d' % len(context.M)] = context.M.copy()


@when("the driver asks the server to echo this value back")
def step_impl(context):
context.results = {}
context.results["as_string"] = tck_util.send_string("RETURN " + tck_util.as_cypher_text(context.expected))
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})


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


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


@then("the result returned from the server should be a single record with a single value")
def step_impl(context):
assert context.results
for result in context.results.values():
assert len(result) == 1
assert len(result[0]) == 1


@step("the value given in the result should be the same as what was sent")
def step_impl(context):
assert len(context.results) > 0
for result in context.results.values():
result_value = result[0].values()[0]
assert result_value == context.expected
123 changes: 123 additions & 0 deletions test/tck/tck_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import string
import random
from neo4j.v1 import compat

from neo4j.v1 import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost")


def send_string(text):
session = driver.session()
result = session.run(text)
session.close()
return result


def send_parameters(statement, parameters):
session = driver.session()
result = session.run(statement, parameters)
session.close()
return result


def get_bolt_value(type, value):
if type == 'Integer':
return int(value)
if type == 'Float':
return float(value)
if type == 'String':
return to_unicode(value)
if type == 'Null':
return None
if type == 'Boolean':
return bool(value)
raise ValueError('No such type : %s' % type)


def as_cypher_text(expected):
if expected is None:
return "Null"
if isinstance(expected, (str, compat.string)):
return '"' + expected + '"'
if isinstance(expected, float):
return repr(expected).replace('+', '')
if isinstance(expected, list):
l = u'['
for i, val in enumerate(expected):
l += as_cypher_text(val)
if i < len(expected)-1:
l+= u','
l += u']'
return l
if isinstance(expected, dict):
d = u'{'
for i, (key, val) in enumerate(expected.items()):
d += to_unicode(key) + ':'
d += as_cypher_text(val)
if i < len(expected.items())-1:
d+= u','
d += u'}'
return d
else:
return to_unicode(expected)


def get_list_from_feature_file(string_list, bolt_type):
inputs = string_list.strip('[]')
inputs = inputs.split(',')
list_to_return = []
for value in inputs:
list_to_return.append(get_bolt_value(bolt_type, value))
return list_to_return


def get_random_string(size):
return u''.join(
random.SystemRandom().choice(list(string.ascii_uppercase + string.digits + string.ascii_lowercase)) for _ in
range(size))


def get_random_bool():
return bool(random.randint(0, 1))


def _get_random_func(type):
def get_none():
return None

if type == 'Integer':
fu = random.randint
args = [-9223372036854775808, 9223372036854775808]
elif type == 'Float':
fu = random.random
args = []
elif type == 'String':
fu = get_random_string
args = [3]
elif type == 'Null':
fu = get_none
args = []
elif type == 'Boolean':
fu = get_random_bool
args = []
else:
raise ValueError('No such type : %s' % type)
return (fu, args)


def get_list_of_random_type(size, type):
fu, args = _get_random_func(type)
return [fu(*args) for _ in range(size)]


def get_dict_of_random_type(size, type):
fu, args = _get_random_func(type)
return {'a%d' % i: fu(*args) for i in range(size)}

def to_unicode(val):
try:
return unicode(val)
except NameError:
return str(val)

1 change: 1 addition & 0 deletions test_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
behave
coverage
teamcity-messages