diff --git a/alignak_app/__init__.py b/alignak_app/__init__.py index 95674a0..bbd655c 100644 --- a/alignak_app/__init__.py +++ b/alignak_app/__init__.py @@ -34,9 +34,12 @@ launch :class:`BackendQThread(s) ` to trigger requests in :class:`BackendClient `. * The :class:`DataManager ` will store data - provided by :class:`BackendClient `. - * The :class:`PyQt ` package display/update the data stored in + provided by :class:`BackendClient ` in + :class:`Items `. + * The :class:`QObjects ` package display/update the data stored in :class:`DataManager `. + * The :class:`Utils ` package contains settings, logs, installation,... + * The :class:`Locales ` package contains translations. """ diff --git a/alignak_app/app.py b/alignak_app/app.py index 0138a18..1c4b968 100644 --- a/alignak_app/app.py +++ b/alignak_app/app.py @@ -33,26 +33,24 @@ import time from logging import DEBUG, INFO - -from PyQt5.Qt import QDialog, QMessageBox, QTimer, QProgressBar, Qt, pyqtSignal, QObject, QIcon -from PyQt5.Qt import QWidget, QVBoxLayout, QLabel +from PyQt5.Qt import QApplication, QObject, QIcon, Qt, QProgressBar, QWidget, QLabel, QVBoxLayout +from PyQt5.Qt import QTimer from alignak_app import __application__, __version__ -from alignak_app.backend.backend import app_backend -from alignak_app.backend.datamanager import data_manager + from alignak_app.utils.config import settings from alignak_app.utils.logs import create_logger - from alignak_app.locales.locales import init_localization -from alignak_app.qobjects.dock.events import init_event_widget +from alignak_app.backend.backend import app_backend +from alignak_app.backend.datamanager import data_manager + +from alignak_app.qthreads.threadmanager import thread_manager, BackendQThread from alignak_app.qobjects.common.widgets import center_widget from alignak_app.qobjects.login.login import LoginQDialog +from alignak_app.qobjects.dock.events import init_event_widget from alignak_app.qobjects.systray.tray_icon import TrayIcon -from alignak_app.qthreads.threadmanager import thread_manager - -# Init App settings before importing QWidgets settings.init_config() settings.init_css() init_localization() @@ -121,25 +119,24 @@ def text(self): return self._text -class AlignakApp(QObject): +class AlignakApp(QObject): # pragma: no cover """ - Class who build Alignak-app and initialize configurations and systray icon. + Class who build Alignak-app QObjects, initialize configurations, systray icon + and Thread Manager. """ - reconnecting = pyqtSignal(str, name='reconnecting') - - def __init__(self, parent=None): - super(AlignakApp, self).__init__(parent) + def __init__(self): + super(AlignakApp, self).__init__() self.tray_icon = None - self.reconnect_mode = False + self.threadmanager_timer = QTimer() - def start(self): # pragma: no cover + def start(self, username=None, password=None): """ - The main function of Alignak-App + Start Alignak-app """ - # Define level of logger and log main informations + # Logger logger.name = 'alignak_app' if settings.get_config('Log', 'debug', boolean=True): logger.setLevel(DEBUG) @@ -148,130 +145,108 @@ def start(self): # pragma: no cover logger.setLevel(INFO) logger.info('- [Log Level]: INFO') + app = QApplication(sys.argv) + app.setQuitOnLastWindowClosed(False) + + # Connection to Backend + if settings.get_config('Alignak', 'username') and not username and not password: + username = settings.get_config('Alignak', 'username') + password = settings.get_config('Alignak', 'password') + + if not app_backend.login(username, password): + login = LoginQDialog() + login.create_widget() + + if login.exec_() == login.Accepted: + username = str(login.username_line.text()) + password = str(login.password_line.text()) + self.start(username, password) + else: + logger.info('The application is closed.') + sys.exit(0) + + # Launch start threads + thread_to_launch = thread_manager.get_threads_to_launch() + thread_to_launch.remove('history') + thread_to_launch.remove('notifications') + logger.info("Filling the database: %s", thread_to_launch) + + launched_threads = [] + for thread in thread_to_launch: + backend_thread = BackendQThread(thread) + backend_thread.start() + + launched_threads.append(backend_thread) + + # Create Progress Bar + app_progress = AppProgressQWidget() + app_progress.initialize() + center_widget(app_progress) + logger.info("Preparing DataManager...") + while data_manager.is_ready() != 'READY': + app_progress.show() + + for _ in range(0, 100): + t = time.time() + while time.time() < t + 0.01: + status = data_manager.is_ready() + app_progress.progress_bar.set_text('%s' % status) + app.processEvents() + + app_progress.close() + logger.info('- [ALIGNAKAPP_LOG_DIR]: %s', os.environ['ALIGNAKAPP_LOG_DIR']) logger.info('- [ALIGNAKAPP_USER_CFG]: %s', os.environ['ALIGNAKAPP_USER_CFG']) logger.info('- [ALIGNAKAPP_APP_CFG]: %s', os.environ['ALIGNAKAPP_APP_CFG']) - logger.info('- [%s]: %s', - os.path.split(settings.settings['settings'])[1], settings.settings['settings']) - logger.info('- [%s]: %s', - os.path.split(settings.settings['images'])[1], settings.settings['images']) - self.run() + init_event_widget() - def app_reconnecting_mode(self, error): # pragma: no cover - """ - Set AlignakApp in reconnect mode and try to login to Backend + requests_interval = int(settings.get_config('Alignak-app', 'requests_interval')) * 1000 + self.threadmanager_timer.setInterval(requests_interval) + self.threadmanager_timer.start() + self.threadmanager_timer.timeout.connect(self.check_threads) - :param error: string error to display in banner - :type error: str - """ + self.tray_icon = TrayIcon(QIcon(settings.get_image('icon'))) + self.tray_icon.build_menu() + self.tray_icon.show() - self.reconnect_mode = True - logger.warning('Application reconnecting MODE: %s', self.reconnecting) - logger.error('... caused by %s', error) - timer = QTimer(self) - - # Stop thread_name manager - thread_manager.stop_threads() - - def connect_to_backend(): - """Try to log in to Backend""" - try: - connect = app_backend.login() - assert connect - timer.stop() - # If connect, reconnecting is disable and threads restart - self.reconnect_mode = False - thread_manager.start() - logger.info('Connection restored : %s', connect) - except AssertionError: - logger.error('Backend is still unreachable...') - - if timer.isActive(): + while self.quit_launched_threads(launched_threads): pass - else: - timer.start(5000) - timer.timeout.connect(connect_to_backend) - def run(self, username=None, password=None): # pragma: no cover - """ - Start all Alignak-app processes and create AppBackend if connection by config file. + sys.exit(app.exec_()) + @staticmethod + def quit_launched_threads(launched_threads): """ + Exit the threads that were started when the application started - if username and password: - app_backend.login(username, password) - else: - app_backend.login() + :param launched_threads: list of threads that have been launched + :type launched_threads: list + :return: empty list if all the threads have been left or current list + :rtype: list + """ - # Check if connected - if app_backend.connected: - # Start ThreadManager - for _ in range(0, 5): - thread_manager.launch_threads() - - self.reconnecting.connect(self.app_reconnecting_mode) - - # Give AlignakApp for AppBackend reconnecting mode - app_backend.app = self - - if 'token' not in app_backend.user: - app_backend.user['token'] = app_backend.backend.token - - # Create Progress Bar - app_progress = AppProgressQWidget() - app_progress.initialize() - center_widget(app_progress) - - logger.info("Preparing DataManager...") - while data_manager.is_ready() != 'READY': - app_progress.show() - for _ in range(0, 100): - t = time.time() - while time.time() < t + 0.01: - status = data_manager.is_ready() - app_progress.progress_bar.set_text('%s' % status) - self.parent().processEvents() - app_progress.close() - - # Launch other threads and run TrayIcon() - logger.info("Datamanager is ready :)") - thread_manager.start() - init_event_widget() - self.tray_icon = TrayIcon(QIcon(settings.get_image('icon'))) - self.tray_icon.build_menu() - self.tray_icon.show() - else: - # In case of data provided in config file fails - login = LoginQDialog() - login.create_widget() + for old_thread in launched_threads: + if old_thread.isFinished(): + old_thread.quit() + old_thread.wait() + launched_threads.remove(old_thread) - if login.exec_() == QDialog.Accepted: - username = str(login.username_line.text()) - password = str(login.password_line.text()) - self.run(username, password) - else: - logger.info('Alignak-App closes...') - sys.exit(0) + return launched_threads @staticmethod - def display_error_msg(): # pragma: no cover + def check_threads(): """ - Display a QMessageBox error in case app fail to start + Launch periodically threads """ - logger.error('Something seems wrong in your configuration.' - 'Please configure Alignak-app before starting it. ' - 'And make sure the backend is available') - - QMessageBox.critical( - None, - _('Configuration / Connection ERROR'), - _( - 'Something seems wrong in your configuration. ' - 'Please configure Alignak-app before starting it. ' - 'And make sure the backend is available' - ) - ) - sys.exit() + # Cleaning threads who are finished + thread_manager.clean_threads() + + # Launch or stop threads + if app_backend.connected: + thread_manager.launch_threads() + else: + logger.info('Can\'t launch thread, App is not connected to backend !') + thread_manager.stop_threads() diff --git a/alignak_app/backend/backend.py b/alignak_app/backend/backend.py index b18c57a..b0eca67 100644 --- a/alignak_app/backend/backend.py +++ b/alignak_app/backend/backend.py @@ -40,6 +40,8 @@ from alignak_app.items.livesynthesis import LiveSynthesis from alignak_app.items.service import Service from alignak_app.items.user import User +from alignak_app.items.realm import Realm +from alignak_app.items.period import Period from alignak_app.utils.config import settings @@ -51,11 +53,16 @@ class BackendClient(object): Class who collect informations with Backend-Client and returns data for Alignak-App. """ + connection_status = { + True: 'Success', + False: 'Failure' + } + def __init__(self): + self.start = False self.backend = None - self.user = {} self.connected = False - self.app = None + self.user = {} def login(self, username=None, password=None): """ @@ -71,11 +78,8 @@ def login(self, username=None, password=None): # Credentials if not username and not password: - if data_manager.is_ready() == 'READY': - username = data_manager.database['user'].name - else: - username = settings.get_config('Alignak', 'username') - password = settings.get_config('Alignak', 'password') + if 'token' in self.user: + username = self.user['token'] # Create Backend object backend_url = settings.get_config('Alignak', 'backend') @@ -87,19 +91,19 @@ def login(self, username=None, password=None): logger.info('Try to connect to app_backend...') if username and password: - # Username & password : not recommended, without "login.form.py" form. + # Username & password : not recommended, without login QDialog try: self.connected = self.backend.login(username, password) if self.connected: self.user['username'] = username self.user['token'] = self.backend.token - logger.info('Connection by password: %s', str(self.connected)) - except BackendException as e: # pragma: no cover - logger.error('Connection to Backend has failed: %s', str(e)) + logger.info('Connection by password: %s', self.connection_status[self.connected]) + except BackendException: # pragma: no cover + logger.error('Connection to Backend has failed !') elif username and not password: # pragma: no cover # Username as token : recommended self.backend.authenticated = True - if self.user: + if 'token' in self.user: self.backend.token = self.user['token'] else: self.backend.token = username @@ -110,16 +114,12 @@ def login(self, username=None, password=None): connection_test = self.get('livesynthesis') self.connected = bool(connection_test) - logger.info('Connection by token: %s', str(self.connected)) - - if not self.connected: - return False + logger.info('Connection by token: %s', self.connection_status[self.connected]) else: - # Else exit - logger.error( - 'Connection to Backend has failed.\nCheck [Alignak] section in configuration file.' + logger.warning( + 'Connection to Backend has failed.\nCheck [Alignak] section in configuration file ' + 'or use login window of application.' ) - return False return self.connected @@ -141,15 +141,14 @@ def get(self, endpoint, params=None, projection=None, all_items=False): request = None - if params is None: - params = {'max_results': 50} - if projection is not None: - generate_proj = {} - for field in projection: - generate_proj[field] = 1 - params['projection'] = json.dumps(generate_proj) - if self.connected: + if params is None: + params = {'max_results': 50} + if projection is not None: + generate_proj = {} + for field in projection: + generate_proj[field] = 1 + params['projection'] = json.dumps(generate_proj) # Request try: if not all_items: @@ -162,29 +161,12 @@ def get(self, endpoint, params=None, projection=None, all_items=False): endpoint, params ) - logger.debug('GET: %s', endpoint) - logger.debug('..with params: %s', str(params)) - logger.debug('...Response > %s', str(request['_status'])) - except (BackendException, json.decoder.JSONDecodeError) as e: - logger.warning('First GET failed: %s', str(e)) - logger.warning('...Request: %s', str(request)) - try: - request = self.backend.get( - endpoint, - params - ) - logger.debug('GET (Retry): %s', endpoint) - logger.debug('..with params: %s', str(params)) - logger.debug('...Response > %s', str(request['_status'])) - except (BackendException, json.decoder.JSONDecodeError) as e: # pragma: no cover - logger.error('GET failed: %s', str(e)) - logger.error('...Request: %s', str(request)) - logger.warning('Application checks the connection with the Backend...') - self.connected = False - if self.app: - if not self.app.reconnect_mode: - self.app.reconnecting.emit(str(e)) - return request + logger.info('GET on [%s] backend > %s', endpoint, str(request['_status'])) + logger.debug('- params: [%s]', str(params)) + except BackendException: + self.connected = False + else: + logger.info('App is not connected to backend !') return request @@ -207,16 +189,13 @@ def post(self, endpoint, data, headers=None): # pragma: no cover - Post already if self.connected: try: request = self.backend.post(endpoint, data, headers=headers) - logger.debug('POST on %s', endpoint) - logger.debug('..with data: %s', str(data)) - logger.debug('...Response > %s', str(request['_status'])) - except BackendException as e: - logger.error('POST failed: %s', str(e)) - logger.warning('Application checks the connection with the Backend...') + logger.info('POST on [%s] backend > %s', endpoint, str(request['_status'])) + logger.debug('- data: [%s]', str(data)) + logger.debug('- headers: [%s]', str(headers)) + except BackendException: self.connected = False - if not self.app.reconnect_mode: - self.app.reconnecting.emit(str(e)) - return request + else: + logger.info('App is not connected to backend !') return request @@ -239,79 +218,73 @@ def patch(self, endpoint, data, headers): if self.connected: try: request = self.backend.patch(endpoint, data, headers=headers, inception=True) - logger.debug('PATCH on %s', endpoint) - logger.debug('..with data: %s', str(data)) - logger.debug('...with headers: %s', str(headers)) - logger.debug('....Response > %s', str(request['_status'])) - except BackendException as e: # pragma: no cover - logger.error('PATCH failed: %s', str(e)) - logger.warning('Application checks the connection with the Backend...') + logger.info('PATCH on [%s] backend > %s', endpoint, str(request['_status'])) + logger.debug('- data: [%s]', str(data)) + logger.debug('- headers: [%s]', str(headers)) + except BackendException: self.connected = False - if not self.app.reconnect_mode: - self.app.reconnecting.emit(str(e)) - return False + else: + logger.info('App is not connected to backend !') return request - def get_realm_name(self, endpoint_id): + def query_realms_data(self): """ - Return realm name or alias + Launch a request on ``realm`` endpoint - :param endpoint_id: id of endpoint - :type endpoint_id: str - :return: realm name or alias - :rtype: str """ - endpoint = '/'.join( - ['realm', endpoint_id] - ) - projection = [ - 'name', - 'alias' - ] + request_data = Realm.get_request_model() - realm = self.get(endpoint, projection=projection) + request = self.get( + request_data['endpoint'], + request_data['params'], + request_data['projection'] + ) - if realm: - if realm['alias']: - return realm['alias'] + if request: + realms_list = [] + for item in request['_items']: + realm = Realm() - return realm['name'] + realm.create( + item['_id'], + item, + item['name'], + ) + realms_list.append(realm) - return 'n/a' + if realms_list: + data_manager.update_database('realm', realms_list) - def get_period_name(self, endpoint_id): + def query_period_data(self): """ - Get the period name or alias + Launch a request on ``timeperiod`` endpoint - :param endpoint_id: id of endpoint - :type endpoint_id: str - :return: name or alias of timeperiod - :rtype: str """ - projection = [ - 'name', - 'alias' - ] - - endpoint = '/'.join(['timeperiod', endpoint_id]) + request_data = Period.get_request_model() - period = self.get(endpoint, projection=projection) - - if period: - if 'host' in endpoint or 'service' in endpoint: - period_items = period['_items'][0] - else: - period_items = period + request = self.get( + request_data['endpoint'], + request_data['params'], + request_data['projection'] + ) - if 'alias' in period_items: - return period_items['alias'] + if request: + periods_list = [] + for item in request['_items']: + period = Period() - return period_items['name'] + period.create( + item['_id'], + item, + item['name'], + ) + periods_list.append(period) - return 'n/a' + if periods_list: + data_manager.update_database('timeperiod', periods_list) def query_user_data(self): """ @@ -319,9 +292,7 @@ def query_user_data(self): """ - user = User() - - request_data = user.get_request_model(self.backend.token) + request_data = User.get_request_model(self.backend.token) request = self.get( request_data['endpoint'], @@ -330,11 +301,14 @@ def query_user_data(self): ) if request: + user = User() + user.create( request['_items'][0]['_id'], request['_items'][0], request['_items'][0]['name'] ) + data_manager.update_database('user', user) def query_hosts_data(self): @@ -352,8 +326,8 @@ def query_hosts_data(self): all_items=True ) - hosts_list = [] if request: + hosts_list = [] for item in request['_items']: host = Host() @@ -504,6 +478,7 @@ def query_history_data(self, hostname=None, host_id=None): request_data['projection'], all_items=False ) + if request: host_history = History() diff --git a/alignak_app/backend/datamanager.py b/alignak_app/backend/datamanager.py index 9d5e193..16e289a 100644 --- a/alignak_app/backend/datamanager.py +++ b/alignak_app/backend/datamanager.py @@ -48,6 +48,8 @@ def __init__(self): 'host': [], 'service': [], 'user': [], + 'realm': [], + 'timeperiod': [], } self.old_notifications = [] @@ -59,19 +61,22 @@ def is_ready(self): :rtype: str """ - if self.database['host'] and \ - self.database['service'] and \ - self.database['livesynthesis']: - return 'READY' + cur_collected = '' + db_names = [ + 'livesynthesis', 'host', 'alignakdaemon', 'user', 'realm', 'timeperiod', 'service' + ] + for db_name in db_names: + try: + assert bool(self.database[db_name]) + cur_collected = 'READY' + except AssertionError: + cur_collected = 'Collecting %s...' % db_name + break - if not self.database['livesynthesis']: - return 'Collecting livesynthesis...' - if not self.database['host']: - return 'Collecting hosts...' - if not self.database['service']: - return 'Collecting services...' + if not cur_collected: + cur_collected = 'Please wait' - return 'Please wait...' + return cur_collected def update_database(self, item_type, items_list): """ @@ -98,7 +103,7 @@ def get_item(self, item_type, key, value=None): :param value: value of the key if needed :type value: str :return: wanted item - :rtype: alignak_app.core.models.item.ItemModel + :rtype: alignak_app.items.item.* """ logger.debug('Get database Item [%s] : %s, %s', item_type, key, value) @@ -133,6 +138,42 @@ def update_item_data(self, item_type, item_id, data): for key in data: item.data[key] = data[key] + def get_realm_name(self, realm): + """ + Return the realm name or alias + + :param realm: wanted realm ``_id`` + :type realm: str + :return: the wanted realm alias or name if available + :rtype: str + """ + + if self.database['realm']: + wanted_realm = self.get_item('realm', realm) + + if wanted_realm: + return wanted_realm.get_display_name() + + return 'n/a' + + def get_period_name(self, period): + """ + Return the period name or alias + + :param period: wanted period ``_id`` + :type period: str + :return: the wanted realm alias or name if available + :rtype: str + """ + + if self.database['timeperiod']: + wanted_period = self.get_item('timeperiod', period) + + if wanted_period: + return wanted_period.get_display_name() + + return 'n/a' + def get_synthesis_count(self): """ Get on "synthesis" endpoint and return the states of hosts and services diff --git a/alignak_app/items/daemon.py b/alignak_app/items/daemon.py index ad763a0..a7f656c 100644 --- a/alignak_app/items/daemon.py +++ b/alignak_app/items/daemon.py @@ -22,7 +22,7 @@ """ Daemon ++++++ - Daemon manage creation of daemon item + Daemon manage creation of daemon item for backend ``alignakdaemon`` endpoint """ diff --git a/alignak_app/items/event.py b/alignak_app/items/event.py index c5e25f9..a70fec3 100644 --- a/alignak_app/items/event.py +++ b/alignak_app/items/event.py @@ -22,7 +22,7 @@ """ Event +++++ - Event manage creation of notification item + Event manage creation of event item (Notifications collected from ``history`` endpoint) """ import datetime diff --git a/alignak_app/items/history.py b/alignak_app/items/history.py index 473d5c3..a777446 100644 --- a/alignak_app/items/history.py +++ b/alignak_app/items/history.py @@ -22,7 +22,7 @@ """ History +++++++ - History manage creation of history item + History manage creation of history item for backend ``history`` endpoint """ from logging import getLogger diff --git a/alignak_app/items/host.py b/alignak_app/items/host.py index d17aec1..eddbf21 100644 --- a/alignak_app/items/host.py +++ b/alignak_app/items/host.py @@ -22,7 +22,7 @@ """ Host ++++ - Host manage creation of host item + Host manage creation of host item for backend ``host`` endpoint """ import json @@ -85,7 +85,7 @@ def get_display_name(self): :rtype: str """ - if self.data['alias']: - return self.data['alias'].capitalize() + if 'alias' in self.data: + return self.data['alias'].title() - return self.data['name'].capitalize() + return self.data['name'].title() diff --git a/alignak_app/items/item.py b/alignak_app/items/item.py index 887afdd..cc4c167 100644 --- a/alignak_app/items/item.py +++ b/alignak_app/items/item.py @@ -22,7 +22,7 @@ """ Item ++++ - Item is parent class for all models + Item is parent class for all items objects """ @@ -33,7 +33,7 @@ class Item(object): """ - Class who create item + Class who create an item """ def __init__(self): @@ -60,17 +60,6 @@ def create(self, _id, data, name=None): if name: self.name = name - def get_data(self, key): - """ - Return key data of item - - :param key: the key who contain the wanted data - :type key: str - :return: the wanted data - """ - - return self.data[key] - def update_data(self, key, new_value): """ Update data of the wanted key @@ -149,7 +138,7 @@ def get_icon_name(item_type, state, acknowledge, downtime, monitored): try: return available_icons[item_type][state] except KeyError as e: - logger.error('Wrong KEY for get_icon(): %s', e) + logger.error('Wrong KEY for get_icon_name(): %s', e) return 'error' diff --git a/alignak_app/items/livesynthesis.py b/alignak_app/items/livesynthesis.py index 58e5da2..74100c4 100644 --- a/alignak_app/items/livesynthesis.py +++ b/alignak_app/items/livesynthesis.py @@ -22,7 +22,7 @@ """ Live Synthesis ++++++++++++++ - Livesynthesis manage creation of livesynthesis item + Livesynthesis manage creation of livesynthesis item for backend ``livesynthesis`` endpoint """ diff --git a/alignak_app/items/period.py b/alignak_app/items/period.py new file mode 100644 index 0000000..a71f66c --- /dev/null +++ b/alignak_app/items/period.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2015-2018: +# Matthieu Estrada, ttamalfor@gmail.com +# +# This file is part of (AlignakApp). +# +# (AlignakApp) is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# (AlignakApp) is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with (AlignakApp). If not, see . + +""" + Period + ++++++ + Period manage creation of period item for backend ``timeperiod`` endpoint +""" + + +from logging import getLogger + +from alignak_app.items.item import Item + +logger = getLogger(__name__) + + +class Period(Item): + """ + Class who create a period item + """ + + def __init__(self): + super(Period, self).__init__() + self.item_type = 'timeperiod' + + @staticmethod + def get_request_model(): + """ + Return the request model for timeperiod requests + + :return: request model for timeperiod endpoint + :rtype: dict + """ + + realms_projection = [ + 'name', 'alias' + ] + + request_model = { + 'endpoint': 'timeperiod', + 'params': None, + 'projection': realms_projection + } + + return request_model + + def get_display_name(self): + """ + Return alias or name if available + + :return: name or alias + :rtype: str + """ + + if 'alias' in self.data: + return self.data['alias'].title() + + return self.data['name'].title() diff --git a/alignak_app/items/realm.py b/alignak_app/items/realm.py new file mode 100644 index 0000000..d7a1fcd --- /dev/null +++ b/alignak_app/items/realm.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2015-2018: +# Matthieu Estrada, ttamalfor@gmail.com +# +# This file is part of (AlignakApp). +# +# (AlignakApp) is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# (AlignakApp) is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with (AlignakApp). If not, see . + +""" + Realm + +++++ + Realm manage creation of realm item for backend ``realm`` endpoint +""" + + +from logging import getLogger + +from alignak_app.items.item import Item + +logger = getLogger(__name__) + + +class Realm(Item): + """ + Class who create a realm item + """ + + def __init__(self): + super(Realm, self).__init__() + self.item_type = 'realm' + + @staticmethod + def get_request_model(): + """ + Return the request model for realm requests + + :return: request model for realm endpoint + :rtype: dict + """ + + realms_projection = [ + 'name', 'alias' + ] + + request_model = { + 'endpoint': 'realm', + 'params': None, + 'projection': realms_projection + } + + return request_model + + def get_display_name(self): + """ + Return alias or name if available + + :return: name or alias + :rtype: str + """ + + if 'alias' in self.data: + return self.data['alias'].title() + + return self.data['name'].title() diff --git a/alignak_app/items/service.py b/alignak_app/items/service.py index 137c013..89fabea 100644 --- a/alignak_app/items/service.py +++ b/alignak_app/items/service.py @@ -22,7 +22,7 @@ """ Service +++++++ - Service manage creation of service item + Service manage creation of service item for backend ``service`` endpoint """ import json @@ -107,7 +107,7 @@ def get_display_name(self): :rtype: str """ - if self.data['alias']: - return self.data['alias'].capitalize() + if 'alias' in self.data: + return self.data['alias'].title() - return self.data['name'].capitalize() + return self.data['name'].title() diff --git a/alignak_app/items/user.py b/alignak_app/items/user.py index 131adcd..b9fb96b 100644 --- a/alignak_app/items/user.py +++ b/alignak_app/items/user.py @@ -35,7 +35,7 @@ class User(Item): """ - Class who create user item + Class who create user item for backend ``user`` endpoint """ def __init__(self): diff --git a/alignak_app/qobjects/dock/user.py b/alignak_app/qobjects/dock/user.py index 1d1de36..b4ebb3f 100644 --- a/alignak_app/qobjects/dock/user.py +++ b/alignak_app/qobjects/dock/user.py @@ -318,7 +318,7 @@ def get_hosts_notif_widget(self): period_title.setObjectName("subtitle") host_notif_layout.addWidget(period_title, 3, 0, 1, 1) self.labels['host_notification_period'].setText( - app_backend.get_period_name( + data_manager.get_period_name( data_manager.database['user'].data['host_notification_period'] ) ) @@ -371,7 +371,7 @@ def get_services_notif_widget(self): period_title.setObjectName("subtitle") service_notif_layout.addWidget(period_title, 3, 0, 1, 1) self.labels['service_notification_period'].setText( - app_backend.get_period_name( + data_manager.get_period_name( data_manager.database['user'].data['service_notification_period'] ) ) @@ -430,7 +430,7 @@ def update_widget(self): # Realm, Role, Email self.labels['realm'].setText( - app_backend.get_realm_name(data_manager.database['user'].data['_realm']) + data_manager.get_realm_name(data_manager.database['user'].data['_realm']) ) self.labels['role'].setText(data_manager.database['user'].get_role().capitalize()) self.labels['email'].setText(data_manager.database['user'].data['email']) diff --git a/alignak_app/qobjects/panel/host.py b/alignak_app/qobjects/panel/host.py index 4d6269c..b645ef7 100644 --- a/alignak_app/qobjects/panel/host.py +++ b/alignak_app/qobjects/panel/host.py @@ -365,7 +365,7 @@ def update_host(self, hostname=None): self.labels['ls_output'].setText(self.host_item.data['ls_output']) self.labels['realm'].setText( - app_backend.get_realm_name(self.host_item.data['_realm']) + data_manager.get_realm_name(self.host_item.data['_realm']) ) self.labels['address'].setText(self.host_item.data['address']) self.labels['business_impact'].setText(str(self.host_item.data['business_impact'])) @@ -383,8 +383,13 @@ def update_host(self, hostname=None): self.history_btn.setToolTip(_('History is available')) else: self.history_btn.setToolTip(_('History is not available, please wait...')) - thread_manager.add_thread( - 'history', - {'hostname': self.host_item.name, 'host_id': self.host_item.item_id} - ) self.history_btn.setEnabled(False) + + if app_backend.connected: + thread_manager.add_priority_thread( + 'history', + {'hostname': self.host_item.name, 'host_id': self.host_item.item_id} + ) + else: + logger.info('Can\'t launch thread, App is not connected to backend !') + thread_manager.stop_threads() diff --git a/alignak_app/qobjects/systray/tray_icon.py b/alignak_app/qobjects/systray/tray_icon.py index 05f9b35..b791807 100644 --- a/alignak_app/qobjects/systray/tray_icon.py +++ b/alignak_app/qobjects/systray/tray_icon.py @@ -28,9 +28,10 @@ import sys from logging import getLogger -from PyQt5.Qt import QMenu, QSystemTrayIcon +from PyQt5.Qt import QMenu, QSystemTrayIcon, QTimer from alignak_app.utils.config import settings +from alignak_app.backend.backend import app_backend from alignak_app.qobjects.app_main import AppQMainWindow from alignak_app.qobjects.systray.about import AboutQDialog @@ -55,6 +56,8 @@ def __init__(self, icon, parent=None): self.qaction_factory = QActionFactory() self.app_about = None self.app_main = AppQMainWindow() + self.connection_timer = QTimer() + self.connection_nb = 3 def build_menu(self): """ @@ -63,13 +66,18 @@ def build_menu(self): """ logger.info("Start TrayIcon...") + + self.connection_timer.setInterval(10000) + self.connection_timer.start() + self.connection_timer.timeout.connect(self.check_connection) + # Create actions - self.create_dock_action() + self.add_alignak_menu() self.menu.addSeparator() - self.create_reload_configuration() - self.create_about_action() + self.add_reload_menu() + self.add_about_menu() self.menu.addSeparator() @@ -77,13 +85,30 @@ def build_menu(self): self.setContextMenu(self.menu) - def create_dock_action(self): + def check_connection(self): + """ + Check periodically connection for App + """ - Create "dock" action + if app_backend.connected: + connect = app_backend.login() + logger.info('App check connection: %s', app_backend.connection_status[connect]) + elif not app_backend.connected and self.connection_nb < 1: + connect = app_backend.login() + logger.warning('App check connection: %s', app_backend.connection_status[connect]) + self.connection_nb = 3 + elif not app_backend.connected: + logger.warning('App check connection in %d0s', self.connection_nb) + self.connection_nb -= 1 + else: + pass + + def add_alignak_menu(self): """ + Create "dock" action - logger.debug('Create Alignak-app Action') + """ self.qaction_factory.create( 'icon', @@ -96,14 +121,12 @@ def create_dock_action(self): self.menu.addAction(self.qaction_factory.get_action('icon')) - def create_reload_configuration(self): + def add_reload_menu(self): """ Create "reload" action """ - logger.debug('Create Reload Action') - self.qaction_factory.create( 'refresh', _('Reload Configuration'), @@ -114,14 +137,12 @@ def create_reload_configuration(self): self.menu.addAction(self.qaction_factory.get_action('refresh')) - def create_about_action(self): + def add_about_menu(self): """ Create AppAbout QWidget and "about" action. """ - logger.debug('Create About Action') - self.app_about = AboutQDialog() self.app_about.initialize() @@ -161,7 +182,7 @@ def quit_app(): # pragma: no cover """ thread_manager.stop_threads() - + logger.info('The application is closed.') sys.exit(0) @staticmethod diff --git a/alignak_app/qthreads/thread.py b/alignak_app/qthreads/thread.py index ef853e7..2d8948c 100644 --- a/alignak_app/qthreads/thread.py +++ b/alignak_app/qthreads/thread.py @@ -27,7 +27,7 @@ from logging import getLogger -from PyQt5.Qt import QThread, pyqtSignal +from PyQt5.Qt import QThread from alignak_app.backend.backend import app_backend @@ -39,8 +39,6 @@ class BackendQThread(QThread): # pylint: disable=too-few-public-methods Class who create a QThread to trigger requests """ - quit_thread = pyqtSignal(name='close_thread') - def __init__(self, thread, data=None): super(BackendQThread, self).__init__() self.thread_name = thread @@ -52,26 +50,31 @@ def run(self): # pragma: no cover """ - self.quit_thread.connect(self.quit) - logger.debug('THREAD: launch a new thread for %s', self.thread_name) - logger.debug('... with data: %s', self.data) - - if 'user' in self.thread_name: - app_backend.query_user_data() - elif 'host' in self.thread_name: - app_backend.query_hosts_data() - elif 'service' in self.thread_name: - app_backend.query_services_data() - elif 'alignakdaemon' in self.thread_name: - app_backend.query_daemons_data() - elif 'livesynthesis' in self.thread_name: - app_backend.query_livesynthesis_data() - elif self.thread_name == 'history': - if self.data: - app_backend.query_history_data(self.data['hostname'], self.data['host_id']) + if app_backend.connected: + logger.debug('Launch a new thread request for backend: %s', self.thread_name) + if 'user' in self.thread_name: + app_backend.query_user_data() + elif 'host' in self.thread_name: + app_backend.query_hosts_data() + elif 'service' in self.thread_name: + app_backend.query_services_data() + elif 'alignakdaemon' in self.thread_name: + app_backend.query_daemons_data() + elif 'livesynthesis' in self.thread_name: + app_backend.query_livesynthesis_data() + elif 'realm' in self.thread_name: + app_backend.query_realms_data() + elif 'timeperiod' in self.thread_name: + app_backend.query_period_data() + elif self.thread_name == 'history': + if self.data: + app_backend.query_history_data(self.data['hostname'], self.data['host_id']) + else: + app_backend.query_history_data() + elif 'notifications' in self.thread_name: + app_backend.query_notifications_data() else: - app_backend.query_history_data() - elif 'notifications' in self.thread_name: - app_backend.query_notifications_data() + logger.error("Thread is unknown: %s", self.thread_name) else: - logger.error("Thread is unknown: %s", self.thread_name) + logger.warning('The app is offline, the threads can not be launched !') + self.quit() diff --git a/alignak_app/qthreads/threadmanager.py b/alignak_app/qthreads/threadmanager.py index dbb9d5d..189fbce 100644 --- a/alignak_app/qthreads/threadmanager.py +++ b/alignak_app/qthreads/threadmanager.py @@ -27,9 +27,7 @@ from logging import getLogger -from PyQt5.Qt import QTimer, QObject - -from alignak_app.utils.config import settings +from PyQt5.Qt import QObject from alignak_app.qthreads.thread import BackendQThread @@ -43,22 +41,9 @@ class ThreadManager(QObject): def __init__(self, parent=None): super(ThreadManager, self).__init__(parent) - self.current_threads = [] + self.current_thread = None + self.priority_threads = [] self.threads_to_launch = self.get_threads_to_launch() - self.timer = QTimer() - - def start(self): # pragma: no cover - """ - Start ThreadManager - - """ - - logger.info('Start Thread Manager...') - - requests_interval = int(settings.get_config('Alignak-app', 'requests_interval')) * 1000 - self.timer.setInterval(requests_interval) - self.timer.start() - self.timer.timeout.connect(self.launch_threads) def get_threads_to_launch(self): """ @@ -71,55 +56,68 @@ def get_threads_to_launch(self): threads_to_launch = [] # Add BackendQThread only if they are not already running - for cur_thread in ['user', 'host', 'service', 'livesynthesis', + for cur_thread in ['livesynthesis', 'host', 'service', 'user', 'realm', 'timeperiod', 'alignakdaemon', 'notifications', 'history']: - if not any(cur_thread == thread.thread_name for thread in self.current_threads): + if self.current_thread: + if cur_thread != self.current_thread.thread_name: + threads_to_launch.append(cur_thread) + else: threads_to_launch.append(cur_thread) logger.debug('Get new threads to launch %s', threads_to_launch) return threads_to_launch - def launch_threads(self): # pragma: no cover + def launch_threads(self): """ - Create threads_to_launch to run + Launch periodically threads """ - if not self.threads_to_launch: + if not thread_manager.threads_to_launch: self.threads_to_launch = self.get_threads_to_launch() - # In case of all threads are not running - if self.threads_to_launch: + # In case there is no thread running + if self.threads_to_launch and not self.current_thread: cur_thread = self.threads_to_launch.pop(0) backend_thread = BackendQThread(cur_thread) backend_thread.start() - self.current_threads.append(backend_thread) + self.current_thread = backend_thread - # Cleaning threads who are finished - for thread in self.current_threads: - if thread.isFinished(): - logger.debug('Remove finished thread: %s', thread.thread_name) - thread.quit() - thread.wait() - self.current_threads.remove(thread) + def clean_threads(self): + """ + Clean current BackendQThreads - def add_thread(self, thread_name, data): """ - Add a thread, actually used for new history - :param thread_name: name of thread + if self.current_thread: + if self.current_thread.isFinished(): + logger.debug('Remove finished thread: %s', self.current_thread.thread_name) + self.current_thread.quit() + self.current_thread = None + + if self.priority_threads: + for thread in self.priority_threads: + if thread.isFinished(): + thread.quit() + self.priority_threads.remove(thread) + logger.debug('Remove finished thread: %s', thread.thread_name) + + def add_priority_thread(self, thread_name, data): # pragma: no cover + """ + Launch a thread with higher priority (doesn't wait launch_threads() function) + + :param thread_name: name of priority thread :type thread_name: str :param data: data to give to thread for request :type data: dict """ - if not any(data == thread.data for thread in self.current_threads): - thread = BackendQThread(thread_name, data) - thread.start() + backend_thread = BackendQThread(thread_name, data) + backend_thread.start() - self.current_threads.append(thread) + self.priority_threads.append(backend_thread) def stop_threads(self): """ @@ -127,13 +125,27 @@ def stop_threads(self): """ - logger.info("Stop backend threads...") - self.timer.stop() - for thread in self.current_threads: - logger.debug('Try to quit thread: %s', thread.thread_name) - thread.quit_thread.emit() + if self.current_thread: + logger.debug('Try to quit current thread: %s', self.current_thread.thread_name) + self.current_thread.quit() + self.current_thread = None + + if self.priority_threads: + self.stop_priority_threads() + + logger.debug("Finished backend threads have been stopped !") + + def stop_priority_threads(self): + """ + Stop priority threads + + """ + + for thread in self.priority_threads: + logger.debug('Try to quit current priority thread: %s', thread.thread_name) + thread.quit() - logger.info("The backend threads were stopped !") + self.priority_threads.remove(thread) thread_manager = ThreadManager() diff --git a/bin/unix/alignak-app.py b/bin/unix/alignak-app.py index 0aa7667..d98d324 100755 --- a/bin/unix/alignak-app.py +++ b/bin/unix/alignak-app.py @@ -33,8 +33,6 @@ from alignak_app.app import AlignakApp from alignak_app import __application__ -from PyQt5.QtWidgets import QApplication - def main(): # pragma: no cover """ @@ -78,13 +76,9 @@ def main(): # pragma: no cover 'and requires an X server to be displayed.%s' % (fail, endc) ) - app = QApplication(sys.argv) - app.setQuitOnLastWindowClosed(False) - - alignak_app = AlignakApp(app) + alignak_app = AlignakApp() alignak_app.start() - sys.exit(app.exec_()) elif args.install and 'win32' not in sys.platform: # ONLY FOR LINUX PLATFORM bin_file = '%s/bin/%s' % (settings.app_cfg_dir, os.path.split(__file__)[1]) diff --git a/docs/api.rst b/docs/api.rst index 213dfa7..6fe4201 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -64,6 +64,16 @@ Items :inherited-members: :show-inheritance: +.. automodule:: alignak_app.items.period + :members: + :inherited-members: + :show-inheritance: + +.. automodule:: alignak_app.items.realm + :members: + :inherited-members: + :show-inheritance: + .. automodule:: alignak_app.items.service :members: :inherited-members: diff --git a/test/test_all_items.py b/test/test_all_items.py index bad54e0..49c3170 100644 --- a/test/test_all_items.py +++ b/test/test_all_items.py @@ -35,6 +35,7 @@ from alignak_app.items.livesynthesis import LiveSynthesis from alignak_app.items.service import Service from alignak_app.items.user import User +from alignak_app.items.realm import Realm class TestAllItems(unittest2.TestCase): @@ -105,7 +106,7 @@ def test_item_model_get_data(self): under_test.create('_id', {'ls_state': 'DOWN', 'ls_acknowledged': True}, 'name') - data_test = under_test.get_data('ls_state') + data_test = under_test.data['ls_state'] self.assertTrue('DOWN' == data_test) @@ -118,29 +119,35 @@ def test_item_model_update_data(self): under_test.update_data('ls_acknowledged', False) - data_test = under_test.get_data('ls_acknowledged') + data_test = under_test.data['ls_acknowledged'] self.assertTrue(data_test is False) def test_get_icon_name(self): """Get Icon Name""" - under_test = get_icon_name('host', 'UP', acknowledge=False, downtime=False, monitored=1) + under_test = get_icon_name( + 'host', 'UP', acknowledge=False, downtime=False, monitored=1) self.assertEqual('hosts_up', under_test) - under_test = get_icon_name('service', 'WARNING', acknowledge=False, downtime=False, monitored=1) + under_test = get_icon_name( + 'service', 'WARNING', acknowledge=False, downtime=False, monitored=1) self.assertEqual('services_warning', under_test) - under_test = get_icon_name('host', 'DOWN', acknowledge=True, downtime=False, monitored=1) + under_test = get_icon_name( + 'host', 'DOWN', acknowledge=True, downtime=False, monitored=1) self.assertEqual('acknowledge', under_test) - under_test = get_icon_name('service', 'UNREACHABLE', acknowledge=True, downtime=True, monitored=2) + under_test = get_icon_name( + 'service', 'UNREACHABLE', acknowledge=True, downtime=True, monitored=2) self.assertEqual('downtime', under_test) - under_test = get_icon_name('host', 'OK', acknowledge=False, downtime=False, monitored=1) + under_test = get_icon_name( + 'host', 'WRONG_STATUS', acknowledge=False, downtime=False, monitored=1) self.assertEqual('error', under_test) - under_test = get_icon_name('host', 'OK', acknowledge=False, downtime=False, monitored=False + False) + under_test = get_icon_name( + 'host', 'UP', acknowledge=False, downtime=False, monitored=False + False) self.assertEqual('hosts_not_monitored', under_test) def test_get_icon_name_from_state(self): @@ -196,7 +203,8 @@ def test_get_host_msg_and_event_type(self): under_test = get_host_msg_and_event_type(host_and_services) self.assertEqual( - 'Host1 is UNKNOWN and acknowledged, some services may be in critical condition or unreachable !', + 'Host1 is UNKNOWN and acknowledged, ' + 'some services may be in critical condition or unreachable !', under_test['message'] ) self.assertEqual(under_test['event_type'], 'DOWN') @@ -342,7 +350,7 @@ def test_get_request_event_model(self): self.assertTrue('projection' in under_test) def test_get_request_livesynthesis_model(self): - """Get Event Request Model""" + """Get LiveSynthesis Request Model""" under_test = LiveSynthesis.get_request_model() @@ -350,3 +358,13 @@ def test_get_request_livesynthesis_model(self): self.assertEqual('livesynthesis', under_test['endpoint']) self.assertTrue('params' in under_test) self.assertTrue('projection' in under_test) + + def get_request_realm_model(self): + """get Realm Request Model""" + + under_test = Realm.get_request_model() + + self.assertTrue('endpoint' in under_test) + self.assertEqual('realm', under_test['endpoint']) + self.assertTrue('params' in under_test) + self.assertTrue('projection' in under_test) diff --git a/test/test_app.py b/test/test_app.py index 43e858f..785f447 100644 --- a/test/test_app.py +++ b/test/test_app.py @@ -24,7 +24,7 @@ import unittest2 from PyQt5.QtWidgets import QApplication -from alignak_app.app import AlignakApp, AppProgressBar +from alignak_app.app import AppProgressBar class TestApp(unittest2.TestCase): @@ -41,20 +41,6 @@ def setUpClass(cls): except: pass - def test_app_reconnect_mode(self): - """Reconnect App""" - - under_test = AlignakApp() - - self.assertIsNone(under_test.tray_icon) - self.assertFalse(under_test.reconnect_mode) - - # Build alignak_app - under_test.app_reconnecting_mode('ERROR') - - self.assertIsNone(under_test.tray_icon) - self.assertTrue(under_test.reconnect_mode) - def test_app_progressbar(self): """App Progress Bar""" diff --git a/test/test_backend.py b/test/test_backend.py index d96ec63..7b5f169 100644 --- a/test/test_backend.py +++ b/test/test_backend.py @@ -42,7 +42,10 @@ def test_log_to_backend(self): under_test = BackendClient() - connect = under_test.login() + connect = under_test.login( + settings.get_config('Alignak', 'username'), + settings.get_config('Alignak', 'password') + ) # Compare config url and app_backend self.assertEquals( @@ -53,9 +56,8 @@ def test_log_to_backend(self): self.assertTrue(under_test.backend.authenticated) self.assertTrue(connect) - second_test = BackendClient() - - connect = second_test.login('admin', 'admin') + # Assert on second connection, backend use token ! + connect = under_test.login() self.assertTrue(connect) def test_get_endpoint_with_params_and_projection(self): @@ -63,7 +65,10 @@ def test_get_endpoint_with_params_and_projection(self): backend_test = BackendClient() - backend_test.login() + backend_test.login( + settings.get_config('Alignak', 'username'), + settings.get_config('Alignak', 'password') + ) # Get hosts states test_projection = [ @@ -83,7 +88,10 @@ def test_patch(self): """PATCH User Notes""" under_test = BackendClient() - under_test.login() + under_test.login( + settings.get_config('Alignak', 'username'), + settings.get_config('Alignak', 'password') + ) users = under_test.get('user') user = users['_items'][0] @@ -108,18 +116,27 @@ def test_patch(self): self.assertNotEqual(user_modified['notes'], notes) self.assertEqual(user_modified['notes'], '') - def test_get_realm_name(self): - """Get User Realm Name""" + def test_query_realms_data(self): + """Query Realms Data""" - backend_test = BackendClient() - backend_test.login() + under_test = BackendClient() + under_test.login() + + from alignak_app.backend.datamanager import data_manager + under_test.query_realms_data() + + self.assertIsNotNone(data_manager.database['realm']) + + def test_query_period_data(self): + """Query TimePeriod Data""" - under_test = backend_test.get_realm_name('false_id') - self.assertEqual('n/a', under_test) + under_test = BackendClient() + under_test.login() + + from alignak_app.backend.datamanager import data_manager + under_test.query_period_data() - backend_test.login() - under_test2 = backend_test.get_realm_name('59c4e38535d17b8dcb0bed42') - self.assertEqual('All', under_test2) + self.assertIsNotNone(data_manager.database['timeperiod']) def test_query_user_data(self): """Query User Data""" @@ -180,7 +197,10 @@ def test_query_history_data(self): """Query History Data""" under_test = BackendClient() - under_test.login() + under_test.login( + settings.get_config('Alignak', 'username'), + settings.get_config('Alignak', 'password') + ) from alignak_app.backend.datamanager import data_manager under_test.query_history_data(self.hostname, self.host_id) @@ -198,20 +218,6 @@ def test_query_history_data(self): self.assertEqual(old_database[0].item_id, data_manager.database['history'][0].item_id) self.assertEqual(old_database[0].item_id, self.host_id) - def test_get_period_name(self): - """Get Period Name""" - - backend_test = BackendClient() - backend_test.login() - - under_test = backend_test.get_period_name('host') - - self.assertEqual('n/a', under_test) - - under_test = backend_test.get_period_name('service') - - self.assertEqual('n/a', under_test) - def test_get_backend_status_icon(self): """Get Backend Status Icon Name""" @@ -220,7 +226,10 @@ def test_get_backend_status_icon(self): under_test = backend_test.get_backend_status_icon() self.assertEqual('disconnected', under_test) - backend_test.login() + backend_test.login( + settings.get_config('Alignak', 'username'), + settings.get_config('Alignak', 'password') + ) under_test = backend_test.get_backend_status_icon() self.assertEqual('connected', under_test) diff --git a/test/test_data_manager.py b/test/test_data_manager.py index bb40892..712bf46 100644 --- a/test/test_data_manager.py +++ b/test/test_data_manager.py @@ -27,6 +27,8 @@ from alignak_app.items.livesynthesis import LiveSynthesis from alignak_app.items.service import Service from alignak_app.items.user import User +from alignak_app.items.realm import Realm +from alignak_app.items.period import Period class TestDataManager(unittest2.TestCase): @@ -151,6 +153,54 @@ class TestDataManager(unittest2.TestCase): event.create(data['_id'], data) event_list.append(event) + # Realm data test + realm_list = [] + for i in range(0, 10): + realm = Realm() + realm.create( + '_id%d' % i, + { + 'name': 'realm%d' % i, + 'alias': 'My Realm %d' % i, + }, + 'realm%d' % i + ) + realm_list.append(realm) + + realm_noalias = Realm() + realm_noalias.create( + '_id', + { + 'name': 'realm', + }, + 'realm' + ) + realm_list.append(realm_noalias) + + # TimePeriod data test + period_list = [] + for i in range(0, 10): + period = Realm() + period.create( + '_id%d' % i, + { + 'name': 'period%d' % i, + 'alias': 'My Time Period %d' % i, + }, + 'period%d' % i + ) + period_list.append(period) + + period_noalias = Period() + period_noalias.create( + '_id', + { + 'name': 'period', + }, + 'period' + ) + period_list.append(period_noalias) + def test_initialize(self): """Initialize DataManager""" @@ -211,6 +261,52 @@ def test_get_item(self): self.assertIsNone(item3) + def test_get_realm_name(self): + """Get Realm in db""" + + under_test = DataManager() + + self.assertFalse(under_test.database['realm']) + + under_test.update_database('realm', self.realm_list) + + self.assertTrue(under_test.database['realm']) + + realm_test = under_test.get_realm_name('_id2') + + self.assertEqual('My Realm 2', realm_test) + + noalias_realm_test = under_test.get_realm_name('_id') + + self.assertEqual('Realm', noalias_realm_test) + + no_realm_test = under_test.get_realm_name('no_realm') + + self.assertEqual('n/a', no_realm_test) + + def test_get_period_name(self): + """Get Time Period in db""" + + under_test = DataManager() + + self.assertFalse(under_test.database['timeperiod']) + + under_test.update_database('timeperiod', self.period_list) + + self.assertTrue(under_test.database['timeperiod']) + + period_test = under_test.get_period_name('_id4') + + self.assertEqual('My Time Period 4', period_test) + + noalias_period_test = under_test.get_period_name('_id') + + self.assertEqual('Period', noalias_period_test) + + no_period_test = under_test.get_period_name('no_period') + + self.assertEqual('n/a', no_period_test) + def test_get_livesynthesis(self): """Get Livesynthesis in db""" @@ -317,12 +413,25 @@ def test_is_ready(self): under_test = DataManager() - self.assertNotEqual('READY', under_test.is_ready()) - + self.assertEqual('Collecting livesynthesis...', under_test.is_ready()) under_test.update_database('livesynthesis', {'data': 'test'}) - self.assertNotEqual('READY', under_test.is_ready()) + + self.assertEqual('Collecting host...', under_test.is_ready()) under_test.update_database('host', {'data': 'test'}) - self.assertNotEqual('READY', under_test.is_ready()) + + self.assertEqual('Collecting alignakdaemon...', under_test.is_ready()) + under_test.update_database('alignakdaemon', {'data': 'test'}) + + self.assertEqual('Collecting user...', under_test.is_ready()) + under_test.update_database('user', {'data': 'test'}) + + self.assertEqual('Collecting realm...', under_test.is_ready()) + under_test.update_database('realm', {'data': 'test'}) + + self.assertEqual('Collecting timeperiod...', under_test.is_ready()) + under_test.update_database('timeperiod', {'data': 'test'}) + + self.assertEqual('Collecting service...', under_test.is_ready()) under_test.update_database('service', {'data': 'test'}) self.assertEqual('READY', under_test.is_ready()) diff --git a/test/test_host_widget.py b/test/test_host_widget.py index e620c55..826043d 100644 --- a/test/test_host_widget.py +++ b/test/test_host_widget.py @@ -29,12 +29,26 @@ from alignak_app.items.service import Service from alignak_app.items.user import User from alignak_app.utils.config import settings +from alignak_app.locales.locales import init_localization +from alignak_app.qobjects.panel.host import HostQWidget -app = QApplication(sys.argv) +# app = QApplication(sys.argv) +init_localization() data_manager.database['user'] = User() data_manager.database['user'].create('_id', {}, 'name') -from alignak_app.qobjects.panel.host import HostQWidget +host = Host() +host.create( + '_id1', + { + 'name': 'localhost', + 'ls_state': 'DOWN', + 'ls_acknowledged': False, + 'ls_downtimed': False, + }, + 'localhost' +) +data_manager.database['host'] = [host] class TestHostQWidget(unittest2.TestCase): @@ -78,6 +92,7 @@ def test_set_data(self): self.assertIsNone(under_test.host_item) self.assertIsNone(under_test.service_items) + data_manager.database['host'] = [host] under_test.set_data('localhost') self.assertIsNotNone(under_test.host_item) diff --git a/test/test_thread_manager.py b/test/test_thread_manager.py index 01143bd..7fcde3e 100644 --- a/test/test_thread_manager.py +++ b/test/test_thread_manager.py @@ -20,7 +20,6 @@ # along with (AlignakApp). If not, see . import unittest2 -from PyQt5.Qt import QTimer from alignak_app.utils.config import settings from alignak_app.locales.locales import init_localization @@ -42,14 +41,11 @@ def test_initialize_thread_manager(self): under_test = ThreadManager() - self.assertFalse(under_test.current_threads) - self.assertIsNotNone(under_test.timer) - self.assertIsInstance(under_test.timer, QTimer) - self.assertEqual( - ['user', 'host', 'service', 'livesynthesis', - 'alignakdaemon', 'notifications', 'history'], - under_test.threads_to_launch - ) + self.assertFalse(under_test.current_thread) + self.assertFalse(under_test.priority_threads) + for thread in ['livesynthesis', 'host', 'service', 'user', + 'alignakdaemon', 'notifications', 'history']: + self.assertTrue(thread in under_test.threads_to_launch) def test_get_threads_to_launch(self): """Get QThreads to Launch""" @@ -59,19 +55,27 @@ def test_get_threads_to_launch(self): under_test = thread_mgr_test.get_threads_to_launch() # If there is no current thread, all threads are added - self.assertEqual([], thread_mgr_test.current_threads) - self.assertEqual( - ['user', 'host', 'service', 'livesynthesis', - 'alignakdaemon', 'notifications', 'history'], - under_test - ) + self.assertIsNone(thread_mgr_test.current_thread) + for thread in ['livesynthesis', 'host', 'service', 'user', 'alignakdaemon', + 'notifications', 'history']: + self.assertTrue(thread in under_test) - thread_mgr_test.current_threads = [BackendQThread('user'), BackendQThread('host')] + thread_mgr_test.current_thread = BackendQThread('user') under_test = thread_mgr_test.get_threads_to_launch() # If there is current thread, ThreadManager add only threads who are necessary - self.assertNotEqual([], thread_mgr_test.current_threads) + self.assertNotEqual([], thread_mgr_test.current_thread) self.assertTrue('user' not in under_test) - self.assertTrue('host' not in under_test) + def test_priority_threads(self): + """Remove Priority Threads""" + + under_test = ThreadManager() + under_test.priority_threads.append(BackendQThread('user')) + + self.assertTrue(under_test.priority_threads) + + under_test.stop_priority_threads() + + self.assertFalse(under_test.priority_threads) diff --git a/test/test_tray_icon.py b/test/test_tray_icon.py index 6e19a8b..e808ab1 100644 --- a/test/test_tray_icon.py +++ b/test/test_tray_icon.py @@ -86,7 +86,7 @@ def test_about_action(self): self.assertFalse(under_test.qaction_factory.actions) - under_test.create_about_action() + under_test.add_about_menu() self.assertIsNotNone(under_test.qaction_factory) self.assertIsInstance(under_test.qaction_factory.get_action('about'), QAction)