From bf7c72ccbae44723644f11c964a4cd11fc66a434 Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Thu, 2 Jan 2025 02:54:19 +0100 Subject: [PATCH] test-api: add a check for each stat parsing Signed-off-by: Kamil Gierszewski --- test/functional/api/cas/statistics.py | 168 ++++++++++++++------------ 1 file changed, 93 insertions(+), 75 deletions(-) diff --git a/test/functional/api/cas/statistics.py b/test/functional/api/cas/statistics.py index 82eae31..3041a3e 100644 --- a/test/functional/api/cas/statistics.py +++ b/test/functional/api/cas/statistics.py @@ -11,6 +11,7 @@ from enum import Enum from typing import List from api.cas import casadm from api.cas.casadm_params import StatsFilter +from connection.utils.output import CmdException from type_def.size import Size, Unit @@ -58,6 +59,9 @@ class CacheStats: case StatsFilter.err: self.error_stats = ErrorStats(stats_dict, percentage_val) + if stats_dict: + raise CmdException(f"Unknown stat(s) left after parsing output cmd\n{stats_dict}") + def __str__(self): # stats_list contains all Class.__str__ methods initialized in CacheStats stats_list = [str(getattr(self, stats_item)) for stats_item in self.__dict__] @@ -72,13 +76,6 @@ class CacheStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.usage_stats -= other.usage_stats - self.request_stats -= other.request_stats - self.block_stats -= other.block_stats - self.error_stats -= other.error_stats - return self - class CoreStats: def __init__( @@ -103,12 +100,8 @@ class CoreStats: case StatsFilter.err: self.error_stats = ErrorStats(stats_dict, percentage_val) - def __sub__(self, other): - self.usage_stats -= other.usage_stats - self.request_stats -= other.request_stats - self.block_stats -= other.block_stats - self.error_stats -= other.error_stats - return self + if stats_dict: + raise CmdException(f"Unknown stat(s) left after parsing output cmd\n{stats_dict}") def __str__(self): # stats_list contains all Class.__str__ methods initialized in CacheStats @@ -149,6 +142,9 @@ class CoreIoClassStats: case StatsFilter.blk: self.block_stats = BlockStats(stats_dict, percentage_val) + if stats_dict: + raise CmdException(f"Unknown stat(s) left after parsing output cmd\n{stats_dict}") + def __eq__(self, other): # check if all initialized variable in self(CacheStats) match other(CacheStats) return [getattr(self, stats_item) for stats_item in self.__dict__] == [ @@ -163,11 +159,6 @@ class CoreIoClassStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.usage_stats -= other.usage_stats - self.request_stats -= other.request_stats - self.block_stats -= other.block_stats - class CacheIoClassStats(CoreIoClassStats): def __init__( @@ -211,6 +202,22 @@ class CacheConfigStats: self.dirty_for = parse_value(value=stats_dict["Dirty for [s]"], unit_type=UnitType.seconds) self.status = stats_dict["Status"] + del stats_dict["Cache Id"] + del stats_dict["Cache Size [4KiB Blocks]"] + del stats_dict["Cache Size [GiB]"] + del stats_dict["Cache Device"] + del stats_dict["Exported Object"] + del stats_dict["Core Devices"] + del stats_dict["Inactive Core Devices"] + del stats_dict["Write Policy"] + del stats_dict["Cleaning Policy"] + del stats_dict["Promotion Policy"] + del stats_dict["Cache line size [KiB]"] + del stats_dict[footprint_key] + del stats_dict["Dirty for [s]"] + del stats_dict["Dirty for"] + del stats_dict["Status"] + def __str__(self): return ( f"Config stats:\n" @@ -254,7 +261,7 @@ class CacheConfigStats: class CoreConfigStats: def __init__(self, stats_dict): - self.core_id = stats_dict["Core Id"] + self.core_id = int(stats_dict["Core Id"]) self.core_dev = stats_dict["Core Device"] self.exp_obj = stats_dict["Exported Object"] self.core_size = parse_value( @@ -267,6 +274,17 @@ class CoreConfigStats: ) self.seq_cutoff_policy = stats_dict["Seq cutoff policy"] + del stats_dict["Core Id"] + del stats_dict["Core Device"] + del stats_dict["Exported Object"] + del stats_dict["Core Size [4KiB Blocks]"] + del stats_dict["Core Size [GiB]"] + del stats_dict["Dirty for [s]"] + del stats_dict["Dirty for"] + del stats_dict["Status"] + del stats_dict["Seq cutoff threshold [KiB]"] + del stats_dict["Seq cutoff policy"] + def __str__(self): return ( f"Config stats:\n" @@ -305,6 +323,11 @@ class IoClassConfigStats: self.eviction_priority = stats_dict["Eviction priority"] self.max_size = stats_dict["Max size"] + del stats_dict["IO class ID"] + del stats_dict["IO class name"] + del stats_dict["Eviction priority"] + del stats_dict["Max size"] + def __str__(self): return ( f"Config stats:\n" @@ -348,6 +371,18 @@ class UsageStats: value=stats_dict[f"Inactive Dirty {unit}"], unit_type=unit ) + for unit in [UnitType.percentage, UnitType.block_4k]: + del stats_dict[f"Occupancy {unit}"] + del stats_dict[f"Free {unit}"] + del stats_dict[f"Clean {unit}"] + del stats_dict[f"Dirty {unit}"] + if f"Inactive Dirty {unit}" in stats_dict: + del stats_dict[f"Inactive Occupancy {unit}"] + if f"Inactive Clean {unit}" in stats_dict: + del stats_dict[f"Inactive Clean {unit}"] + if f"Inactive Dirty {unit}" in stats_dict: + del stats_dict[f"Inactive Dirty {unit}"] + def __str__(self): return ( f"Usage stats:\n" @@ -376,13 +411,6 @@ class UsageStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.occupancy -= other.occupancy - self.free -= other.free - self.clean -= other.clean - self.dirty -= other.dirty - return self - class IoClassUsageStats: def __init__(self, stats_dict, percentage_val): @@ -391,6 +419,11 @@ class IoClassUsageStats: self.clean = parse_value(value=stats_dict[f"Clean {unit}"], unit_type=unit) self.dirty = parse_value(value=stats_dict[f"Dirty {unit}"], unit_type=unit) + for unit in [UnitType.percentage, UnitType.block_4k]: + del stats_dict[f"Occupancy {unit}"] + del stats_dict[f"Clean {unit}"] + del stats_dict[f"Dirty {unit}"] + def __str__(self): return ( f"Usage stats:\n" @@ -417,21 +450,19 @@ class IoClassUsageStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.occupancy -= other.occupancy - self.clean -= other.clean - self.dirty -= other.dirty - return self - class RequestStats: def __init__(self, stats_dict, percentage_val): unit = UnitType.percentage if percentage_val else UnitType.requests self.read = RequestStatsChunk( - stats_dict=stats_dict, percentage_val=percentage_val, operation=OperationType.read + stats_dict=stats_dict, + percentage_val=percentage_val, + operation=OperationType.read, ) self.write = RequestStatsChunk( - stats_dict=stats_dict, percentage_val=percentage_val, operation=OperationType.write + stats_dict=stats_dict, + percentage_val=percentage_val, + operation=OperationType.write, ) self.pass_through_reads = parse_value( value=stats_dict[f"Pass-Through reads {unit}"], unit_type=unit @@ -446,6 +477,17 @@ class RequestStats: value=stats_dict[f"Total requests {unit}"], unit_type=unit ) + for unit in [UnitType.percentage, UnitType.requests]: + for operation in [OperationType.read, OperationType.write]: + del stats_dict[f"{operation} hits {unit}"] + del stats_dict[f"{operation} partial misses {unit}"] + del stats_dict[f"{operation} full misses {unit}"] + del stats_dict[f"{operation} total {unit}"] + del stats_dict[f"Pass-Through reads {unit}"] + del stats_dict[f"Pass-Through writes {unit}"] + del stats_dict[f"Serviced requests {unit}"] + del stats_dict[f"Total requests {unit}"] + def __str__(self): return ( f"Request stats:\n" @@ -472,15 +514,6 @@ class RequestStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.read -= other.read - self.write -= other.write - self.pass_through_reads -= other.pass_through_reads - self.pass_through_writes -= other.pass_through_writes - self.requests_serviced -= other.requests_serviced - self.requests_total -= other.requests_total - return self - class RequestStatsChunk: def __init__(self, stats_dict, percentage_val: bool, operation: OperationType): @@ -515,13 +548,6 @@ class RequestStatsChunk: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.hits -= other.hits - self.part_misses -= other.part_misses - self.full_misses -= other.full_misses - self.total -= other.total - return self - class BlockStats: def __init__(self, stats_dict, percentage_val): @@ -537,6 +563,12 @@ class BlockStats: device="exported object", ) + for unit in [UnitType.percentage, UnitType.block_4k]: + for device in ["core", "cache", "exported object"]: + del stats_dict[f"Reads from {device} {unit}"] + del stats_dict[f"Writes to {device} {unit}"] + del stats_dict[f"Total to/from {device} {unit}"] + def __str__(self): return ( f"Block stats:\n" @@ -555,12 +587,6 @@ class BlockStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.core -= other.core - self.cache -= other.cache - self.exp_obj -= other.exp_obj - return self - class ErrorStats: def __init__(self, stats_dict, percentage_val): @@ -573,6 +599,13 @@ class ErrorStats: ) self.total_errors = parse_value(value=stats_dict[f"Total errors {unit}"], unit_type=unit) + for unit in [UnitType.percentage, UnitType.requests]: + for device in ["Core", "Cache"]: + del stats_dict[f"{device} read errors {unit}"] + del stats_dict[f"{device} write errors {unit}"] + del stats_dict[f"{device} total errors {unit}"] + del stats_dict[f"Total errors {unit}"] + def __str__(self): return ( f"Error stats:\n" @@ -593,12 +626,6 @@ class ErrorStats: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.cache -= other.cache - self.core -= other.core - self.total_errors -= other.total_errors - return self - class BasicStatsChunk: def __init__(self, stats_dict: dict, percentage_val: bool, device: str): @@ -620,12 +647,6 @@ class BasicStatsChunk: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.reads -= other.reads - self.writes -= other.writes - self.total -= other.total - return self - class BasicStatsChunkError: def __init__(self, stats_dict: dict, percentage_val: bool, device: str): @@ -647,12 +668,6 @@ class BasicStatsChunkError: def __iter__(self): return iter([getattr(self, stats_item) for stats_item in self.__dict__]) - def __sub__(self, other): - self.reads -= other.reads - self.writes -= other.writes - self.total -= other.total - return self - def get_stat_value(stat_dict: dict, key: str): idx = key.index("[") @@ -698,7 +713,10 @@ def _get_section_filters(filter: List[StatsFilter], io_class_stats: bool = False def get_stats_dict( - filter: List[StatsFilter], cache_id: int, core_id: int = None, io_class_id: int = None + filter: List[StatsFilter], + cache_id: int, + core_id: int = None, + io_class_id: int = None, ): csv_stats = casadm.print_statistics( cache_id=cache_id,