diff --git a/backend_server/database.py b/backend_server/database.py index f801eb57..4475fb6c 100644 --- a/backend_server/database.py +++ b/backend_server/database.py @@ -36,10 +36,14 @@ def __init__(self, host, dbport, dbname, user, password): self.session = queries.TornadoSession(connection_uri) - def test_series(self, series_id=None): - return self.session.query(sql_queries.test_series(series=series_id)), list_of_dicts + def team_names(self): + return self.session.query(sql_queries.TEAM_NAMES), list_of_values - def teams(self): + def test_series(self, series_id=None, team=None): + sql = sql_queries.test_series(series=series_id, team=team) + return self.session.query(sql, {'team': team}), list_of_dicts + + def teams(self, team=None): def series_by_team(rows): all_series = list_of_dicts(rows) teams = [] @@ -60,7 +64,8 @@ def series_by_team(rows): if current_team: teams.append(current_team) return teams - return self.session.query(sql_queries.test_series(by_teams=True)), series_by_team + sql = sql_queries.test_series(by_teams=True, team=team) + return self.session.query(sql, {'team': team}), series_by_team def history_page_data(self, test_series, start_from, num_of_builds, offset): history_sql = sql_queries.history_page_data(test_series, start_from, num_of_builds, offset) @@ -127,6 +132,13 @@ def list_of_dicts(rows): def single_dict(rows): return list_of_dicts(rows)[0] if rows else None +def list_of_values(rows): + results = [] + for row in rows: + values = [row[key] for key in row] + results.append(values if len(values) > 1 else values[0]) + return results + def history_data(history_rows): suites = [] current_suite = None diff --git a/backend_server/server.py b/backend_server/server.py index 4e968b0f..451b68d2 100644 --- a/backend_server/server.py +++ b/backend_server/server.py @@ -307,6 +307,7 @@ def __init__(self, database): handlers = [ url(r"/$", BaseDataHandler), url(r"/data/?$", BaseDataHandler), + url(r"/data/team_names/?$", TeamNamesDataHandler), url(r"/data/teams/?$", TeamsDataHandler), url(r"/data/series/?$", SeriesDataHandler), url(r"/data/series/(?P[0-9]+)/info/?$", @@ -335,11 +336,7 @@ def __init__(self, database): SuiteLogMessageDataHandler), url(r"/data/test_runs/(?P[0-9]+)/test_cases/(?P[0-9]+)/log_messages?$", TestCaseLogMessageDataHandler), - url( - r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), - - # url(r"/data/history/?$", OldHistoryDataHandler), # Depricated see HistoryDataHandler - # url(r"/data/metadata/?$", OldMetaDataHandler), # Depricated see MetaDataHandler + url(r"/data/keyword_tree/(?P[0-9a-fA-F]{40})/?$", KeywordTreeDataHandler), # For query testing purposes only url(r"/data/foo/?$", FooDataHandler) @@ -357,7 +354,6 @@ def __init__(self, database): class InvalidArgumentError(ValueError): """Exception for communicating an invalid user argument was suplied""" - pass def free_connection(connections): @@ -458,6 +454,33 @@ def get(self): self.redirect('/data/doc') +class TeamNamesDataHandler(BaseHandler): + @tornado.gen.coroutine + def get(self): + """ + --- + tags: + - Teams + summary: Get list of team names + description: Returns an array of all teams found in the database. + produces: + - application/json + responses: + 200: + description: A list of teams + schema: + type: object + properties: + teams: + type: array + items: + type: string + description: Team name + """ + teams = yield coroutine_query(self.database.team_names) + self.write({'teams': teams}) + + class TeamsDataHandler(BaseHandler): @tornado.gen.coroutine def get(self): @@ -470,6 +493,13 @@ def get(self): Nested in each team is listed all series for the team in an array. produces: - application/json + parameters: + - name: team + in: query + description: name of the team + required: false + type: string + allowEmptyValue: true responses: 200: description: A list of teams @@ -493,7 +523,8 @@ def get(self): items: $ref: '#/definitions/SeriesModel' """ - teams = yield coroutine_query(self.database.teams) + team = self.get_argument('team', None) + teams = yield coroutine_query(self.database.teams, team=team) self.write({'teams': teams}) @@ -508,6 +539,13 @@ def get(self): description: List all test series. Most recently updated first produces: - application/json + parameters: + - name: team + in: query + description: name of the team + required: false + type: string + allowEmptyValue: true responses: 200: description: A list of series @@ -519,7 +557,8 @@ def get(self): items: $ref: '#/definitions/SeriesModel' """ - series = yield coroutine_query(self.database.test_series) + team = self.get_argument('team', None) + series = yield coroutine_query(self.database.test_series, team=team) self.write({'series': series}) diff --git a/backend_server/sql_queries.py b/backend_server/sql_queries.py index 5ae2c039..255e7ff3 100644 --- a/backend_server/sql_queries.py +++ b/backend_server/sql_queries.py @@ -9,11 +9,13 @@ ORDER BY call_index::int; """ +TEAM_NAMES = "SELECT DISTINCT team FROM test_series ORDER BY team" + # Build status is aggregated from test cases statuses. # Due to reruns only the last execution of a test case is considered. # Last execution is determined primarily by test start_time if that exists # otherwise by archiving order i.e. test_run_id -def test_series(by_teams=False, series=None): +def test_series(by_teams=False, series=None, team=None): return """ WITH last_builds as ( SELECT series, @@ -53,10 +55,12 @@ def test_series(by_teams=False, series=None): JOIN suite_result ON tsm.test_run_id=suite_result.test_run_id GROUP BY tsm.series ) AS last_build_start_times ON test_series.id=last_build_start_times.series +{team_filter} GROUP BY id, name, team, build_count, build_number, build_id ORDER BY {team_sorting} sorting_value """.format(team_sorting="team," if by_teams else '', # nosec - series_filter='WHERE series={}'.format(int(series)) if series else '') # nosec + series_filter='WHERE series={}'.format(int(series)) if series else '', # nosec + team_filter='WHERE team=%(team)s' if team else '') def test_run_ids(series=None, build_num=None, start_from=None, last=None, offset=0): diff --git a/end_to_end_tests/robot_tests/backend/api/basic.robot b/end_to_end_tests/robot_tests/backend/api/basic.robot index 9f9b6b56..ac84c73b 100644 --- a/end_to_end_tests/robot_tests/backend/api/basic.robot +++ b/end_to_end_tests/robot_tests/backend/api/basic.robot @@ -19,24 +19,26 @@ API documentation page /data/doc /data/doc/ +Team names data + GET /data/team_names + Integer response status 200 + String $.teams[*] + Teams data GET /data/teams Integer response status 200 String $.teams[*].name Integer $.teams[*].series_count + Valid series object $.teams[*].all_builds + Array $.teams[*].series minItems=1 + Valid series object $.teams[*].series[*] - Object $.teams[*].all_builds - Integer $.teams[*].all_builds.id - String $.teams[*].all_builds.name - String $.teams[*].all_builds.team - String $.teams[*].all_builds.last_imported - String $.teams[*].all_builds.last_started - Integer $.teams[*].all_builds.builds - Integer $.teams[*].all_builds.last_build - String $.teams[*].all_builds.last_build_id - String $.teams[*].all_builds.last_status - - Array $.teams[*].series minItems=1 + GET /data/teams?team=TestArchiver + Integer response status 200 + String $.teams[*].name + Integer $.teams[*].series_count + Valid series object $.teams[*].all_builds + Array $.teams[*].series minItems=1 Valid series object $.teams[*].series[*] Series data @@ -45,6 +47,11 @@ Series data Array $.series minItems=1 Valid series object $.series[*] + GET /data/series?team=TestArchiver + Integer response status 200 + Array $.series minItems=1 + Valid series object $.series[*] + Series info data GET /data/series/${FIXTURE_SERIES_ID}/info Integer response status 200