tests/elasticsearch: Catch painless script errors and pretty print them
Debugging update painless script is hard as errors are returned in a not really readable JSON format.
To gain debuggig time, wrap search.origin_update
calls when running
elasticsearch tests in order to catch painless script errors and
pretty print them.
Tests will also immediatly fail when such errors are detected.
Below are the kind of pytest
reports we can obtain (I intentionnally
added errors in the script code):
_____________________________________________________________________________ TestElasticsearchSearch.test_search_blocklisted_update _____________________________________________________________________________
self = <swh.search.tests.test_elasticsearch.TestElasticsearchSearch testMethod=test_search_blocklisted_update>
def test_search_blocklisted_update(self):
origin1 = {"url": "http://origin1"}
> self.search.origin_update([origin1])
swh/search/tests/test_search.py:595:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <swh.search.elasticsearch.ElasticSearch object at 0x7f8337865780>, args = ([{'url': 'http://origin1'}],), kwargs = {}, script_error = True
error_detail = 'Painless update script failed (compile error).\nerror type: illegal_argument_exception\nerror reason: invalid declara...nscript stack:\n\n... it_types field value\nLst visit_types = ctx._source ...\n ^---- HERE'
error = {'caused_by': {'reason': 'invalid declaration: cannot resolve type [Lst]', 'type': 'illegal_argument_exception'}, 'lang': 'painless', 'position': {'end': 72, 'offset': 47, 'start': 22}, 'reason': 'compile error', ...}
@py_assert2 = False, @py_assert1 = False, @py_format4 = 'True is False'
@py_format6 = 'Painless update script failed (compile error).\n~error type: illegal_argument_exception\n~error reason: invalid decla...types field value\n~Lst visit_types = ctx._source ...\n~ ^---- HERE\n>assert True is False'
def _origin_update(self, *args, **kwargs):
script_error = False
error_detail = ""
try:
origin_update(*args, **kwargs)
except BulkIndexError as e:
error = e.errors[0].get("update", {}).get("error", {}).get("caused_by")
if error and "script_stack" in error:
script_error = True
error_detail = (
f"Painless update script failed ({error['reason']}).\n"
)
error_detail += f"error type: {error['caused_by']['type']}\n"
error_detail += f"error reason: {error['caused_by']['reason']}\n"
error_detail += "script stack:\n\n" + "\n".join(
error["script_stack"]
)
else:
raise e
> assert script_error is False, error_detail
E AssertionError: Painless update script failed (compile error).
E error type: illegal_argument_exception
E error reason: invalid declaration: cannot resolve type [Lst]
E script stack:
E
E ... it_types field value
E Lst visit_types = ctx._source ...
E ^---- HERE
E assert True is False
swh/search/tests/test_elasticsearch.py:47: AssertionError
_________________________________________________________________________ TestElasticsearchSearch.test_origin_visit_types_update_search __________________________________________________________________________
self = <swh.search.tests.test_elasticsearch.TestElasticsearchSearch testMethod=test_origin_visit_types_update_search>
def test_origin_visit_types_update_search(self):
origin_url = "http://foobar.baz"
self.search.origin_update([{"url": origin_url}])
self.search.flush()
def _add_visit_type(visit_type):
self.search.origin_update(
[{"url": origin_url, "visit_types": [visit_type]}]
)
self.search.flush()
def _check_visit_types(visit_types_list):
for visit_types in visit_types_list:
actual_page = self.search.origin_search(
url_pattern="http", visit_types=visit_types
)
assert actual_page.next_page_token is None
results = [r["url"] for r in actual_page.results]
expected_results = [origin_url]
assert sorted(results) == sorted(expected_results)
_add_visit_type("git")
_check_visit_types([["git"], ["git", "hg"]])
> _add_visit_type("svn")
swh/search/tests/test_search.py:171:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
swh/search/tests/test_search.py:154: in _add_visit_type
[{"url": origin_url, "visit_types": [visit_type]}]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <swh.search.elasticsearch.ElasticSearch object at 0x7f81232aeeb8>, args = ([{'url': 'http://foobar.baz', 'visit_types': ['svn']}],), kwargs = {}, script_error = True
error_detail = 'Painless update script failed (runtime error).\nerror type: illegal_argument_exception\nerror reason: dynamic method ...ource.visit_typescontains(visit_types[i])) {\n \n ^---- HERE'
error = {'caused_by': {'reason': 'dynamic method [java.util.LinkedHashMap, visit_typescontains/1] not found', 'type': 'illegal...exception'}, 'lang': 'painless', 'position': {'end': 425, 'offset': 405, 'start': 357}, 'reason': 'runtime error', ...}
@py_assert2 = False, @py_assert1 = False, @py_format4 = 'True is False'
@py_format6 = 'Painless update script failed (runtime error).\n~error type: illegal_argument_exception\n~error reason: dynamic metho...(visit_types[i])) {\n~ \n~ ^---- HERE\n>assert True is False'
def _origin_update(self, *args, **kwargs):
script_error = False
error_detail = ""
try:
origin_update(*args, **kwargs)
except BulkIndexError as e:
error = e.errors[0].get("update", {}).get("error", {}).get("caused_by")
if error and "script_stack" in error:
script_error = True
error_detail = (
f"Painless update script failed ({error['reason']}).\n"
)
error_detail += f"error type: {error['caused_by']['type']}\n"
error_detail += f"error reason: {error['caused_by']['reason']}\n"
error_detail += "script stack:\n\n" + "\n".join(
error["script_stack"]
)
else:
raise e
> assert script_error is False, error_detail
E AssertionError: Painless update script failed (runtime error).
E error type: illegal_argument_exception
E error reason: dynamic method [java.util.LinkedHashMap, visit_typescontains/1] not found
E script stack:
E
E if (!ctx._source.visit_typescontains(visit_types[i])) {
E
E ^---- HERE
E assert True is False
swh/search/tests/test_elasticsearch.py:47: AssertionError
Migrated from D5853 (view on Phabricator)