From 6ffbb81ec808aa615c7dad95fe6328ea5cc9c7b5 Mon Sep 17 00:00:00 2001 From: chenjiankun Date: Sat, 21 Apr 2018 08:53:03 +0000 Subject: Add testing gating reporting page Change-Id: I9f46d684a11b7999defffe983fc3224ef1a50412 Signed-off-by: chenjiankun --- reporting/api/service/__init__.py | 0 reporting/api/service/result.py | 90 ++++++++++++++++++++++++++ reporting/api/service/scenario.py | 133 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 reporting/api/service/__init__.py create mode 100644 reporting/api/service/result.py create mode 100644 reporting/api/service/scenario.py (limited to 'reporting/api/service') diff --git a/reporting/api/service/__init__.py b/reporting/api/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/reporting/api/service/result.py b/reporting/api/service/result.py new file mode 100644 index 0000000..fa6553c --- /dev/null +++ b/reporting/api/service/result.py @@ -0,0 +1,90 @@ +import json +import logging +from collections import defaultdict + +from tornado.gen import coroutine +from tornado.gen import Return +from tornado.httpclient import AsyncHTTPClient + +from api import conf as consts +from api.extension.client import NoQueueTimeoutHTTPClient + +LOG = logging.getLogger(__name__) +AsyncHTTPClient.configure(NoQueueTimeoutHTTPClient) + + +class Result(object): + + def __init__(self): + self._url = '{}/results?period={}&version={}&page={}' + self._client = AsyncHTTPClient() + self._result = defaultdict(list) + + @property + @coroutine + def result(self): + if not self._result: + yield self.update_results() + raise Return(self._result) + + @coroutine + def update_results(self): + LOG.info('start update results') + + for version in consts.versions: + yield self._update_version_result(version) + + LOG.info('results update finished') + + @coroutine + def _update_version_result(self, version): + total_page = yield self._get_total_page(version) + + responses = yield self._fetch_results(version, total_page) + + self._update_version_dict(version, responses) + + @coroutine + def _fetch_results(self, version, total_page): + urls = [self._url.format(consts.base_url, consts.period, version, i) + for i in range(1, total_page + 1)] + responses = yield [self._client.fetch(url) for url in urls] + raise Return(responses) + + @coroutine + def _get_total_page(self, version): + url = self._url.format(consts.base_url, consts.period, version, 1) + response = yield self._client.fetch(url) + raise Return(json.loads(response.body)['pagination']['total_pages']) + + def _update_version_dict(self, version, responses): + for response in responses: + results = json.loads(response.body)['results'] + for result in results: + data = {k: v for k, v in result.items() if k != 'details'} + self._result[version].append(data) + + +class ResultCache(Result): + + @classmethod + @coroutine + def update(cls): + cls._check() + + yield cls.cache.update_results() + + @classmethod + @coroutine + def get(cls, version): + cls._check() + + result = yield cls.cache.result + raise Return(result[version]) + + @classmethod + def _check(cls): + try: + cls.cache + except AttributeError: + cls.cache = cls() diff --git a/reporting/api/service/scenario.py b/reporting/api/service/scenario.py new file mode 100644 index 0000000..f9e2a91 --- /dev/null +++ b/reporting/api/service/scenario.py @@ -0,0 +1,133 @@ +import abc +from collections import defaultdict + +import six +from tornado.gen import coroutine +from tornado.gen import Return + +from api.service.result import ResultCache + +PROJECTS = ['fastdatastacks', 'barometer', 'sfc', 'sdnvpn', 'doctor', 'parser'] + + +def _set(key, llist): + return set(x[key] for x in llist) + + +def _filter(key, value, llist): + return filter(lambda x: x[key] == value, llist) + + +class ScenarioTableResult(object): + + def __init__(self, scenario, version, installer, iteration): + self.scenario = scenario + self.version = version + self.installer = installer + self.iteration = iteration + + @coroutine + def get(self): + results = yield ResultCache.get(self.version) + results = self._filter_result(results) + results = self._struct_result(results) + + raise Return(results) + + def _filter_result(self, results): + results = [x for x in results if x['build_tag']] + if self.installer: + results = _filter('installer', self.installer, results) + if self.scenario: + results = _filter('scenario', self.scenario, results) + return results + + def _struct_result(self, results): + + return { + s: self._struct_scenario(_filter('scenario', s, results)) + for s in _set('scenario', results) + } + + def _struct_scenario(self, data): + return sorted([ + HandlerFacade.get_result(b, _filter('build_tag', b, data)) + for b in _set('build_tag', data) + ], key=lambda x: x['date'], reverse=True)[:self.iteration] + + +class HandlerFacade(object): + + @classmethod + def get_result(cls, index, data): + if not data: + return {} + + cls._change_name_to_functest(data) + data = cls._sort_by_start_date(data) + + return { + 'id': index, + 'date': data[0]['start_date'], + 'version': data[0]['version'], + 'installer': data[0]['installer'], + 'projects': cls._get_projects_data(data) + } + + @classmethod + def _sort_by_start_date(cls, data): + return sorted(data, key=lambda x: x['start_date']) + + @classmethod + def _get_projects_data(cls, data): + + return { + p: HANDLER_MAP[p](_filter('project_name', p, data)).struct() + for p in _set('project_name', data) + } + + @classmethod + def _change_name_to_functest(cls, data): + for ele in data: + if ele['project_name'] in PROJECTS: + ele['project_name'] = 'functest' + + +@six.add_metaclass(abc.ABCMeta) +class ProjectHandler(object): + + def __init__(self, data): + self.data = data + + def struct(self): + return self._struct_project_data() + + def _struct_project_data(self): + return { + 'gating': self._gating() + } + + @abc.abstractmethod + def _gating(self): + pass + + +class DefaultHandler(ProjectHandler): + + def _struct_project_data(self): + return {} + + def _gating(self): + pass + + +class FunctestHandler(ProjectHandler): + + def _gating(self): + if all([x['criteria'] == 'PASS' for x in self.data]): + return 'PASS' + else: + return 'FAIL' + + +HANDLER_MAP = defaultdict(lambda: DefaultHandler, functest=FunctestHandler) -- cgit 1.2.3-korg