From 8deea9ade08fe15fe4aa821e385f79ca1469f8c5 Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Mon, 26 Apr 2021 11:23:10 +0300 Subject: [PATCH 1/6] Added backend for logging with keywords --- backend_server/database.py | 6 + backend_server/server.py | 103 +++++++++++++++++- backend_server/sql_queries.py | 24 ++++ .../backend/api/testing_log_exec_path.robot | 25 +++++ 4 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 end_to_end_tests/robot_tests/backend/api/testing_log_exec_path.robot diff --git a/backend_server/database.py b/backend_server/database.py index f801eb57..9cee0dab 100644 --- a/backend_server/database.py +++ b/backend_server/database.py @@ -104,6 +104,10 @@ def test_case_log_messages(self, test_run_id, test_case): sql = sql_queries.log_messages(test_run_id, test_id=test_case) return self.session.query(sql), list_of_dicts + def test_case_log_messages_with_build(self, series, build_number, test_case): + sql = sql_queries.log_messages_with_build(series, build_number, test_id=test_case) + return self.session.query(sql), list_of_dicts + def keyword_tree(self, fingerprint): sql = "SELECT * FROM keyword_tree WHERE fingerprint=%(fingerprint)s" return self.session.query(sql, {'fingerprint': fingerprint}), single_dict @@ -114,6 +118,8 @@ def subtrees(self, fingerprint): def keyword_analysis(self, test_series, build_number): return self.session.query(sql_queries.keyword_analysis(test_series, build_number)), list_of_dicts + def keyword_tree_with_test_id(self, series, build_number, test_run): + return self.session.query(sql_queries.fingerprints_with_id(series, build_number, test_run)), list_of_dicts def list_of_dicts(rows): results = [] diff --git a/backend_server/server.py b/backend_server/server.py index 4e968b0f..bca640ab 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -1,7 +1,7 @@ import argparse import json import sys - +import copy import tornado.httpserver import tornado.ioloop import tornado.web @@ -337,7 +337,9 @@ def __init__(self, database): TestCaseLogMessageDataHandler), url( r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), - + url( + r"/data/testcase_keywords/(?P[0-9]+)/builds/(?P[0-9]+)/test_cases/(?P[0-9]+)", TestcaseKeywordHandler), + # url(r"/data/history/?$", OldHistoryDataHandler), # Depricated see HistoryDataHandler # url(r"/data/metadata/?$", OldMetaDataHandler), # Depricated see MetaDataHandler @@ -427,6 +429,8 @@ def keyword_tree(self, fingerprint): if keyword_tree: keyword_tree['children'] = [] keyword_tree = yield self.child_trees(keyword_tree) + keyword_tree['keyword_amount'] = len(keyword_tree['children']) + (1 if keyword_tree['keyword'] else 0) + keyword_tree['log_messages'] = [] return keyword_tree return None @@ -439,13 +443,14 @@ def child_trees(self, keyword_tree): child_tree = self.tree_from_cache(child['fingerprint']) if not child_tree: child_tree = yield self.child_trees(child) + child_tree['log_messages'] = [] self._keyword_tree_cache[child['fingerprint']] = child_tree keyword_tree['children'].append(child_tree) return keyword_tree def tree_from_cache(self, fingerprint): try: - return self._keyword_tree_cache.get(fingerprint, None) + return copy.deepcopy(self._keyword_tree_cache.get(fingerprint, None)) except AttributeError: self._keyword_tree_cache = {} return None @@ -1482,6 +1487,98 @@ def get(self, series, build_number): statistics = yield coroutine_query(self.database.keyword_analysis, series, build_number) self.write({'statistics': statistics}) +class TestcaseKeywordHandler(BaseHandler): + @tornado.gen.coroutine + def get(self, series, build_number, test_run): + """ + --- + tags: + - Test Case Keywords + summary: Keywords of Test Cases + description: List of keywords within a Test Case Setup, Execution, Teardown and their logs, in the order of execution + produces: + - application/json + parameters: + - name: series + in: path + description: series id + required: true + type: integer + - name: build_number + in: path + description: build number + required: true + type: integer + - name: test_run + in: path + description: test run + required: true + type: integer + responses: + 200: + description: List of keywords within a Test Case Setup, Execution, Teardown and their logs + schema: + type: object + properties: + statistics: + type: array + items: + $ref: '#/definitions/BuildKeywordAnalysisObjectModel' + """ + testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_id, series, build_number, test_run) + log_messages = yield coroutine_query(self.database.test_case_log_messages_with_build, series, build_number, test_run) + setup_fingerprint=(testcase_fingerprints[0]['setup_fingerprint']) + execution_fingerprint=(testcase_fingerprints[0]['execution_fingerprint']) + teardown_fingerprint=(testcase_fingerprints[0]['teardown_fingerprint']) + keyword_array = {'setup': None, 'execution': None, 'teardown': None} + if setup_fingerprint: + keyword_array['setup'] = yield self.keyword_tree(setup_fingerprint.lower()) + if execution_fingerprint: + keyword_array['execution'] = yield self.keyword_tree(execution_fingerprint.lower()) + if teardown_fingerprint: + keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) + + amount_of_setup= 1 if setup_fingerprint else 0 + amount_of_execution=int(keyword_array['execution']['keyword_amount']) + for log in log_messages: + parsed_execution_path = (self.parse_execution_path(log['execution_path'])) + if(int(parsed_execution_path[0]) <= amount_of_setup): + if(len(parsed_execution_path) == 1): + keyword_array['setup']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') + elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): + if amount_of_setup is 1: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') + else: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') + else: + if(len(parsed_execution_path) == 1): + keyword_array['teardown']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['teardown'], parsed_execution_path, log, 'teardown') + + self.write({'keywords': keyword_array}) + + def set_log(self, tree, path, log, state): + if state == 'setup' or state =='teardown': + path=path[1:] + else: + # If the state is only execution we assume there is a setup and fix indexes accordingly + if(state == 'execution'): + path[0]=(path[0]-1) + for number in path: + if(number-1 < 0): + tree=tree['children'][number] + else: + tree=tree['children'][(number-1)] + + tree['log_messages'].append(log['message']) + + def parse_execution_path(self, execution_path): + remove_test_case = execution_path.split('-k') + test_cases_int = list(map(lambda x: int(x), remove_test_case[1:])) + return test_cases_int class FooDataHandler(BaseHandler): def get(self): diff --git a/backend_server/sql_queries.py b/backend_server/sql_queries.py index 334c322b..d28bb703 100644 --- a/backend_server/sql_queries.py +++ b/backend_server/sql_queries.py @@ -448,6 +448,20 @@ def log_messages(test_run_id, suite_id=None, test_id=None): suite_filter="AND suite_id={}".format(int(suite_id)) if suite_id else '', test_filter="test_id={}".format(int(test_id)) if test_id else 'test_id IS NULL') +def log_messages_with_build(series, build_number, suite_id=None, test_id=None): + return """ +SELECT * +FROM log_message +WHERE test_run_id IN ({test_run_ids}) + AND {test_filter} + {suite_filter} +ORDER BY timestamp, id +""".format(suite_filter="AND suite_id={}".format(int(suite_id)) if suite_id else '', + test_filter="test_id={}".format(int(test_id)) if test_id else 'test_id IS NULL', + test_run_ids=test_run_ids(series, build_num=build_number)) + + + def most_stable_tests(series, start_from, last, offset, limit, limit_offset, stable): return """ SELECT suite_id, suite_name, suite_full_name, @@ -518,3 +532,13 @@ def keyword_analysis(series, build_number): GROUP BY tree.library, tree.keyword, total_elapsed.total ORDER BY total DESC """.format(test_run_ids=test_run_ids(series, build_num=build_number)) + +def fingerprints_with_id(series, build_number,test_run): + return """ +SELECT setup_fingerprint, execution_fingerprint, + teardown_fingerprint, test_id, + test_run_id, execution_path +FROM test_result +WHERE test_id={test_id} and test_run_id IN ({test_run_ids}) +""".format(test_id=test_run, + test_run_ids=test_run_ids(series, build_num=build_number)) \ No newline at end of file diff --git a/end_to_end_tests/robot_tests/backend/api/testing_log_exec_path.robot b/end_to_end_tests/robot_tests/backend/api/testing_log_exec_path.robot new file mode 100644 index 00000000..a37814b3 --- /dev/null +++ b/end_to_end_tests/robot_tests/backend/api/testing_log_exec_path.robot @@ -0,0 +1,25 @@ +*** Settings *** +Force Tags exec_path + +*** Test cases *** + +API documentation page + [Setup] Run Keywords Empty Keyword Info Log Keyword + [Teardown] Run Keywords Empty Keyword Info Log Keyword + Empty Keyword + Info Log Keyword + Warn Log Keyword + Empty Keyword + Info Log Keyword + +*** Keywords *** + + +Empty Keyword + No Operation + +Info Log Keyword + Log Keyword INFO + +Warn Log Keyword + Log Keyword WARN \ No newline at end of file From 0809bd2d6f268c2329ad34dfff275b5c49b1cb30 Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Mon, 26 Apr 2021 11:38:12 +0300 Subject: [PATCH 2/6] Added 404 for incorrect indexes --- backend_server/server.py | 69 +++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/backend_server/server.py b/backend_server/server.py index bca640ab..e19de628 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -1525,41 +1525,44 @@ def get(self, series, build_number, test_run): items: $ref: '#/definitions/BuildKeywordAnalysisObjectModel' """ - testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_id, series, build_number, test_run) - log_messages = yield coroutine_query(self.database.test_case_log_messages_with_build, series, build_number, test_run) - setup_fingerprint=(testcase_fingerprints[0]['setup_fingerprint']) - execution_fingerprint=(testcase_fingerprints[0]['execution_fingerprint']) - teardown_fingerprint=(testcase_fingerprints[0]['teardown_fingerprint']) - keyword_array = {'setup': None, 'execution': None, 'teardown': None} - if setup_fingerprint: - keyword_array['setup'] = yield self.keyword_tree(setup_fingerprint.lower()) - if execution_fingerprint: - keyword_array['execution'] = yield self.keyword_tree(execution_fingerprint.lower()) - if teardown_fingerprint: - keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) - - amount_of_setup= 1 if setup_fingerprint else 0 - amount_of_execution=int(keyword_array['execution']['keyword_amount']) - for log in log_messages: - parsed_execution_path = (self.parse_execution_path(log['execution_path'])) - if(int(parsed_execution_path[0]) <= amount_of_setup): - if(len(parsed_execution_path) == 1): - keyword_array['setup']['log_messages'].append(log['message']) - else: - self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') - elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): - if amount_of_setup is 1: - self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') - else: - self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') - else: - if(len(parsed_execution_path) == 1): - keyword_array['teardown']['log_messages'].append(log['message']) + try: + testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_id, series, build_number, test_run) + log_messages = yield coroutine_query(self.database.test_case_log_messages_with_build, series, build_number, test_run) + setup_fingerprint=(testcase_fingerprints[0]['setup_fingerprint']) + execution_fingerprint=(testcase_fingerprints[0]['execution_fingerprint']) + teardown_fingerprint=(testcase_fingerprints[0]['teardown_fingerprint']) + keyword_array = {'setup': None, 'execution': None, 'teardown': None} + if setup_fingerprint: + keyword_array['setup'] = yield self.keyword_tree(setup_fingerprint.lower()) + if execution_fingerprint: + keyword_array['execution'] = yield self.keyword_tree(execution_fingerprint.lower()) + if teardown_fingerprint: + keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) + + amount_of_setup= 1 if setup_fingerprint else 0 + amount_of_execution=int(keyword_array['execution']['keyword_amount']) + for log in log_messages: + parsed_execution_path = (self.parse_execution_path(log['execution_path'])) + if(int(parsed_execution_path[0]) <= amount_of_setup): + if(len(parsed_execution_path) == 1): + keyword_array['setup']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') + elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): + if amount_of_setup is 1: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') + else: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') else: - self.set_log(keyword_array['teardown'], parsed_execution_path, log, 'teardown') + if(len(parsed_execution_path) == 1): + keyword_array['teardown']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['teardown'], parsed_execution_path, log, 'teardown') + + self.write({'keywords': keyword_array}) + except IndexError: + self.send_not_found_response() - self.write({'keywords': keyword_array}) - def set_log(self, tree, path, log, state): if state == 'setup' or state =='teardown': path=path[1:] From aaed7cb0b1f44966e7d2847baf31a49dc17fc5f1 Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Mon, 26 Apr 2021 11:42:42 +0300 Subject: [PATCH 3/6] removed useless keyword_amount stat --- backend_server/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend_server/server.py b/backend_server/server.py index e19de628..d0180b68 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -429,7 +429,6 @@ def keyword_tree(self, fingerprint): if keyword_tree: keyword_tree['children'] = [] keyword_tree = yield self.child_trees(keyword_tree) - keyword_tree['keyword_amount'] = len(keyword_tree['children']) + (1 if keyword_tree['keyword'] else 0) keyword_tree['log_messages'] = [] return keyword_tree return None @@ -1540,7 +1539,8 @@ def get(self, series, build_number, test_run): keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) amount_of_setup= 1 if setup_fingerprint else 0 - amount_of_execution=int(keyword_array['execution']['keyword_amount']) + amount_of_execution=int(len(keyword_array['execution']['children'])) + for log in log_messages: parsed_execution_path = (self.parse_execution_path(log['execution_path'])) if(int(parsed_execution_path[0]) <= amount_of_setup): From df7007877b86a93d75fff7f1cb46755397e93b2a Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Mon, 26 Apr 2021 11:53:06 +0300 Subject: [PATCH 4/6] codacy fixes --- backend_server/server.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend_server/server.py b/backend_server/server.py index d0180b68..2a51e04e 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -339,7 +339,6 @@ def __init__(self, database): r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), url( r"/data/testcase_keywords/(?P[0-9]+)/builds/(?P[0-9]+)/test_cases/(?P[0-9]+)", TestcaseKeywordHandler), - # url(r"/data/history/?$", OldHistoryDataHandler), # Depricated see HistoryDataHandler # url(r"/data/metadata/?$", OldMetaDataHandler), # Depricated see MetaDataHandler @@ -1549,7 +1548,7 @@ def get(self, series, build_number, test_run): else: self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): - if amount_of_setup is 1: + if amount_of_setup == 1: self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') else: self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') From 6b140f1f135f4028788007959a8b1e684c5c1527 Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Tue, 27 Apr 2021 14:06:08 +0300 Subject: [PATCH 5/6] Added possibility to query with test_run_id --- backend_server/database.py | 7 +- backend_server/server.py | 172 ++++++++++++++++++++++------------ backend_server/sql_queries.py | 14 ++- 3 files changed, 128 insertions(+), 65 deletions(-) diff --git a/backend_server/database.py b/backend_server/database.py index 9cee0dab..34440bbf 100644 --- a/backend_server/database.py +++ b/backend_server/database.py @@ -118,8 +118,11 @@ def subtrees(self, fingerprint): def keyword_analysis(self, test_series, build_number): return self.session.query(sql_queries.keyword_analysis(test_series, build_number)), list_of_dicts - def keyword_tree_with_test_id(self, series, build_number, test_run): - return self.session.query(sql_queries.fingerprints_with_id(series, build_number, test_run)), list_of_dicts + def keyword_tree_with_test_id(self, series, build_number, test_id): + return self.session.query(sql_queries.fingerprints_with_id(series, build_number, test_id)), list_of_dicts + + def keyword_tree_with_test_run_and_id(self, test_run_id, test_id): + return self.session.query(sql_queries.fingerprints_with_run_and_id(test_run_id, test_id)), list_of_dicts def list_of_dicts(rows): results = [] diff --git a/backend_server/server.py b/backend_server/server.py index 2a51e04e..5b94e501 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -338,7 +338,10 @@ def __init__(self, database): url( r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), url( - r"/data/testcase_keywords/(?P[0-9]+)/builds/(?P[0-9]+)/test_cases/(?P[0-9]+)", TestcaseKeywordHandler), + r"/data/testcase_keywords/(?P[0-9]+)/builds/(?P[0-9]+)/test_id/(?P[0-9]+)", TestcaseKeywordHandler), + url( + r"/data/testcase_keywords/test_run_id/(?P[0-9]+)/test_id/(?P[0-9]+)", TestcaseKeywordHandlerWithRun), + # url(r"/data/history/?$", OldHistoryDataHandler), # Depricated see HistoryDataHandler # url(r"/data/metadata/?$", OldMetaDataHandler), # Depricated see MetaDataHandler @@ -1485,9 +1488,68 @@ def get(self, series, build_number): statistics = yield coroutine_query(self.database.keyword_analysis, series, build_number) self.write({'statistics': statistics}) -class TestcaseKeywordHandler(BaseHandler): +class KeywordLogHandler(BaseHandler): + def generate_keyword_array(self, testcase_fingerprints, log_messages): + keyword_array = {'setup': None, 'execution': None, 'teardown': None} + + setup_fingerprint=(testcase_fingerprints[0]['setup_fingerprint']) + execution_fingerprint=(testcase_fingerprints[0]['execution_fingerprint']) + teardown_fingerprint=(testcase_fingerprints[0]['teardown_fingerprint']) + if setup_fingerprint: + keyword_array['setup'] = yield self.keyword_tree(setup_fingerprint.lower()) + if execution_fingerprint: + keyword_array['execution'] = yield self.keyword_tree(execution_fingerprint.lower()) + if teardown_fingerprint: + keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) + + amount_of_setup= 1 if not keyword_array['setup'] == None else 0 + amount_of_execution=int(len(keyword_array['execution']['children'])) + + for log in log_messages: + parsed_execution_path = (self.parse_execution_path(log['execution_path'])) + if(int(parsed_execution_path[0]) <= amount_of_setup): + if(len(parsed_execution_path) == 1): + keyword_array['setup']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') + elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): + if amount_of_setup == 1: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') + else: + self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') + else: + if(len(parsed_execution_path) == 1): + keyword_array['teardown']['log_messages'].append(log['message']) + else: + self.set_log(keyword_array['teardown'], parsed_execution_path, log, 'teardown') + + return keyword_array + + @classmethod + def set_log(self, tree, path, log, state): + if state == 'setup' or state =='teardown': + path=path[1:] + else: + # If the state is only execution we assume there is a setup and fix indexes accordingly + if(state == 'execution'): + path[0]=(path[0]-1) + for number in path: + if(number-1 < 0): + tree=tree['children'][number] + else: + tree=tree['children'][(number-1)] + + tree['log_messages'].append(log['message']) + + @classmethod + def parse_execution_path(self, execution_path): + remove_test_case = execution_path.split('-k') + test_cases_int = list(map(lambda x: int(x), remove_test_case[1:])) + return test_cases_int + +class TestcaseKeywordHandler(KeywordLogHandler): @tornado.gen.coroutine - def get(self, series, build_number, test_run): + def get(self, series, build_number, test_id): """ --- tags: @@ -1507,9 +1569,9 @@ def get(self, series, build_number, test_run): description: build number required: true type: integer - - name: test_run + - name: test_id in: path - description: test run + description: test id required: true type: integer responses: @@ -1524,70 +1586,58 @@ def get(self, series, build_number, test_run): $ref: '#/definitions/BuildKeywordAnalysisObjectModel' """ try: - testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_id, series, build_number, test_run) - log_messages = yield coroutine_query(self.database.test_case_log_messages_with_build, series, build_number, test_run) - setup_fingerprint=(testcase_fingerprints[0]['setup_fingerprint']) - execution_fingerprint=(testcase_fingerprints[0]['execution_fingerprint']) - teardown_fingerprint=(testcase_fingerprints[0]['teardown_fingerprint']) - keyword_array = {'setup': None, 'execution': None, 'teardown': None} - if setup_fingerprint: - keyword_array['setup'] = yield self.keyword_tree(setup_fingerprint.lower()) - if execution_fingerprint: - keyword_array['execution'] = yield self.keyword_tree(execution_fingerprint.lower()) - if teardown_fingerprint: - keyword_array['teardown'] = yield self.keyword_tree(teardown_fingerprint.lower()) - - amount_of_setup= 1 if setup_fingerprint else 0 - amount_of_execution=int(len(keyword_array['execution']['children'])) - - for log in log_messages: - parsed_execution_path = (self.parse_execution_path(log['execution_path'])) - if(int(parsed_execution_path[0]) <= amount_of_setup): - if(len(parsed_execution_path) == 1): - keyword_array['setup']['log_messages'].append(log['message']) - else: - self.set_log(keyword_array['setup'], parsed_execution_path, log, 'setup') - elif(int(parsed_execution_path[0]) <= (amount_of_setup + amount_of_execution)): - if amount_of_setup == 1: - self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution') - else: - self.set_log(keyword_array['execution'], parsed_execution_path, log, 'execution_no_setup') - else: - if(len(parsed_execution_path) == 1): - keyword_array['teardown']['log_messages'].append(log['message']) - else: - self.set_log(keyword_array['teardown'], parsed_execution_path, log, 'teardown') - + testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_id, series, build_number, test_id) + log_messages = yield coroutine_query(self.database.test_case_log_messages_with_build, series, build_number, test_id) + keyword_array = yield from self.generate_keyword_array(testcase_fingerprints, log_messages) self.write({'keywords': keyword_array}) except IndexError: self.send_not_found_response() - def set_log(self, tree, path, log, state): - if state == 'setup' or state =='teardown': - path=path[1:] - else: - # If the state is only execution we assume there is a setup and fix indexes accordingly - if(state == 'execution'): - path[0]=(path[0]-1) - for number in path: - if(number-1 < 0): - tree=tree['children'][number] - else: - tree=tree['children'][(number-1)] - - tree['log_messages'].append(log['message']) - - def parse_execution_path(self, execution_path): - remove_test_case = execution_path.split('-k') - test_cases_int = list(map(lambda x: int(x), remove_test_case[1:])) - return test_cases_int - +class TestcaseKeywordHandlerWithRun(KeywordLogHandler): + @tornado.gen.coroutine + def get(self, test_run_id, test_id): + """ + --- + tags: + - Test Case Keywords With Run + summary: Keywords of Test Cases With Test Run ID + description: List of keywords within a Test Case Setup, Execution, Teardown and their logs, in the order of execution + produces: + - application/json + parameters: + - name: test_run_id + in: path + description: series id + required: true + type: integer + - name: test_id + in: path + description: test id + required: true + type: integer + responses: + 200: + description: List of keywords within a Test Case Setup, Execution, Teardown and their logs + schema: + type: object + properties: + statistics: + type: array + items: + $ref: '#/definitions/BuildKeywordAnalysisObjectModel' + """ + try: + testcase_fingerprints = yield coroutine_query(self.database.keyword_tree_with_test_run_and_id, test_run_id, test_id) + log_messages = yield coroutine_query(self.database.test_case_log_messages, test_run_id, test_id) + keyword_array = yield from self.generate_keyword_array(testcase_fingerprints, log_messages) + self.write({'keywords': keyword_array}) + except IndexError: + self.send_not_found_response() + class FooDataHandler(BaseHandler): def get(self): self.write({'suites': []}) - - def main(): parser = argparse.ArgumentParser( description='Test manager 2.0 backend server') diff --git a/backend_server/sql_queries.py b/backend_server/sql_queries.py index d28bb703..8b4ec25d 100644 --- a/backend_server/sql_queries.py +++ b/backend_server/sql_queries.py @@ -533,12 +533,22 @@ def keyword_analysis(series, build_number): ORDER BY total DESC """.format(test_run_ids=test_run_ids(series, build_num=build_number)) -def fingerprints_with_id(series, build_number,test_run): +def fingerprints_with_run_and_id(test_run_id, test_id): + return """ +SELECT setup_fingerprint, execution_fingerprint, + teardown_fingerprint, test_id, + test_run_id, execution_path +FROM test_result +WHERE test_id={test_id} and test_run_id={test_run_id} +""".format(test_id=test_id, + test_run_id= test_run_id) + +def fingerprints_with_id(series, build_number,test_id): return """ SELECT setup_fingerprint, execution_fingerprint, teardown_fingerprint, test_id, test_run_id, execution_path FROM test_result WHERE test_id={test_id} and test_run_id IN ({test_run_ids}) -""".format(test_id=test_run, +""".format(test_id=test_id, test_run_ids=test_run_ids(series, build_num=build_number)) \ No newline at end of file From 80136d1b7dd6b37569a448e00ca03e02c250270e Mon Sep 17 00:00:00 2001 From: lauri_koskela Date: Tue, 27 Apr 2021 14:08:23 +0300 Subject: [PATCH 6/6] some changes for docs --- backend_server/server.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend_server/server.py b/backend_server/server.py index 5b94e501..b09dfb3b 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -338,7 +338,7 @@ def __init__(self, database): url( r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), url( - r"/data/testcase_keywords/(?P[0-9]+)/builds/(?P[0-9]+)/test_id/(?P[0-9]+)", TestcaseKeywordHandler), + r"/data/testcase_keywords/series/(?P[0-9]+)/builds/(?P[0-9]+)/test_id/(?P[0-9]+)", TestcaseKeywordHandler), url( r"/data/testcase_keywords/test_run_id/(?P[0-9]+)/test_id/(?P[0-9]+)", TestcaseKeywordHandlerWithRun), @@ -1599,7 +1599,7 @@ def get(self, test_run_id, test_id): """ --- tags: - - Test Case Keywords With Run + - Test Case Keywords summary: Keywords of Test Cases With Test Run ID description: List of keywords within a Test Case Setup, Execution, Teardown and their logs, in the order of execution produces: @@ -1607,7 +1607,7 @@ def get(self, test_run_id, test_id): parameters: - name: test_run_id in: path - description: series id + description: test run id required: true type: integer - name: test_id