Skip to content

Commit

Permalink
Major fixes to unit tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
senthurayyappan committed Nov 21, 2024
1 parent ba56f3f commit 8e825ee
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 304 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,4 @@ cython_debug/
#.idea/

*.csv
*.log.*
2 changes: 1 addition & 1 deletion opensourceleg/control/compiled_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(
self.outputs = None

def __del__(self) -> None:
if self.cleanup_func is not None:
if hasattr(self, "cleanup_func") and self.cleanup_func is not None:
self.cleanup_func()

def __repr__(self) -> str:
Expand Down
27 changes: 22 additions & 5 deletions opensourceleg/logging/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ def untrack_variable(self, var_func: Callable[[], Any]) -> None:
def __repr__(self) -> str:
return f"Logger(file_path={self._file_path})"

def set_log_path(self, log_path: str) -> None:
self._log_path = log_path
self._generate_file_paths()

def set_file_name(self, file_name: Union[str, None]) -> None:
self._user_file_name = file_name
self._generate_file_paths()
Expand Down Expand Up @@ -212,24 +216,26 @@ def _generate_file_paths(self) -> None:
self._file_path = file_path + ".log"
self._csv_path = file_path + ".csv"

# Log the generated file paths for debugging
self.debug(f"Generated file paths: log file - {self._file_path}, csv file - {self._csv_path}")

def __enter__(self) -> "Logger":
return self

def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
self.close()

def reset(self) -> None:
self._buffer.clear()
self.close()
self._setup_logging()

self._tracked_vars.clear()
self._var_names.clear()
self._header_written = False

if hasattr(self, "_file_handler"):
self._file_handler.close()
del self._file_handler

# re-initialize the logger

def close(self) -> None:
self.flush_buffer()

Expand Down Expand Up @@ -268,6 +274,16 @@ def file_path(self) -> str:
self._generate_file_paths()
return self._file_path

@property
def csv_path(self) -> str:
if not self._csv_path:
self._generate_file_paths()
return self._csv_path

@property
def log_path(self) -> str:
return self._log_path

@property
def buffer_size(self) -> int:
return self._buffer_size
Expand All @@ -290,6 +306,7 @@ def file_backup_count(self) -> int:


# Initialize a global logger instance to be used throughout the library
SCRIPT_DIR = os.path.dirname(__file__)
LOGGER = Logger()

if __name__ == "__main__":
Expand All @@ -301,7 +318,7 @@ def __init__(self) -> None:
def update(self) -> None:
self.a += 0.2

my_logger = Logger(buffer_size=5000, file_name="test_logger", log_path="./logs")
my_logger = Logger(buffer_size=1, file_name="test_logger", log_path="./logs")
x = 0.0
y = 0.0

Expand Down
2 changes: 0 additions & 2 deletions opensourceleg/robots/osl.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from opensourceleg.logging import LOGGER
from opensourceleg.robots.base import RobotBase, TActuator, TSensor
from opensourceleg.sensors.base import LoadcellBase, SensorBase
from opensourceleg.sensors.imu import LordMicrostrainIMU
from opensourceleg.sensors.loadcell import SRILoadcell


Expand Down Expand Up @@ -94,7 +93,6 @@ def joint_encoder_ankle(self) -> Union[TSensor, SensorBase]:
"knee": DephyLegacyActuator("knee", offline=False, frequency=frequency, gear_ratio=9 * (83 / 18)),
},
sensors={
"imu": LordMicrostrainIMU(frequency=frequency, port="/dev/ttyS0"),
"loadcell": SRILoadcell(calibration_matrix=LOADCELL_MATRIX),
},
)
Expand Down
2 changes: 1 addition & 1 deletion opensourceleg/sensors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def check_sensor_stream(func: Callable) -> Callable:
@wraps(func)
def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
# TODO: This could be a generic type that points to actuator, sensor, etc.
if self.is_streaming:
if not self.is_streaming:
raise SensorNotStreamingException(sensor_name=self.__repr__())
return func(self, *args, **kwargs)

Expand Down
8 changes: 4 additions & 4 deletions opensourceleg/sensors/imu.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
sys.path.append("/usr/share/python3-mscl")
import mscl
except ImportError:
LOGGER.error(
print(
"Failed to import mscl. Please install the MSCL library from Lord Microstrain and append the path"
"to the PYTHONPATH or sys.path. Checkout https://github.com/LORD-MicroStrain/MSCL/tree/master"
"and https://lord-microstrain.github.io/MSCL/Documentation/MSCL%20API%20Documentation/index.html"
Expand All @@ -18,17 +18,17 @@
try:
import adafruit_bno055
except ImportError:
LOGGER.error("Failed to import adafruit_bno055")
print("Failed to import adafruit_bno055")

try:
import board
except ImportError:
LOGGER.error("Failed to import board")
print("Failed to import board")

try:
import busio
except ImportError:
LOGGER.error("Failed to import busio")
print("Failed to import busio")


class LordMicrostrainIMU(IMUBase):
Expand Down
121 changes: 53 additions & 68 deletions tests/test_logging/test_logging_logger.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import csv
import logging
import os
from collections import deque
from unittest.mock import Mock

import pytest

from opensourceleg.logging.logger import LOGGER, Logger, LogLevel

CURR_DIR = os.path.dirname(os.path.realpath(__file__))


# Test LogLevel class
def test_log_level_default():
Expand All @@ -27,45 +30,46 @@ def test_log_level_len():
assert len(LogLevel) == 5


# Test Logger class
@pytest.fixture(scope="function")
def test_logger():
log = Logger()
log = Logger(
log_path=CURR_DIR,
file_name="test_logging",
)
log.reset()
yield log


# check if the fixture is being reset after each test
def test_fixture_reset(test_logger: Logger):
assert not hasattr(test_logger, "_file_handler")


# Test new
def test_logger_new():
logger = Logger()
logger2 = Logger()
assert logger is logger2
logger.reset()
logger2.reset()
def test_logger_new(test_logger: Logger):
new_logger = Logger.__new__(Logger)
assert new_logger is test_logger
new_logger.reset()


# Test init
def test_logger_init_default():
logger = Logger()
def test_logger_init_default(test_logger: Logger):
assert all([
logger._log_path == "./",
isinstance(logger.file_level, LogLevel),
isinstance(logger.stream_level, LogLevel),
logger.file_max_bytes == 0,
logger._file_backup_count == 5,
logger.buffer_size == 1000,
isinstance(test_logger.file_level, LogLevel),
isinstance(test_logger.stream_level, LogLevel),
test_logger.file_max_bytes == 0,
test_logger._file_backup_count == 5,
test_logger.buffer_size == 1000,
])
logger.reset()


def test_logger_init_set():
logger = Logger(buffer_size=10, file_level=LogLevel.CRITICAL)
def test_logger_init_set(test_logger: Logger):
test_logger = Logger(buffer_size=10, file_level=LogLevel.CRITICAL)
assert all([
logger._log_format == "[%(asctime)s] %(levelname)s: %(message)s",
logger._buffer_size == 10,
logger._file_level == LogLevel.CRITICAL,
test_logger._log_format == "[%(asctime)s] %(levelname)s: %(message)s",
test_logger._buffer_size == 10,
test_logger._file_level == LogLevel.CRITICAL,
])
logger.reset()


# Test setup logging
Expand All @@ -85,28 +89,20 @@ def test_setup_logging():


# Test setup file handler
def test_setup_file_handler():
test_logger = Logger(
file_max_bytes=0,
file_backup_count=20,
file_level=LogLevel.WARNING,
log_format="[%(levelname)s]",
)
def test_setup_file_handler(test_logger: Logger):
assert not hasattr(test_logger, "_file_handler")

test_logger._setup_file_handler()

assert all([
test_logger._file_handler.maxBytes == 0,
test_logger._file_handler.backupCount == 20,
test_logger._file_handler.level == LogLevel.WARNING.value,
test_logger._file_handler.mode == "a",
test_logger._file_handler.formatter._fmt == "[%(levelname)s]",
test_logger._file_handler.backupCount == 5,
test_logger._file_handler.level == LogLevel.DEBUG.value,
test_logger._file_handler.mode == "w",
test_logger._file_handler.formatter._fmt == "[%(asctime)s] %(levelname)s: %(message)s",
hasattr(test_logger, "_file_handler"),
])

test_logger.reset()


# Test ensure file handler
def test_ensure_file_handler_called_once(test_logger: Logger):
Expand Down Expand Up @@ -158,17 +154,15 @@ def test_set_file_name_str(test_logger: Logger):
test_logger.set_file_name("test_file")
assert all([
test_logger._user_file_name == "test_file",
test_logger._file_path == "",
test_logger._csv_path == "",
test_logger._file_path == f"{CURR_DIR}/test_file.log",
test_logger._csv_path == f"{CURR_DIR}/test_file.csv",
])


def test_set_file_name_none(test_logger: Logger):
test_logger.set_file_name(None)
assert all([
test_logger._user_file_name is None,
test_logger._file_path == "",
test_logger._csv_path == "",
])


Expand All @@ -183,7 +177,7 @@ def test_set_file_level(test_logger: Logger):

def test_set_file_level_has_attr(test_logger: Logger):
test_logger._setup_file_handler()
assert all([hasattr(test_logger, "_file_handler"), test_logger._file_handler.mode == "a"])
assert all([hasattr(test_logger, "_file_handler"), test_logger._file_handler.mode == "w"])

test_logger.set_file_level(LogLevel.DEBUG)
assert all([
Expand Down Expand Up @@ -216,7 +210,7 @@ def test_set_format(test_logger: Logger):

def test_set_format_has_attr(test_logger: Logger):
test_logger._setup_file_handler()
assert all([hasattr(test_logger, "_file_handler"), test_logger._file_handler.mode == "a"])
assert all([hasattr(test_logger, "_file_handler"), test_logger._file_handler.mode == "w"])

test_logger.set_format("[%(test)s]")
assert test_logger._file_handler.formatter._fmt == "[%(test)s]"
Expand Down Expand Up @@ -278,10 +272,6 @@ def test_func() -> int:

test_logger._ensure_file_handler()

# Clear the file to start since it is being used by other tests
test_logger._file = open(test_logger._csv_path, "w", newline="")
test_logger.close()

test_logger.flush_buffer()
assert len(test_logger._buffer) == 0

Expand Down Expand Up @@ -324,31 +314,25 @@ def test_generate_file_paths_no_input_filename(test_logger: Logger):
def test_generate_file_paths_with_input_filename(test_logger: Logger):
test_logger._user_file_name = "test_file"
test_logger._generate_file_paths()
assert test_logger._csv_path == "./test_file.csv"
assert test_logger._csv_path == f"{test_logger.log_path}/test_file.csv"


# Test enter
def test_enter(test_logger: Logger):
assert isinstance(test_logger.__enter__(), Logger)
assert test_logger.__enter__() is test_logger


# Test exit
def test_exit(test_logger: Logger):
test_logger.track_variable(lambda: 2, "first")
test_logger.update()

original_flush = test_logger.flush_buffer
original_close = test_logger.close
test_logger.flush_buffer = Mock()
test_logger.close = Mock()
with test_logger:
# Perform some logging operations
test_logger.track_variable(lambda: 1, "test_var")
test_logger.update()

test_logger.__exit__(1, 1, 1)
test_logger.flush_buffer.assert_called_once()
test_logger.close.assert_called_once()

test_logger.flush_buffer = original_flush
test_logger.close = original_close
# After exiting the context, the logger should be closed
assert len(test_logger._buffer) == 0
assert test_logger._file is None
assert test_logger._writer is None


# Test reset
Expand Down Expand Up @@ -484,15 +468,15 @@ def test_log(test_logger: Logger):
logging.Logger.log = original_log


# Test file path
def test_file_path(test_logger: Logger):
original_generate = test_logger._generate_file_paths
# # Test file path
# def test_file_path(test_logger: Logger):
# original_generate = test_logger._generate_file_paths

test_logger._generate_file_paths = Mock()
test_logger._file_path = ""
test_logger._generate_file_paths.assert_called_once()
# test_logger._generate_file_paths = Mock()
# test_logger._file_path = ""
# test_logger._generate_file_paths.assert_called_once()

test_logger._generate_file_paths = original_generate
# test_logger._generate_file_paths = original_generate


# Test buffer size
Expand All @@ -509,6 +493,7 @@ def test_file_level(test_logger: Logger):

# Test stream level
def test_stream_level(test_logger: Logger):
assert test_logger._file is None
test_logger.set_stream_level(LogLevel.INFO)
assert test_logger.stream_level == LogLevel.INFO

Expand Down
Loading

0 comments on commit 8e825ee

Please sign in to comment.