diff --git a/.pylintrc b/.pylintrc index dd31fb26..283432d0 100644 --- a/.pylintrc +++ b/.pylintrc @@ -64,7 +64,7 @@ disable=R0903, R0902, C0200, C0114, C0103, R1705, R0913, W0102, C0112, R1720, R0915, W0237, R1732, W1514, R1718, - C0206, W0236, W0223, + C0206, W0236, W0223, W1201, print-statement, parameter-unpacking, unpacking-in-except, diff --git a/powerapi/actor.py b/powerapi/actor.py index 47bedfd7..64a72285 100644 --- a/powerapi/actor.py +++ b/powerapi/actor.py @@ -178,7 +178,7 @@ def receiveMsg_StartMessage(self, message: StartMessage, sender: ActorAddress): Actor.receiveMsg_StartMessage(self, message, sender) self.wakeupAfter(self._time_interval) - def receiveMsg_WakeupMessage(self, message: WakeupMessage, _: ActorAddress): + def receiveMsg_WakeupMessage(self, _: WakeupMessage, __: ActorAddress): """ When receiving a WakeupMessage, launch the actor task """ diff --git a/powerapi/cli/__init__.py b/powerapi/cli/__init__.py index 8be7c309..0d77e689 100644 --- a/powerapi/cli/__init__.py +++ b/powerapi/cli/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/cli/config_validator.py b/powerapi/cli/config_validator.py index 58fe320d..eebf6434 100644 --- a/powerapi/cli/config_validator.py +++ b/powerapi/cli/config_validator.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/cli/parser.py b/powerapi/cli/parser.py index 259b8f4d..c4029aaf 100644 --- a/powerapi/cli/parser.py +++ b/powerapi/cli/parser.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/database/__init__.py b/powerapi/database/__init__.py index 35f94e0d..628d85e0 100644 --- a/powerapi/database/__init__.py +++ b/powerapi/database/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,7 +26,6 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - from powerapi.database.base_db import BaseDB, IterDB, DBError from powerapi.database.csvdb import CsvDB, CsvBadFilePathError from powerapi.database.csvdb import CsvBadCommonKeysError, HeaderAreNotTheSameError @@ -36,4 +35,4 @@ from powerapi.database.prometheus_db import PrometheusDB from powerapi.database.virtiofs_db import VirtioFSDB from powerapi.database.direct_prometheus_db import DirectPrometheusDB -from .socket_db import SocketDB +from powerapi.database.socket_db import SocketDB diff --git a/powerapi/database/base_db.py b/powerapi/database/base_db.py index 02a22a48..d78861b8 100644 --- a/powerapi/database/base_db.py +++ b/powerapi/database/base_db.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,7 +26,6 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - from typing import List, Type from powerapi.report import Report from powerapi.exception import PowerAPIExceptionWithMessage @@ -91,8 +90,6 @@ def connect(self): def iter(self, stream_mode: bool) -> IterDB: """ Create the iterator for get the data - :param report_model: Object that herit from ReportModel and define - the type of Report :param stream_mode: Define if we read in stream mode """ raise NotImplementedError() @@ -102,7 +99,6 @@ def save(self, report: Report): Allow to save a json input in the db :param report: Report - :param report_model: ReportModel """ raise NotImplementedError() @@ -111,6 +107,5 @@ def save_many(self, reports: List[Report]): Allow to save a batch of data :param reports: Batch of Serialized Report - :param report_model: ReportModel """ raise NotImplementedError() diff --git a/powerapi/database/csvdb.py b/powerapi/database/csvdb.py index 1383de37..ffb7722a 100644 --- a/powerapi/database/csvdb.py +++ b/powerapi/database/csvdb.py @@ -26,7 +26,6 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - import csv import os @@ -65,10 +64,10 @@ class CsvIterDB(IterDB): This class allows to browse a database as an iterable """ - def __init__(self, db, filenames, report_model, stream_mode): + def __init__(self, db, filenames, report_type, stream_mode): """ """ - super().__init__(db, report_model, stream_mode) + super().__init__(db, report_type, stream_mode) self.filenames = filenames @@ -160,7 +159,7 @@ def __next__(self) -> Report: if row_timestamp > current_timestamp: if path_file == self.filenames[-1]: self.saved_timestamp = row_timestamp - break # move to next file + break # move to next file if row_timestamp < current_timestamp: self.tmp_read[path_file]['next_line'] = self._next(path_file) @@ -168,7 +167,7 @@ def __next__(self) -> Report: if previous_target is not None: if row['target'] != previous_target: - break # move to next file + break # move to next file else: previous_target = row['target'] @@ -191,7 +190,7 @@ class CsvDB(BaseDB): CsvDB class herited from BaseDB This class define the behaviour for reading some csv file. - a CsvDB instance can be define by his ReportModel and its current path + a CsvDB instance can be define by its current path """ def __init__(self, report_type: Type[Report], tags: List[str], current_path="/tmp/csvdbtest", files=[]): @@ -265,7 +264,6 @@ def save(self, report: Report): Allow to save a serialized_report in the db :param report: Report - :param report_model: ReportModel """ csv_header, data = self.report_type.to_csv_lines(report, self.tags) @@ -308,7 +306,6 @@ def save_many(self, reports: List[Report]): Allow to save a batch of report :param reports: Batch of report. - :param report_model: ReportModel """ for report in reports: self.save(report) diff --git a/powerapi/database/direct_prometheus_db.py b/powerapi/database/direct_prometheus_db.py index 6f6dab65..b34837bd 100644 --- a/powerapi/database/direct_prometheus_db.py +++ b/powerapi/database/direct_prometheus_db.py @@ -34,8 +34,8 @@ except ImportError: logging.getLogger().info("prometheus-client is not installed.") -from powerapi.database import BaseDB from powerapi.report import Report +from .base_db import BaseDB class DirectPrometheusDB(BaseDB): diff --git a/powerapi/database/influxdb.py b/powerapi/database/influxdb.py index cba4264b..5b2f9851 100644 --- a/powerapi/database/influxdb.py +++ b/powerapi/database/influxdb.py @@ -26,21 +26,16 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - import logging +from typing import List, Type try: from influxdb import InfluxDBClient from requests.exceptions import ConnectionError as InfluxConnectionError except ImportError: logging.getLogger().info("influx-client is not installed.") -from typing import List, Type - - -from powerapi.database import BaseDB, DBError - from powerapi.report import Report +from .base_db import BaseDB, DBError class CantConnectToInfluxDBException(DBError): @@ -126,7 +121,6 @@ def save_many(self, reports: List[Report]): Save a batch of data :param reports: Batch of data. - :param report_model: ReportModel """ data_list = list(map(lambda r: self.report_type.to_influxdb(r, self.tags), reports)) diff --git a/powerapi/database/opentsdb.py b/powerapi/database/opentsdb.py index 864a3971..df551aa7 100644 --- a/powerapi/database/opentsdb.py +++ b/powerapi/database/opentsdb.py @@ -35,7 +35,7 @@ from typing import List, Type from powerapi.report import PowerReport, Report -from powerapi.database import BaseDB, DBError +from .base_db import BaseDB, DBError class CantConnectToOpenTSDBException(DBError): @@ -105,7 +105,6 @@ def save_many(self, reports: List[Report]): Save a batch of data :param reports: Batch of data. - :param report_model: ReportModel """ for report in reports: diff --git a/powerapi/database/prometheus_db.py b/powerapi/database/prometheus_db.py index bddc3bff..6ed3bb4f 100644 --- a/powerapi/database/prometheus_db.py +++ b/powerapi/database/prometheus_db.py @@ -27,17 +27,15 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import logging +from typing import List, Type try: from prometheus_client import start_http_server, Gauge except ImportError: logging.getLogger().info("prometheus-client is not installed.") -from typing import List, Type - -from powerapi.database import BaseDB - from powerapi.report import Report from powerapi.utils import StatBuffer +from .base_db import BaseDB class PrometheusDB(BaseDB): diff --git a/powerapi/database/socket_db.py b/powerapi/database/socket_db.py index b09f3b52..e4178591 100644 --- a/powerapi/database/socket_db.py +++ b/powerapi/database/socket_db.py @@ -30,9 +30,10 @@ from typing import Type, List import json -from powerapi.database import IterDB, BaseDB + from powerapi.utils import JsonStream from powerapi.report import Report +from .base_db import IterDB, BaseDB, DBError BUFFER_SIZE = 4096 SOCKET_TIMEOUT = 0.5 @@ -77,13 +78,13 @@ async def callback(stream_reader, _): return callback def __iter__(self): - raise NotImplementedError() + raise DBError('Socket db don\'t support __iter__ method') def save(self, report: Report): - raise NotImplementedError() + raise DBError('Socket db don\'t support save method') def save_many(self, reports: List[Report]): - raise NotImplementedError() + raise DBError('Socket db don\'t support save_many method') class IterSocketDB(IterDB): diff --git a/powerapi/database/virtiofs_db.py b/powerapi/database/virtiofs_db.py index b3e1b2d0..21918c6a 100644 --- a/powerapi/database/virtiofs_db.py +++ b/powerapi/database/virtiofs_db.py @@ -31,8 +31,8 @@ from typing import List, Type -from powerapi.database import BaseDB, DBError from powerapi.report import Report +from .base_db import BaseDB, DBError class DirectoryDoesNotExistForVirtioFS(DBError): @@ -47,18 +47,20 @@ class VirtioFSDB(BaseDB): """ write power consumption of virtual machine in a file shared with the virtual machine - The File will be written in a directory created by the VM manager. + The File will be written in a directory created by the VM manager. A regular expression must be given by the VM manager to extract vm name from target name. VM name is used to find directory that contains the output file. """ - def __init__(self, report_type: Type[Report], vm_name_regexp: str, root_directory_name: str, vm_directory_name_prefix : str = '', vm_directory_name_suffix : str = ''): + def __init__(self, report_type: Type[Report], vm_name_regexp: str, root_directory_name: str, + vm_directory_name_prefix: str = '', vm_directory_name_suffix: str = ''): """ - :param vm_name_regexp: regexp used to extract vm name from report. The regexp must match the name of the target in the HWPC-report and a group must + :param vm_name_regexp: regexp used to extract vm name from report. The regexp must match the name of the target + in the HWPC-report and a group must :param root_directory_name: directory where VM directory will be stored :param vm_directory_name_prefix: first part of the VM directory name :param vm_directory_name_suffix: last part of the VM directory name """ - BaseDB.__init__(self) + BaseDB.__init__(self, report_type) self.vm_name_regexp = re.compile(vm_name_regexp) self.root_directory_name = root_directory_name @@ -82,7 +84,7 @@ def save(self, report: Report): return vm_filename, power = self.report_type.to_virtiofs_db(report) - vm_filename_path =self.root_directory_name + '/' + directory_name + '/' + vm_filename_path = self.root_directory_name + '/' + directory_name + '/' if not os.path.exists(vm_filename_path): raise DirectoryDoesNotExistForVirtioFS(vm_filename_path) diff --git a/powerapi/dispatch_rule/__init__.py b/powerapi/dispatch_rule/__init__.py index 58f407f2..f731a68e 100644 --- a/powerapi/dispatch_rule/__init__.py +++ b/powerapi/dispatch_rule/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/dispatch_rule/dispatch_rule.py b/powerapi/dispatch_rule/dispatch_rule.py index a1746fb9..6bdf8c85 100644 --- a/powerapi/dispatch_rule/dispatch_rule.py +++ b/powerapi/dispatch_rule/dispatch_rule.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/dispatch_rule/hwpc_dispatch_rule.py b/powerapi/dispatch_rule/hwpc_dispatch_rule.py index 90fee3d7..96f2a5ac 100644 --- a/powerapi/dispatch_rule/hwpc_dispatch_rule.py +++ b/powerapi/dispatch_rule/hwpc_dispatch_rule.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ from enum import IntEnum -from powerapi.dispatch_rule import DispatchRule +from .dispatch_rule import DispatchRule class HWPCDepthLevel(IntEnum): diff --git a/powerapi/dispatch_rule/power_dispatch_rule.py b/powerapi/dispatch_rule/power_dispatch_rule.py index 3603ee28..583dedec 100644 --- a/powerapi/dispatch_rule/power_dispatch_rule.py +++ b/powerapi/dispatch_rule/power_dispatch_rule.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,10 +26,12 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - +from typing import Tuple from enum import IntEnum -from powerapi.dispatch_rule import DispatchRule +from powerapi.report import PowerReport + +from .dispatch_rule import DispatchRule class PowerDepthLevel(IntEnum): @@ -43,7 +45,10 @@ class PowerDepthLevel(IntEnum): CORE = 2 -def extract_id_from_report(report, depth): +def extract_id_from_report(report: PowerReport, depth: PowerDepthLevel) -> Tuple: + """ + :return: a report id generated from the report and the given depth + """ if depth == PowerDepthLevel.TARGET: return (report.target,) @@ -53,9 +58,9 @@ def extract_id_from_report(report, depth): if depth == PowerDepthLevel.SOCKET: return extract_id_from_report(report, depth - 1) + (report.metadata['socket'],) - if depth == PowerDepthLevel.CORE: - return extract_id_from_report(report, depth - 1) + (report.metadata['core'],) - + return extract_id_from_report(report, depth - 1) + (report.metadata['core'],) + + class PowerDispatchRule(DispatchRule): """ Group by rule for HWPC report @@ -74,7 +79,6 @@ def _set_field(self): return ['target'] return ['sensor', 'socket', 'core'][:(self.depth + 1)] - def get_formula_id(self, report): return [extract_id_from_report(report, self.depth)] diff --git a/powerapi/dispatcher/__init__.py b/powerapi/dispatcher/__init__.py index 0b761585..f3f349db 100644 --- a/powerapi/dispatcher/__init__.py +++ b/powerapi/dispatcher/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/dispatcher/dispatcher_actor.py b/powerapi/dispatcher/dispatcher_actor.py index f5c3d514..43db64ac 100644 --- a/powerapi/dispatcher/dispatcher_actor.py +++ b/powerapi/dispatcher/dispatcher_actor.py @@ -32,12 +32,12 @@ from powerapi.actor import Actor, InitializationException from powerapi.formula import FormulaActor, FormulaValues -from powerapi.dispatcher import RouteTable from powerapi.dispatch_rule import DispatchRule from powerapi.utils import Tree from powerapi.report import Report from powerapi.message import StartMessage, DispatcherStartMessage, FormulaStartMessage, EndMessage, ErrorMessage, OKMessage from powerapi.dispatcher.blocking_detector import BlockingDetector +from powerapi.dispatcher.route_table import RouteTable def _clean_list(id_list): diff --git a/powerapi/dispatcher/route_table.py b/powerapi/dispatcher/route_table.py index ea9b99c5..15be3775 100644 --- a/powerapi/dispatcher/route_table.py +++ b/powerapi/dispatcher/route_table.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/filter/filter.py b/powerapi/filter.py similarity index 97% rename from powerapi/filter/filter.py rename to powerapi/filter.py index c41e115e..955fed7b 100644 --- a/powerapi/filter/filter.py +++ b/powerapi/filter.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/filter/__init__.py b/powerapi/filter/__init__.py deleted file mode 100644 index 09a49236..00000000 --- a/powerapi/filter/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from powerapi.filter.filter import Filter, RouterWithoutRuleException diff --git a/powerapi/formula/__init__.py b/powerapi/formula/__init__.py index 248ee94e..0ac59ca8 100644 --- a/powerapi/formula/__init__.py +++ b/powerapi/formula/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/message.py b/powerapi/message.py index 68fd9da6..3885568c 100644 --- a/powerapi/message.py +++ b/powerapi/message.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,7 +33,6 @@ if TYPE_CHECKING: from powerapi.database import BaseDB from powerapi.filter import Filter - from powerapi.report_model import ReportModel from powerapi.dispatcher import RouteTable from powerapi.formula import FormulaActor, FormulaValues, DomainValues from powerapi.report_modifier import ReportModifier diff --git a/powerapi/pusher.py b/powerapi/pusher.py index 019e9671..761c140d 100644 --- a/powerapi/pusher.py +++ b/powerapi/pusher.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/report/__init__.py b/powerapi/report/__init__.py index 8966e81d..1f4ed39a 100644 --- a/powerapi/report/__init__.py +++ b/powerapi/report/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,5 +29,5 @@ from powerapi.report.report import Report, BadInputData from powerapi.report.power_report import PowerReport -from powerapi.report.hwpc_report import * +from powerapi.report.hwpc_report import HWPCReport from powerapi.report.control_report import ControlReport diff --git a/powerapi/report/control_report.py b/powerapi/report/control_report.py index f1034002..96dda84e 100644 --- a/powerapi/report/control_report.py +++ b/powerapi/report/control_report.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,13 +26,12 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - from __future__ import annotations from datetime import datetime from typing import Dict, List -from powerapi.report import Report +from .report import Report class ControlReport(Report): @@ -59,12 +58,21 @@ def __repr__(self) -> str: @staticmethod def from_json(data: Dict) -> ControlReport: + """ + :return: a dictionary, that can be converted into json format, from a given ControlReport + """ return ControlReport(data['timestamp'], data['sensor'], data['target'], data['action'], data['parameters']) @staticmethod def from_mongodb(data: Dict) -> ControlReport: + """ + :return: a ControlReport from a dictionary pulled from mongodb + """ return ControlReport.from_json(data) @staticmethod def to_mongodb(report: ControlReport) -> Dict: + """ + :return: a dictionary, that can be stored into a mongodb, from a given ControlReport + """ return report.__dict__ diff --git a/powerapi/report/hwpc_report.py b/powerapi/report/hwpc_report.py index cefac7e3..ac8d158c 100644 --- a/powerapi/report/hwpc_report.py +++ b/powerapi/report/hwpc_report.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -81,7 +81,6 @@ def __init__(self, timestamp: datetime, sensor: str, target: str, groups: Dict[s def __repr__(self) -> str: return 'HWCPReport(%s, %s, %s, %s)' % (self.timestamp, self.sensor, self.target, sorted(self.groups.keys())) - @staticmethod def from_json(data: Dict) -> HWPCReport: """ @@ -93,7 +92,7 @@ def from_json(data: Dict) -> HWPCReport: ts = Report._extract_timestamp(data['timestamp']) return HWPCReport(ts, data['sensor'], data['target'], data['groups']) except KeyError as exn: - raise BadInputData('no field ' + str(exn.args[0]) + ' in json document') + raise BadInputData('no field ' + str(exn.args[0]) + ' in json document') from exn @staticmethod def to_json(report: HWPCReport) -> Dict: @@ -101,38 +100,46 @@ def to_json(report: HWPCReport) -> Dict: @staticmethod def from_mongodb(data: Dict) -> HWPCReport: + """ + :return: a HWPCReport from a dictionary pulled from mongodb + """ return HWPCReport.from_json(data) @staticmethod def to_mongodb(report: HWPCReport) -> Dict: + """ + :return: a dictionary, that can be stored into a mongodb, from a given HWPCReport + """ return HWPCReport.to_json(report) @staticmethod - def from_csv_lines(lines: List[Tuple[str, Dict]]) -> HWPCReport: + def from_csv_lines(lines: List[Tuple[str, Dict[str, str]]]) -> HWPCReport: + """ + :param lines: list of pre-parsed lines. a line is a tuple composed with : + - the file name where the line were read + - a dictionary where key is column name and value is the value read from the line + :return: a HWPCReport that contains value from the given lines + """ sensor_name = None target = None timestamp = None groups = {} for file_name, row in lines: - group_name = file_name[:-4] if file_name[len(file_name)-4:] == '.csv' else file_name + group_name = file_name[:-4] if file_name[len(file_name) - 4:] == '.csv' else file_name try: if sensor_name is None: sensor_name = row['sensor'] + target = row['target'] + timestamp = HWPCReport._extract_timestamp(row['timestamp']) else: if sensor_name != row['sensor']: raise BadInputData('csv line with different sensor name are mixed into one report') - if target is None: - target = row['target'] - else: if target != row['target']: raise BadInputData('csv line with different target are mixed into one report') - if timestamp is None: - timestamp = HWPCReport._extract_timestamp(row['timestamp']) - else: if timestamp != HWPCReport._extract_timestamp(row['timestamp']): raise BadInputData('csv line with different timestamp are mixed into one report') - + if group_name not in groups: groups[group_name] = {} @@ -148,42 +155,6 @@ def from_csv_lines(lines: List[Tuple[str, Dict]]) -> HWPCReport: row['socket']][row['cpu']][key] = int(value) except KeyError as exn: - raise BadInputData('missing field ' + str(exn.args[0]) + ' in csv file ' + file_name) + raise BadInputData('missing field ' + str(exn.args[0]) + ' in csv file ' + file_name) from exn return HWPCReport(timestamp, sensor_name, target, groups) - -############################# -# REPORT CREATION FUNCTIONS # -############################# - - -def create_core_report(core_id, event_id, event_value, events=None): - id_str = str(core_id) - data = {id_str: {}} - if events is not None: - data[id_str] = events - return data - data[id_str] = {event_id: event_value} - return data - - -def create_socket_report(socket_id, core_list): - id_str = str(socket_id) - data = {id_str: {}} - for core in core_list: - data[id_str].update(core) - return data - - -def create_group_report(group_id, socket_list): - group = {} - for socket in socket_list: - group.update(socket) - return (group_id, group) - - -def create_report_root(group_list, timestamp=datetime.fromtimestamp(0), sensor='toto', target='system'): - sensor = HWPCReport(timestamp=timestamp, sensor=sensor, target=target, groups={}) - for (group_id, group) in group_list: - sensor.groups[group_id] = group - return sensor diff --git a/powerapi/report/power_report.py b/powerapi/report/power_report.py index a8ce4b07..65282036 100644 --- a/powerapi/report/power_report.py +++ b/powerapi/report/power_report.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -70,11 +70,16 @@ def from_json(data: Dict) -> Report: ts = Report._extract_timestamp(data['timestamp']) return PowerReport(ts, data['sensor'], data['target'], data['power'], data['metadata']) except KeyError as exn: - raise BadInputData('no field ' + str(exn.args[0]) + ' in json document') + raise BadInputData('no field ' + str(exn.args[0]) + ' in json document') from exn @staticmethod def from_csv_lines(lines: List[Tuple[str, Dict]]) -> PowerReport: - + """ + :param lines: list of pre-parsed lines. a line is a tuple composed with : + - the file name where the line were read + - a dictionary where key is column name and value is the value read from the line + :return: a PowerReport that contains value from the given lines + """ if len(lines) != 1: raise BadInputData('a power report could only be parsed from one csv line') file_name, row = lines[0] @@ -84,8 +89,6 @@ def from_csv_lines(lines: List[Tuple[str, Dict]]) -> PowerReport: target = row['target'] timestamp = Report._extract_timestamp(row['timestamp']) power = float(row['power']) - socket = int(row['socket']) - core = -1 if 'core' not in row else row['core'] metadata = {} for key in row.keys(): @@ -94,10 +97,18 @@ def from_csv_lines(lines: List[Tuple[str, Dict]]) -> PowerReport: return PowerReport(timestamp, sensor_name, target, power, metadata) except KeyError as exn: - raise BadInputData('missing field ' + str(exn.args[0]) + ' in csv file ' + file_name) + raise BadInputData('missing field ' + str(exn.args[0]) + ' in csv file ' + file_name) from exn @staticmethod def to_csv_lines(report: PowerReport, tags: List[str]) -> Tuple[List[str], Dict]: + """ + convert a power report into csv lines + :param report: Report that will be converted into csv lines + :param tags: metadata added as columns in csv file + :return: list of pre-parsed lines. a line is a tuple composed with : + - the file name where the line were read + - a dictionary where key is column name and value is the value read from the line + """ line = { 'sensor': report.sensor, 'target': report.target, @@ -130,7 +141,7 @@ def _gen_tag(self, metadata_keept): for metadata_name in metadata_keept: if metadata_name not in self.metadata: - raise BadInputData('no tag ' + tag + ' in power report') + raise BadInputData('no tag ' + metadata_name + ' in power report') else: tags[metadata_name] = self.metadata[metadata_name] @@ -138,6 +149,9 @@ def _gen_tag(self, metadata_keept): @staticmethod def to_influxdb(report: PowerReport, tags: List[str]) -> Dict: + """ + :return: a dictionary, that can be stored into an influxdb, from a given PowerReport + """ return { 'measurement': 'power_consumption', 'tags': report._gen_tag(tags), @@ -149,6 +163,9 @@ def to_influxdb(report: PowerReport, tags: List[str]) -> Dict: @staticmethod def to_prometheus(report: PowerReport, tags: List[str]) -> Dict: + """ + :return: a dictionary, that can be stored into a prometheus instance, from a given PowerReport + """ return { 'tags': report._gen_tag(tags), 'time': int(report.timestamp.timestamp()), @@ -157,9 +174,14 @@ def to_prometheus(report: PowerReport, tags: List[str]) -> Dict: @staticmethod def to_mongodb(report: PowerReport) -> Dict: + """ + :return: a dictionary, that can be stored into a mongodb, from a given PowerReport + """ return PowerReport.to_json(report) @staticmethod def from_mongodb(data: Dict) -> Report: + """ + :return: a PowerReport from a dictionary pulled from mongodb + """ return PowerReport.from_json(data) - diff --git a/powerapi/report/report.py b/powerapi/report/report.py index 5f19c8bf..376002a8 100644 --- a/powerapi/report/report.py +++ b/powerapi/report/report.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ from __future__ import annotations from datetime import datetime -from typing import Dict, List +from typing import Dict from powerapi.exception import PowerAPIExceptionWithMessage from powerapi.message import Message @@ -42,7 +42,6 @@ class BadInputData(PowerAPIExceptionWithMessage): """ Exception raised when input data can't be converted to a Report """ - class Report(Message): @@ -57,6 +56,7 @@ def __init__(self, timestamp: datetime, sensor: str, target: str): :param str sensor: Sensor name. :param str target: Target name. """ + Message.__init__(self, None) self.timestamp = timestamp self.sensor = sensor self.target = target @@ -76,13 +76,11 @@ def __eq__(self, other): self.sensor == other.sensor and self.target == other.target) - @staticmethod - def get_tags() -> List[str]: - return ['target', 'sensor'] - - @staticmethod def to_json(report: Report) -> Dict: + """ + :return: a json dictionary, that can be converted into json format, from a given Report + """ return report.__dict__ @staticmethod @@ -90,10 +88,12 @@ def _extract_timestamp(ts): if isinstance(ts, str): try: return datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S.%f") - except ValueError as exn: + except ValueError: try: - return datetime.fromtimestamp(int(ts)/1000) - except ValueError: - raise BadInputData(exn.args) + return datetime.fromtimestamp(int(ts) / 1000) + except ValueError as exn: + raise BadInputData(exn.args) from exn if isinstance(ts, datetime): return ts + + raise BadInputData('timestamp must be a datetime.datetime or a string') diff --git a/powerapi/report_modifier/__init__.py b/powerapi/report_modifier/__init__.py index 83c03af0..755d21bb 100644 --- a/powerapi/report_modifier/__init__.py +++ b/powerapi/report_modifier/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/report_modifier/libvirt_mapper.py b/powerapi/report_modifier/libvirt_mapper.py index e34235c1..bb8933bb 100644 --- a/powerapi/report_modifier/libvirt_mapper.py +++ b/powerapi/report_modifier/libvirt_mapper.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/report_modifier/report_modifier.py b/powerapi/report_modifier/report_modifier.py index 37d87643..2b2e3d0f 100644 --- a/powerapi/report_modifier/report_modifier.py +++ b/powerapi/report_modifier/report_modifier.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/supervisor.py b/powerapi/supervisor.py index acc1362a..7fa0d9c2 100644 --- a/powerapi/supervisor.py +++ b/powerapi/supervisor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -133,7 +133,6 @@ def launch(self, actor_cls: Type[Actor], start_message: StartMessage): return address elif isinstance(answer, ErrorMessage): raise InitializationException(answer.error_message) - print(answer) raise InitializationException("Unknow message type : " + str(type(answer))) def _add_actor(self, address, name, actor_cls): diff --git a/powerapi/test_utils/__init__.py b/powerapi/test_utils/__init__.py index 722f5d56..582930c5 100644 --- a/powerapi/test_utils/__init__.py +++ b/powerapi/test_utils/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/test_utils/abstract_test.py b/powerapi/test_utils/abstract_test.py index f773e365..6029d042 100644 --- a/powerapi/test_utils/abstract_test.py +++ b/powerapi/test_utils/abstract_test.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -30,33 +30,46 @@ import pytest -from thespian.actors import ActorSystem, ActorExitRequest +from thespian.actors import ActorSystem from powerapi.message import OKMessage, ErrorMessage, PingMessage, EndMessage -from powerapi.actor import Actor from .db import FakeDB, CrashDB from .dummy_actor import DummyActor, DummyStartMessage, logger from .actor import system, is_actor_alive -LOGGER_NAME='thespian_test_logger' +LOGGER_NAME = 'thespian_test_logger' + def recv_from_pipe(pipe, timeout): + """ + add timeout to function pipe.recv + """ if pipe.poll(timeout): return pipe.recv() else: return None + class UnknowMessage: - pass + """ + Message of type unknown. + """ + class AbstractTestActor: """ - test basic actor behaviour + Basic test that an actor should pass + + To use it with an actor that you create you must implement the method actor and actor_start_message + test function added to this class must take in parameter the two fixtures system and (actor of started_actor) """ - @classmethod + @classmethod def teardown_class(cls): - while ActorSystem().listen(0.1) != None: + """ + After all test was executed, shutdown the actor system + """ + while ActorSystem().listen(0.1) is not None: continue ActorSystem().shutdown() @@ -83,14 +96,23 @@ def dummy_pipe_in(self, dummy_pipe): @pytest.fixture def actor(self): + """ + This fixture must return the actor class of the tested actor + """ raise NotImplementedError() @pytest.fixture def actor_start_message(self): + """ + This fixture must return an instance of start message used to start the tested actor + """ raise NotImplementedError() @pytest.fixture def started_actor(self, system, actor, actor_start_message): + """ + fixture that return and actor that was started with a StartMessage + """ system.ask(actor, actor_start_message) return actor @@ -118,16 +140,32 @@ def test_send_EndMessage_to_started_actor_make_it_terminate(self, system, starte system.tell(started_actor, EndMessage) assert not is_actor_alive(system, started_actor) + def define_database_content(content): + """ + Decorator used to define database content when using an actor with database + + ! If you use this decorator, you need to insert handler in pytest_generate_tests function ! + ! see tests/unit/test_puller.py::pytest_generate_tests for example ! + """ def wrap(func): setattr(func, '_content', content) return func return wrap + class AbstractTestActorWithDB(AbstractTestActor): + """ + Base test for actor using a database + + This class add fixtures to communicate with a fake database + """ @pytest.fixture def pipe(self): + """ + pipe used to communicate between pytest process and actor + """ return Pipe() @pytest.fixture @@ -146,10 +184,16 @@ def pipe_in(self, pipe): @pytest.fixture def fake_db(self, content, pipe_in): + """ + Return a FakeDB that will send information through the pipe when using its API + """ return FakeDB(content, pipe_in) @pytest.fixture def crash_db(self): + """ + Return a FakeDB that will crash when using its connect method + """ return CrashDB() @pytest.fixture @@ -161,5 +205,3 @@ def started_actor(self, actor, pipe_out, fake_db, actor_start_message): def test_starting_actor_make_it_connect_to_database(self, system, actor, actor_start_message, pipe_out): ActorSystem().ask(actor, actor_start_message) assert pipe_out.recv() == 'connected' - - diff --git a/powerapi/test_utils/actor.py b/powerapi/test_utils/actor.py index cc0ead05..bc3ba2e1 100644 --- a/powerapi/test_utils/actor.py +++ b/powerapi/test_utils/actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ from powerapi.dispatcher import DispatcherActor from powerapi.formula import FormulaActor from powerapi.message import PusherStartMessage, PullerStartMessage, DispatcherStartMessage, FormulaStartMessage -from powerapi.message import PingMessage, StartMessage, OKMessage +from powerapi.message import PingMessage, OKMessage from powerapi.supervisor import LOG_DEF @@ -45,14 +45,22 @@ DISPATCHER_NAME = 'test_dispatcher' DISPATCHER_DEVICE_ID = 'test_device' + @pytest.fixture def system(): + """ + fixture that start an Actor system with log enabled before launching the test and shutdown it after the test end + """ syst = ActorSystem(systemBase='multiprocQueueBase', logDefs=LOG_DEF) yield syst syst.shutdown() + @pytest.fixture def shutdown_system(): + """ + fixture that shutdown all multiproQeueuBase actor system after the test end + """ yield None syst = ActorSystem(systemBase='multiprocQueueBase', logDefs=LOG_DEF) syst.shutdown() @@ -60,6 +68,9 @@ def shutdown_system(): @pytest.fixture() def puller(system): + """ + fixture that create a PullerActor before launching the test and stop it after the test end + """ actor = system.createActor(PullerActor) yield actor system.tell(actor, ActorExitRequest()) @@ -67,34 +78,53 @@ def puller(system): @pytest.fixture() def puller_start_message(database, report_filter, stream_mode): + """ + return a puller start message + """ return PullerStartMessage('system', PULLER_NAME, database, report_filter, stream_mode) @pytest.fixture() def started_puller(system, puller, puller_start_message): + """ + fixture that create and start a PullerActor and actor before launching the test and stop it after the test end + """ system.ask(puller, puller_start_message) return puller @pytest.fixture() def pusher(system): + """ + fixture that create a PusherActor before launching the test and stop it after the test end + """ actor = system.createActor(PusherActor) yield actor system.tell(actor, ActorExitRequest()) @pytest.fixture() -def pusher_start_message(database, report_type): +def pusher_start_message(database): + """ + return a pusher start message + """ return PusherStartMessage('system', PUSHER_NAME, database) @pytest.fixture() def started_pusher(system, pusher, pusher_start_message): + """ + fixture that create and start a PusherActor and actor before launching the test and stop it after the test end + """ system.ask(pusher, pusher_start_message) return pusher + @pytest.fixture() def dispatcher(system): + """ + fixture that create a DispatcherActor before launching the test and stop it after the test end + """ actor = system.createActor(DispatcherActor) yield actor system.tell(actor, ActorExitRequest()) @@ -102,10 +132,17 @@ def dispatcher(system): @pytest.fixture() def dispatcher_start_message(formula_class, formula_values, route_table): + """ + return a dispatcher start message + """ return DispatcherStartMessage('system', DISPATCHER_NAME, formula_class, formula_values, route_table, DISPATCHER_DEVICE_ID) + @pytest.fixture() def started_dispatcher(system, dispatcher, dispatcher_start_message): + """ + fixture that create and start a DispatcherActor and actor before launching the test and stop it after the test end + """ system.ask(dispatcher, dispatcher_start_message) return dispatcher @@ -118,6 +155,9 @@ def __init__(self): FormulaActor.__init__(self, FormulaStartMessage) def receiveMsg_Report(self, message: Report, sender: ActorAddress): + """ + crash when receiving a report + """ raise Exception() @@ -126,5 +166,4 @@ def is_actor_alive(system, actor_address, time=1): wait the actor to terminate or 0.5 secondes and return its is_alive value """ msg = system.ask(actor_address, PingMessage('system'), time) - print(msg) return isinstance(msg, OKMessage) diff --git a/powerapi/test_utils/db/__init__.py b/powerapi/test_utils/db/__init__.py index 05742818..d02c05f5 100644 --- a/powerapi/test_utils/db/__init__.py +++ b/powerapi/test_utils/db/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/powerapi/test_utils/db/csv.py b/powerapi/test_utils/db/csv.py index a1347ae7..6f0ff997 100644 --- a/powerapi/test_utils/db/csv.py +++ b/powerapi/test_utils/db/csv.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -40,7 +40,9 @@ @pytest.fixture def files(): + """ + fixture that remove csv files used by test module before launching the test and after the test end + """ os.system('rm -Rf ' + OUTPUT_PATH + 'grvingt-12-system') yield None os.system('rm -Rf ' + OUTPUT_PATH + 'grvingt-12-system') - return None diff --git a/powerapi/test_utils/db/db.py b/powerapi/test_utils/db/db.py index 6d61c0a3..93bd081a 100644 --- a/powerapi/test_utils/db/db.py +++ b/powerapi/test_utils/db/db.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -26,22 +26,30 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - from powerapi.database import BaseDB, DBError from powerapi.report import Report + class FakeDBError(Exception): - pass + """ + Exception raised to crash the db + """ + class FakeDB(BaseDB): + """ + A fake database that send information throug a pipe when its api is used + """ def __init__(self, content=[], pipe=None, *args, **kwargs): BaseDB.__init__(self, Report) self._content = content self.pipe = pipe - self.exceptions = [FakeDBError] def connect(self): + """ + send the string connected through the pipe + """ if self.pipe is not None: self.pipe.send('connected') @@ -49,20 +57,28 @@ def iter(self, stream_mode): return self._content.__iter__() def save(self, report): + """ + send the saved report through the pipe + """ if self.pipe is not None: self.pipe.send(report) def save_many(self, reports): + """ + send the saved reports through the pipe + """ if self.pipe is not None: self.pipe.send(reports) + class SilentFakeDB(BaseDB): """ - An empty Database that don't send log message + An empty Database that don't send information through the pipe """ def __init__(self, content=[], pipe=None, *args, **kwargs): BaseDB.__init__(self, Report) - self._content = [] + self._content = content + def connect(self): pass @@ -77,19 +93,23 @@ def save_many(self, reports): class CrashDB(BaseDB): - + """ + FakeDB that crash when using its connect method + """ def __init__(self, *args, **kwargs): BaseDB.__init__(self, Report) def connect(self): raise DBError('crash') + def define_database(database): """ Decorator to set the _database attribute for individual tests. ! If you use this decorator, you need to insert handler in pytest_generate_tests function ! + ! see tests/unit/test_puller.py::pytest_generate_tests for example ! """ def wrap(func): setattr(func, '_database', database) @@ -103,6 +123,7 @@ def define_report_type(report_type): attribute for individuel tests. ! If you use this decorator, you need to insert handler in pytest_generate_tests function ! + ! see tests/unit/test_puller.py::pytest_generate_tests for example ! """ def wrap(func): setattr(func, '_report_type', report_type) diff --git a/powerapi/test_utils/db/influx.py b/powerapi/test_utils/db/influx.py index c985e7cd..20538191 100644 --- a/powerapi/test_utils/db/influx.py +++ b/powerapi/test_utils/db/influx.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -26,12 +26,10 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import datetime - import pytest from influxdb import InfluxDBClient -from ..report.power import SENSOR_NAME, TARGET_NAME + INFLUX_URI = 'localhost' INFLUX_PORT = 8086 @@ -40,26 +38,34 @@ @pytest.fixture() def influx_database(influxdb_content): + """ + connect to a local influx database (localhost:8086) and store data contained in the list influxdb_content + after test end, delete the data + """ client = InfluxDBClient(host=INFLUX_URI, port=INFLUX_PORT) - delete_db(client, INFLUX_DBNAME) - init_db(client, influxdb_content) + _delete_db(client, INFLUX_DBNAME) + _init_db(client, influxdb_content) yield client - delete_db(client, INFLUX_DBNAME) + _delete_db(client, INFLUX_DBNAME) -def init_db(client, content): +def _init_db(client, content): + if content != []: client.create_database(INFLUX_DBNAME) client.switch_database(INFLUX_DBNAME) client.write_points(content) - -def delete_db(client, db_name): + +def _delete_db(client, db_name): client.drop_database(db_name) client.close() def get_all_reports(client, db_name): + """ + get all points stored in the database during test execution + """ client.switch_database(db_name) result = client.query('SELECT * FROM "power_consumption"') return list(result.get_points()) diff --git a/powerapi/test_utils/db/mongo.py b/powerapi/test_utils/db/mongo.py index ab35f4b1..e292b2df 100644 --- a/powerapi/test_utils/db/mongo.py +++ b/powerapi/test_utils/db/mongo.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -26,8 +26,6 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import datetime - import pytest import pymongo @@ -41,27 +39,30 @@ @pytest.fixture def mongo_database(mongodb_content): """ - mongo database with 10 hwpc-report + connect to a local mongo database (localhost:27017) and store data contained in the list influxdb_content + after test end, delete the data """ - gen_base_db_test(MONGO_URI, mongodb_content) + _gen_base_db_test(MONGO_URI, mongodb_content) yield None - clean_base_db_test(MONGO_URI) + _clean_base_db_test(MONGO_URI) -def gen_base_db_test(uri, content): +def _gen_base_db_test(uri, content): mongo = pymongo.MongoClient(uri) db = mongo[MONGO_DATABASE_NAME] + # delete collection if it already exist db[MONGO_INPUT_COLLECTION_NAME].drop() db.create_collection(MONGO_INPUT_COLLECTION_NAME) for item in content: db[MONGO_INPUT_COLLECTION_NAME].insert_one(item) + # delete output collection db[MONGO_OUTPUT_COLLECTION_NAME].drop() mongo.close() -def clean_base_db_test(uri): +def _clean_base_db_test(uri): """ drop test_hwrep and test_result collections """ diff --git a/powerapi/test_utils/db/socket.py b/powerapi/test_utils/db/socket.py index bac3cefb..e85dca4a 100644 --- a/powerapi/test_utils/db/socket.py +++ b/powerapi/test_utils/db/socket.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -51,6 +51,7 @@ def run(self): self.socket.send(bytes(json.dumps(msg), 'utf-8')) self.socket.close() + class ClientThreadDelay(Thread): """ Thread that open a connection to a socket and send it a list of reports diff --git a/powerapi/test_utils/dummy_actor.py b/powerapi/test_utils/dummy_actor.py index e1956699..1c5c579e 100644 --- a/powerapi/test_utils/dummy_actor.py +++ b/powerapi/test_utils/dummy_actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -30,16 +30,24 @@ import pytest -from thespian.actors import Actor, ActorSystem, ActorExitRequest +from thespian.actors import Actor, ActorExitRequest -from powerapi.message import PingMessage, StartMessage, OKMessage, ErrorMessage +from powerapi.message import StartMessage, OKMessage, ErrorMessage from powerapi.actor import Actor as PowerapiActor, InitializationException from powerapi.formula import DomainValues -LOGGER_NAME='thespian_test_logger' +LOGGER_NAME = 'thespian_test_logger' + @pytest.fixture def logger(system, dummy_pipe_in): + """ + fixture that return a DummyActor + + A DummyActor is an actor that send every received message to the pytest process through a pipe + This type of actor is usefull to unit test actor that interact with other actors. + It may tests if the tested actor send the correct message to the actor it must interact with + """ logger_actor = system.createActor(DummyActor, globalName=LOGGER_NAME) system.tell(logger_actor, DummyStartMessage('system', 'logger', dummy_pipe_in)) yield logger_actor @@ -47,6 +55,10 @@ def logger(system, dummy_pipe_in): class DummyStartMessage(StartMessage): + """ + Message used to start a DummyActor + :param pipe: pipe used to send message to pytest process + """ def __init__(self, sender_name, name, pipe): StartMessage.__init__(self, sender_name, name) self.pipe = pipe @@ -59,9 +71,12 @@ class DummyActor(Actor): def __init__(self): Actor.__init__(self) self.pipe = None - + self.name = None def receiveMessage(self, message, sender): + """ + when receive a message, send it to the pytest process through a pipe + """ if isinstance(message, DummyStartMessage): self.pipe = message.pipe self.name = message.name @@ -72,13 +87,20 @@ def receiveMessage(self, message, sender): class DummyFormulaActor(Actor): """ - Formula that forward received message to fake pusher + A fake FormulaActor that is connected to a DummyActor (a fake pusher) """ def __init__(self): + Actor.__init__(self) self.name = None self.fake_puller = None def receiveMessage(self, message, sender): + """ + When receiving a message : + if its a Start message containing initialization values : initailize the DummyFormula + if its an ActorExitRequest : notify the pusher that the Dummyformula die + if its an other type of message : forward it to the fake pusher + """ logging.debug('receive : ' + str(message), extra={'actor_name': self.name}) if isinstance(message, StartMessage): self.name = message.name @@ -96,7 +118,9 @@ def gen_domain_values(device_id, formula_id): class CrashException(Exception): - pass + """ + Exception raised by formla to make it crash + """ class CrashFormulaActor(DummyFormulaActor): @@ -107,8 +131,6 @@ def __init__(self): DummyFormulaActor.__init__(self) self.report_received = 0 - - def receiveMessage(self, message, sender): logging.debug('receive : ' + str(message), extra={'actor_name': self.name}) if isinstance(message, StartMessage): @@ -128,7 +150,7 @@ def receiveMessage(self, message, sender): class CrashInitFormulaActor(DummyFormulaActor): """ - Formula that at initialization end answer ErrorMessage to StartMessage + Formula answer ErrorMessage to StartMessage Like DummyFormulaActor, it will forward received Message to fake pusher """ def __init__(self): @@ -148,7 +170,7 @@ def receiveMessage(self, message, sender): class DummyPowerapiActor(PowerapiActor): """ - Actor that have the same thant a basic powerapi actor + Actor that have the same API than a basic powerapi actor """ def __init__(self): @@ -157,7 +179,7 @@ def __init__(self): class CrashInitActor(DummyPowerapiActor): """ - Basic powerapi actor that crash a initialisation + Basic powerapi actor that crash at initialisation """ def _initialization(self, msg): raise InitializationException('error') @@ -165,10 +187,13 @@ def _initialization(self, msg): class CrashActor(DummyPowerapiActor): """ - Basic powerapi actor that crash after 2s + Basic powerapi actor that crash 2s after initialization """ - def _initialization(self, msg): + def _initialization(self, _): self.wakeupAfter(2) def receiveMsg_WakeupMessage(self, message, sender): + """ + crash after being waked up by system, 2s after initialization + """ raise CrashException() diff --git a/powerapi/test_utils/libvirt.py b/powerapi/test_utils/libvirt.py index 6e1f65fc..c1e4f806 100644 --- a/powerapi/test_utils/libvirt.py +++ b/powerapi/test_utils/libvirt.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -26,8 +26,6 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import pytest - try: from libvirt import libvirtError except ImportError: @@ -45,15 +43,27 @@ class MockedDomain: + """ + Mocked libvirt domain that contain only uuid string + """ def __init__(self, uuid_str): self.uuid_str = uuid_str def UUIDString(self): + """ + mocked UUIDString method + """ return self.uuid_str class MockedLibvirt: + """ + Mocked libvirt client + """ def lookupByName(self, domain_name): + """ + :return: MockedDomain with UUID_1 + """ if domain_name == DOMAIN_NAME_1: return MockedDomain(UUID_1) raise libvirtError('') diff --git a/powerapi/test_utils/report/hwpc.py b/powerapi/test_utils/report/hwpc.py index e490bc24..5c36dfe3 100644 --- a/powerapi/test_utils/report/hwpc.py +++ b/powerapi/test_utils/report/hwpc.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -29,10 +29,11 @@ import json from typing import Dict, List -from powerapi.report import HWPCReport, create_socket_report, create_report_root, create_group_report, create_core_report +from powerapi.report import HWPCReport import powerapi.test_utils.report as parent_module from powerapi.test_utils.libvirt import LIBVIRT_TARGET_NAME1, LIBVIRT_TARGET_NAME2 + ################### # Report Creation # ################### @@ -48,10 +49,11 @@ def extract_rapl_reports_with_2_sockets(number_of_reports: int) -> List[Dict]: json_file.close() return reports['reports'][:number_of_reports] + def extract_all_events_reports_with_2_sockets(number_of_reports: int) -> List[Dict]: """ Extract the number_of_reports first reports of the file hwpc_rapl_2_socket.json - This file contain hwpc reports , recorded on a two socket host, with events : + This file contain hwpc reports , recorded on a two socket host, with events : - RAPL_PKG - MPERF - APERF @@ -68,11 +70,12 @@ def extract_all_events_reports_with_2_sockets(number_of_reports: int) -> List[Di json_file.close() return reports['reports'][:number_of_reports] + def extract_all_events_reports_with_vm_name(number_of_reports: int) -> List[Dict]: """ Extract the number_of_reports first reports of the file hwpc_all_vm_target.json - This file contain hwpc reports , recorded on a two socket host, with events : + This file contain hwpc reports , recorded on a two socket host, with events : - RAPL_PKG - MPERF - APERF @@ -90,7 +93,8 @@ def extract_all_events_reports_with_vm_name(number_of_reports: int) -> List[Dict json_file = open(path + '/hwpc_all_vm_target.json', 'r') reports = json.load(json_file) json_file.close() - return list(filter(lambda r: r['target'] == LIBVIRT_TARGET_NAME1 or r['target'] == LIBVIRT_TARGET_NAME2, reports['reports']))[:number_of_reports] + return list(filter(lambda r: r['target'] == LIBVIRT_TARGET_NAME1 or r['target'] == LIBVIRT_TARGET_NAME2, reports['reports']))[:number_of_reports] + def gen_HWPCReports(number_of_reports: int) -> List[HWPCReport]: """ diff --git a/powerapi/test_utils/report/power.py b/powerapi/test_utils/report/power.py index e8f8c084..96f40b93 100644 --- a/powerapi/test_utils/report/power.py +++ b/powerapi/test_utils/report/power.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -35,8 +35,13 @@ POWER_REPORT_1 = PowerReport(0, SENSOR_NAME, TARGET_NAME, 1234, {'socket': 0, 'metadata1': 'truc', 'metadata2': 'oui'}) + def gen_json_power_report(number_of_reports): - """ generate number_of_reports power report with json format + """ + generate number_of_reports power report with json format + each power report have the same sensor, target and power value (100W) + only the timestamp is different. + timestamp is generated from 01/01/1970 0:00.0 for the first report and is incremented by 1s for each returned report """ reports = [] for ts in range(number_of_reports): diff --git a/powerapi/utils/__init__.py b/powerapi/utils/__init__.py index 36597305..8c5f2dd1 100644 --- a/powerapi/utils/__init__.py +++ b/powerapi/utils/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from powerapi.utils.utils import * +from powerapi.utils.utils import timestamp_to_datetime, datetime_to_timestamp, dict_merge from powerapi.utils.tree import Tree from powerapi.utils.stat_buffer import StatBuffer from .json_stream import JsonStream diff --git a/powerapi/utils/json_stream.py b/powerapi/utils/json_stream.py index 3fce8682..d3d48bf8 100644 --- a/powerapi/utils/json_stream.py +++ b/powerapi/utils/json_stream.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,13 +26,9 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import asyncio - - DEFAULT_BUFFER_SIZE = 4096 - class JsonStream: """read data received from a input utf-8 byte stream socket as a json stream diff --git a/powerapi/utils/stat_buffer.py b/powerapi/utils/stat_buffer.py index 0e5bfd12..f07292de 100644 --- a/powerapi/utils/stat_buffer.py +++ b/powerapi/utils/stat_buffer.py @@ -30,6 +30,15 @@ from typing import Dict, List, Tuple import numpy as np + +def _compute_stats(values: List[float]) -> Tuple[float, float, float, float]: + """ + compute mean, std, min, max from a list of float + """ + np_values = np.array([value['value'] for value in values]) + return np_values.mean(), np_values.std(), np_values.min(), np_values.max() + + class StatBuffer: """ Buffer that store timeseries values and compute statistics on it @@ -73,13 +82,6 @@ def is_available(self, key: str) -> bool: return (last_measure['time'] - first_measure['time']) >= self.aggregation_periode - def _compute_stats(self, values: List[float]) -> Tuple[float, float, float, float]: - """ - :return: mean, std, min, max - """ - np_values = np.array([value['value'] for value in values]) - return np_values.mean(), np_values.std(), np_values.min(), np_values.max() - def _split_values(self, values: List[Dict]): time_of_first_measure = values[0]['time'] @@ -116,7 +118,7 @@ def get_stats(self, key: str) -> Dict: values, self.buffer[key] = self._split_values(self.buffer[key]) - mean, std, min, max = self._compute_stats(values) + mean, std, min, max = _compute_stats(values) return { 'mean': mean, diff --git a/powerapi/utils/tree.py b/powerapi/utils/tree.py index 98f149e8..27926179 100644 --- a/powerapi/utils/tree.py +++ b/powerapi/utils/tree.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -52,7 +52,6 @@ def add(self, path, value): if len(path) == 0: raise ValueError() - if len(path) == 1: self.root = Node(path[0], value) return diff --git a/powerapi/utils/utils.py b/powerapi/utils/utils.py index cbdfc70e..d0bad20b 100644 --- a/powerapi/utils/utils.py +++ b/powerapi/utils/utils.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +30,7 @@ import collections.abc as collections import datetime + def timestamp_to_datetime(timestamp): """ Create datetime from a timestamp value @@ -37,7 +38,7 @@ def timestamp_to_datetime(timestamp): :param int timestamp: :rtype: datetime.datetime """ - return datetime.datetime.fromtimestamp(timestamp/1000) + return datetime.datetime.fromtimestamp(timestamp / 1000) def datetime_to_timestamp(date): @@ -47,7 +48,7 @@ def datetime_to_timestamp(date): :param datetime.datetime date: :rtype: int """ - return int(datetime.datetime.timestamp(date)*1000) + return int(datetime.datetime.timestamp(date) * 1000) def dict_merge(dict1, dict2): diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index c6129c0e..00000000 --- a/tests/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Copyright (c) 2018, INRIA -Copyright (c) 2018, University of Lille -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" \ No newline at end of file diff --git a/tests/acceptation/crash/test_crash_formula_medium_error.py b/tests/acceptation/crash/test_crash_formula_medium_error.py index 2abf01e1..599057cf 100644 --- a/tests/acceptation/crash/test_crash_formula_medium_error.py +++ b/tests/acceptation/crash/test_crash_formula_medium_error.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/acceptation/crash/test_crash_formula_minor_error.py b/tests/acceptation/crash/test_crash_formula_minor_error.py index 9f0f6694..9c8c2821 100644 --- a/tests/acceptation/crash/test_crash_formula_minor_error.py +++ b/tests/acceptation/crash/test_crash_formula_minor_error.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/acceptation/test_simple_architecture.py b/tests/acceptation/test_simple_architecture.py index bdb70b18..4c526d41 100644 --- a/tests/acceptation/test_simple_architecture.py +++ b/tests/acceptation/test_simple_architecture.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/acceptation/test_simple_architecture_with_libvirt_mapper.py b/tests/acceptation/test_simple_architecture_with_libvirt_mapper.py index e4cb7f51..6e868502 100644 --- a/tests/acceptation/test_simple_architecture_with_libvirt_mapper.py +++ b/tests/acceptation/test_simple_architecture_with_libvirt_mapper.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/acceptation/test_stop_architecture_with_sigterm_signal_must_stop_all_actor.py b/tests/acceptation/test_stop_architecture_with_sigterm_signal_must_stop_all_actor.py index ec58f150..1f28fdb3 100644 --- a/tests/acceptation/test_stop_architecture_with_sigterm_signal_must_stop_all_actor.py +++ b/tests/acceptation/test_stop_architecture_with_sigterm_signal_must_stop_all_actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/cli/test_generate_pusher.py b/tests/integration/cli/test_generate_pusher.py index 41e67fe6..f2d26c83 100644 --- a/tests/integration/cli/test_generate_pusher.py +++ b/tests/integration/cli/test_generate_pusher.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/database/test_csvdb.py b/tests/integration/database/test_csvdb.py index f08d7bbd..f824134d 100644 --- a/tests/integration/database/test_csvdb.py +++ b/tests/integration/database/test_csvdb.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -33,8 +33,8 @@ import os import csv -from powerapi.report import create_core_report, create_group_report, create_report_root,\ - create_socket_report +# from powerapi.report import create_core_report, create_group_report, create_report_root,\ +# create_socket_report from powerapi.report import PowerReport, HWPCReport from powerapi.database import CsvDB from powerapi.database import CsvBadFilePathError, CsvBadCommonKeysError, HeaderAreNotTheSameError @@ -91,28 +91,28 @@ ################### -def gen_hwpc_report(): - """ - Return a well formated HWPCReport - """ - cpua0 = create_core_report('1', 'e0', '0') - cpub0 = create_core_report('2', 'e0', '1') - cpuc0 = create_core_report('3', 'e0', '2') - cpud0 = create_core_report('4', 'e0', '3') - cpua1 = create_core_report('1', 'e1', '0') - cpub1 = create_core_report('2', 'e1', '1') - cpuc1 = create_core_report('3', 'e1', '2') - cpud1 = create_core_report('4', 'e1', '3') - - socketa0 = create_socket_report('1', [cpua0, cpub0]) - socketb0 = create_socket_report('2', [cpuc0, cpud0]) - socketa1 = create_socket_report('1', [cpua1, cpub1]) - socketb1 = create_socket_report('2', [cpuc1, cpud1]) - - groupa = create_group_report('group1', [socketa0, socketb0]) - groupb = create_group_report('group2', [socketa1, socketb1]) - - return create_report_root([groupa, groupb]) +# def gen_hwpc_report(): +# """ +# Return a well formated HWPCReport +# """ +# cpua0 = create_core_report('1', 'e0', '0') +# cpub0 = create_core_report('2', 'e0', '1') +# cpuc0 = create_core_report('3', 'e0', '2') +# cpud0 = create_core_report('4', 'e0', '3') +# cpua1 = create_core_report('1', 'e1', '0') +# cpub1 = create_core_report('2', 'e1', '1') +# cpuc1 = create_core_report('3', 'e1', '2') +# cpud1 = create_core_report('4', 'e1', '3') + +# socketa0 = create_socket_report('1', [cpua0, cpub0]) +# socketb0 = create_socket_report('2', [cpuc0, cpud0]) +# socketa1 = create_socket_report('1', [cpua1, cpub1]) +# socketb1 = create_socket_report('2', [cpuc1, cpud1]) + +# groupa = create_group_report('group1', [socketa0, socketb0]) +# groupb = create_group_report('group2', [socketa1, socketb1]) + +# return create_report_root([groupa, groupb]) def gen_power_report(): diff --git a/tests/integration/database/test_influxdb.py b/tests/integration/database/test_influxdb.py index eaa910d4..8b20b165 100644 --- a/tests/integration/database/test_influxdb.py +++ b/tests/integration/database/test_influxdb.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/database/test_mongodb.py b/tests/integration/database/test_mongodb.py index 66db35fd..1f444a11 100644 --- a/tests/integration/database/test_mongodb.py +++ b/tests/integration/database/test_mongodb.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/database/test_socket_db.py b/tests/integration/database/test_socket_db.py index 44fbfd6b..4ac03892 100644 --- a/tests/integration/database/test_socket_db.py +++ b/tests/integration/database/test_socket_db.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/test_dispatcher.py b/tests/integration/test_dispatcher.py index 431a494d..81ecb531 100644 --- a/tests/integration/test_dispatcher.py +++ b/tests/integration/test_dispatcher.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/pusher/test_integration_pusher.py b/tests/integration/test_pusher.py similarity index 98% rename from tests/integration/pusher/test_integration_pusher.py rename to tests/integration/test_pusher.py index e1d68fc1..9b5c638f 100644 --- a/tests/integration/pusher/test_integration_pusher.py +++ b/tests/integration/test_pusher.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/integration/test_supervisor.py b/tests/integration/test_supervisor.py index 65386d3a..721ac560 100644 --- a/tests/integration/test_supervisor.py +++ b/tests/integration/test_supervisor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/cli/test_parser.py b/tests/unit/cli/test_parser.py index 2beca6b1..7e1f082e 100644 --- a/tests/unit/cli/test_parser.py +++ b/tests/unit/cli/test_parser.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/cli/test_tools.py b/tests/unit/cli/test_tools.py index 132a2473..b5e38d18 100644 --- a/tests/unit/cli/test_tools.py +++ b/tests/unit/cli/test_tools.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/dispatcher_rule/test_hwpc_dispatch_rule.py b/tests/unit/dispatch_rule/test_hwpc_dispatch_rule.py similarity index 87% rename from tests/unit/dispatcher_rule/test_hwpc_dispatch_rule.py rename to tests/unit/dispatch_rule/test_hwpc_dispatch_rule.py index a0c8f651..b9f5ede6 100644 --- a/tests/unit/dispatcher_rule/test_hwpc_dispatch_rule.py +++ b/tests/unit/dispatch_rule/test_hwpc_dispatch_rule.py @@ -1,21 +1,21 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# +# # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# +# # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -26,9 +26,10 @@ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# +from datetime import datetime from copy import deepcopy import pytest -from powerapi.report import * +from powerapi.report import HWPCReport from powerapi.dispatch_rule import HWPCDispatchRule, HWPCDepthLevel """ Test HWPCDispatcheRule @@ -44,6 +45,37 @@ """ +def create_core_report(core_id, event_id, event_value, events=None): + id_str = str(core_id) + data = {id_str: {}} + if events is not None: + data[id_str] = events + return data + data[id_str] = {event_id: event_value} + return data + + +def create_socket_report(socket_id, core_list): + id_str = str(socket_id) + data = {id_str: {}} + for core in core_list: + data[id_str].update(core) + return data + + +def create_group_report(group_id, socket_list): + group = {} + for socket in socket_list: + group.update(socket) + return (group_id, group) + + +def create_report_root(group_list, timestamp=datetime.fromtimestamp(0), sensor='toto', target='system'): + sensor = HWPCReport(timestamp=timestamp, sensor=sensor, target=target, groups={}) + for (group_id, group) in group_list: + sensor.groups[group_id] = group + return sensor + CPU_1 = create_core_report('1', 'e0', '0') CPU_2 = create_core_report('2', 'e0', '1') CPU_3 = create_core_report('3', 'e0', '2') diff --git a/tests/unit/dispatcher_rule/test_power_dispatch_rule.py b/tests/unit/dispatch_rule/test_power_dispatch_rule.py similarity index 97% rename from tests/unit/dispatcher_rule/test_power_dispatch_rule.py rename to tests/unit/dispatch_rule/test_power_dispatch_rule.py index 5daf677a..45d5c596 100644 --- a/tests/unit/dispatcher_rule/test_power_dispatch_rule.py +++ b/tests/unit/dispatch_rule/test_power_dispatch_rule.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/dispatcher/test_blocking_detector.py b/tests/unit/dispatcher/test_blocking_detector.py index 2bdfc0a6..ee4fc298 100644 --- a/tests/unit/dispatcher/test_blocking_detector.py +++ b/tests/unit/dispatcher/test_blocking_detector.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/dispatcher/test_dispatcher_actor.py b/tests/unit/dispatcher/test_dispatcher_actor.py index 96ffbb79..014ba2c8 100644 --- a/tests/unit/dispatcher/test_dispatcher_actor.py +++ b/tests/unit/dispatcher/test_dispatcher_actor.py @@ -1,5 +1,6 @@ -# Copyright (c) 2018, INRIA Copyright (c) 2018, University of Lille All rights -# reserved. +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille +# All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: diff --git a/tests/unit/dispatcher_rule/test_hwpc_dispatcher_rule.py b/tests/unit/dispatcher_rule/test_hwpc_dispatcher_rule.py deleted file mode 100644 index 72c6911a..00000000 --- a/tests/unit/dispatcher_rule/test_hwpc_dispatcher_rule.py +++ /dev/null @@ -1,228 +0,0 @@ -""" -Copyright (c) 2018, INRIA -Copyright (c) 2018, University of Lille -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - -import pytest -from powerapi.report import * -from powerapi.dispatch_rule import HWPCDispatchRule, HWPCDepthLevel - - -""" -Test HWPCDispatcheRule - -When testing on HWPC report, we test to get formula id for this reports - -report_1 : one group, one socket, one CPU -report_2 : one group, two socket, one CPU per socket -report_3 : one group, two socket, two CPU per socket - -each report could be associated with a RAPL group that contain one socket and -one CPU - -""" - -CPU_1 = create_core_report('1', 'e0', '0') -CPU_2 = create_core_report('2', 'e0', '1') -CPU_3 = create_core_report('3', 'e0', '2') -CPU_4 = create_core_report('4', 'e0', '3') - -SOCKET_1 = create_socket_report('1', [CPU_1]) -SOCKET_2 = create_socket_report('1', [CPU_1, CPU_2]) -SOCKET_3 = create_socket_report('2', [CPU_3, CPU_4]) - -GROUP_1 = create_group_report('1', [SOCKET_1]) -GROUP_2 = create_group_report('1', [SOCKET_2]) -GROUP_3 = create_group_report('1', [SOCKET_2, SOCKET_3]) -RAPL = create_group_report('RAPL', [SOCKET_1]) - -REPORT_1 = create_report_root([GROUP_1]) -REPORT_2 = create_report_root([GROUP_2]) -REPORT_3 = create_report_root([GROUP_3]) - -REPORT_1_RAPL = create_report_root([GROUP_1, RAPL]) -REPORT_2_RAPL = create_report_root([GROUP_2, RAPL]) -REPORT_3_RAPL = create_report_root([GROUP_3, RAPL]) - - -############ -# Fixtures # -############ -@pytest.fixture(params=[REPORT_1, REPORT_2, REPORT_3, REPORT_1_RAPL, - REPORT_2_RAPL, REPORT_3_RAPL]) -def report(request): - return request.param - - -@pytest.fixture(params=[REPORT_1, REPORT_1_RAPL]) -def report_1(request): - return request.param - - -@pytest.fixture(params=[REPORT_2, REPORT_2_RAPL]) -def report_2(request): - return request.param - - -@pytest.fixture(params=[REPORT_3, REPORT_3_RAPL]) -def report_3(request): - return request.param - - -######### -# UTILS # -######### -def validate_formula_id(formula_id_list, validation_list): - """ - assert if every element in formula_id_list are in validation list and - vice versa - - validation_list must be sorted - """ - assert len(formula_id_list) == len(validation_list) - formula_id_list.sort() - - for a, b in zip(formula_id_list, validation_list): - assert a == b - - -######################### -# TEST REPORT STRUCTURE # -######################### - -def test_init_fields_name_test(): - """ - test if the field's names of the dispatch_rule identifier tuple are - correctly initialized - """ - assert HWPCDispatchRule(HWPCDepthLevel.TARGET).fields == ['target'] - assert HWPCDispatchRule(HWPCDepthLevel.ROOT).fields == ['sensor'] - assert HWPCDispatchRule(HWPCDepthLevel.SOCKET).fields == ['sensor', - 'socket'] - assert HWPCDispatchRule(HWPCDepthLevel.CORE).fields == ['sensor', 'socket', - 'core'] - -#################################### -# TEST DISPATCH BY ROOT AND TARGET # -#################################### - - -def test_get_formula_id_sensor_rule(report): - """ - get formula id from reports with a rule that dispatch by sensor : - - the method must return this list : - [('toto',)] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.ROOT).get_formula_id(report) - validate_formula_id(ids, [('toto',)]) - - -def test_get_formula_id_target_rule(report): - """ - get formula id from reports with a rule that dispatch by target : - - the method must return this list : - [('system',)] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.TARGET).get_formula_id(report) - validate_formula_id(ids, [('system',)]) - - -########################### -# TEST DISPATCH BY SOCKET # -########################### -def test_get_formula_id_socket_rule_report_1(report_1): - """ - get formula id from report1 with a rule that dispatch by socket : - - the method must return this list : - [('toto','1')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.SOCKET).get_formula_id(report_1) - validate_formula_id(ids, [('toto', '1')]) - - -def test_get_formula_id_socket_rule_report_2(report_2): - """ - get formula id from report2 with a rule that dispatch by socket : - - the method must return this list : - [('toto','1'), ('toto','2')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.SOCKET).get_formula_id(report_2) - validate_formula_id(ids, [('toto', '1')]) - - -def test_get_formula_id_socket_rule_report_3(report_3): - """ - get formula id from report3 with a rule that dispatch by socket : - - the method must return this list : - [('toto','1'), ('toto','2')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.SOCKET).get_formula_id(report_3) - validate_formula_id(ids, [('toto', '1'), ('toto', '2')]) - - -######################### -# TEST DISPATCH BY CORE # -######################### -def test_get_formula_id_cpu_rule_report_1(report_1): - """ - get formula id from report1 with a rule that dispatch by cpu : - - the method must return this list : - [('toto','1', '1')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.CORE).get_formula_id(report_1) - validate_formula_id(ids, [('toto', '1', '1')]) - - -def test_get_formula_id_cpu_rule_report_2(report_2): - """ - get formula id from report2 with a rule that dispatch by cpu : - - the method must return this list : - [('toto','1', '1'), ('toto','2', '2')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.CORE).get_formula_id(report_2) - validate_formula_id(ids, [('toto', '1', '1'), ('toto', '1', '2')]) - - -def test_get_formula_id_cpu_rule_report_3(report_3): - """ - get formula id from report3 with a rule that dispatch by cpu : - - the method must return this list : - [('toto','1', '1'), ('toto','1', '2'), ('toto','2', '3'), ('toto','2', '3')] - """ - ids = HWPCDispatchRule(HWPCDepthLevel.CORE).get_formula_id(report_3) - validate_formula_id(ids, [('toto', '1', '1'), ('toto', '1', '2'), - ('toto', '2', '3'), ('toto', '2', '4')]) diff --git a/tests/unit/report/test_hwpc_report.py b/tests/unit/report/test_hwpc_report.py index b117849c..9ff1cd9a 100644 --- a/tests/unit/report/test_hwpc_report.py +++ b/tests/unit/report/test_hwpc_report.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/report_modifier/test_libvirt_mapper.py b/tests/unit/report_modifier/test_libvirt_mapper.py index 5ef72564..5838bc40 100644 --- a/tests/unit/report_modifier/test_libvirt_mapper.py +++ b/tests/unit/report_modifier/test_libvirt_mapper.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/test_dummy_formula_actor.py b/tests/unit/test_dummy_formula_actor.py index a5ea2b64..b272602f 100644 --- a/tests/unit/test_dummy_formula_actor.py +++ b/tests/unit/test_dummy_formula_actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -60,6 +60,6 @@ def test_send_Report_to_dummy_formula_make_formula_send_power_report_to_logger_w report1 = Report(1, 2, 3) system.tell(started_actor, report1) - _, msg = dummy_pipe_out.recv() + _, msg = recv_from_pipe(dummy_pipe_out, 2) assert isinstance(msg, PowerReport) assert msg.power == 42 diff --git a/tests/unit/test_puller_actor.py b/tests/unit/test_puller_actor.py index 76ba64b6..116e5f67 100644 --- a/tests/unit/test_puller_actor.py +++ b/tests/unit/test_puller_actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -125,7 +125,7 @@ def test_create_puller_with_router_without_rules_must_raise_RouterWithoutRuleExc def test_start_actor_with_db_that_contains_2_report_make_actor_send_reports_to_dispatcher(self, system, started_actor, fake_dispatcher, content, dummy_pipe_out): for report in content: - assert dummy_pipe_out.recv() == ('dispatcher', report) + assert recv_from_pipe(dummy_pipe_out, 2) == ('dispatcher', report) def test_starting_actor_in_non_stream_mode_make_it_terminate_itself_after_empty_db(self, system, started_actor): time.sleep(1) diff --git a/tests/unit/test_pusher_actor.py b/tests/unit/test_pusher_actor.py index 0fb3ec46..a7de51fc 100644 --- a/tests/unit/test_pusher_actor.py +++ b/tests/unit/test_pusher_actor.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # Redistribution and use in source and binary forms, with or without @@ -33,7 +33,7 @@ from powerapi.report import Report from powerapi.pusher import PusherActor from powerapi.message import PusherStartMessage, ErrorMessage, EndMessage -from powerapi.test_utils.abstract_test import AbstractTestActorWithDB +from powerapi.test_utils.abstract_test import AbstractTestActorWithDB, recv_from_pipe from powerapi.test_utils.report.power import POWER_REPORT_1 from powerapi.test_utils.actor import system @@ -64,7 +64,7 @@ def test_starting_actor_with_db_that_crash_when_connected_must_answer_error_mess def test_send_one_power_report_to_pusher_make_it_save_to_database(self, system, started_actor, pipe_out): system.tell(started_actor, POWER_REPORT_1) - assert pipe_out.recv() == POWER_REPORT_1 + assert recv_from_pipe(pipe_out, 0.5) == POWER_REPORT_1 def test_send_EndMessage_to_started_pusher_make_it_forward_to_supervisor(self, system, started_actor, pipe_out): system.tell(started_actor, EndMessage('system')) diff --git a/tests/unit/utils/test_JsonStream.py b/tests/unit/utils/test_JsonStream.py index 7a64c9e9..4dfaa7d0 100644 --- a/tests/unit/utils/test_JsonStream.py +++ b/tests/unit/utils/test_JsonStream.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/utils/test_stat_buffer.py b/tests/unit/utils/test_stat_buffer.py index 53a5a6c5..b2233ba3 100644 --- a/tests/unit/utils/test_stat_buffer.py +++ b/tests/unit/utils/test_stat_buffer.py @@ -1,5 +1,5 @@ -# Copyright (c) 2018, INRIA -# Copyright (c) 2018, University of Lille +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/tests/unit/utils/test_tree.py b/tests/unit/utils/test_tree.py index edb50f10..6af9a17d 100644 --- a/tests/unit/utils/test_tree.py +++ b/tests/unit/utils/test_tree.py @@ -1,34 +1,31 @@ -""" -Copyright (c) 2018, INRIA -Copyright (c) 2018, University of Lille -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - +# Copyright (c) 2021, INRIA +# Copyright (c) 2021, University of Lille +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import pytest from copy import deepcopy from powerapi.utils.tree import Node, Tree