Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
"""Shared pytest fixtures for the CodeCarbon test suite."""

import threading

import pytest

from codecarbon.core.hardware_cache import clear_cache as clear_hardware_cache
from codecarbon.external.scheduler import PeriodicScheduler


@pytest.fixture(autouse=True)
Expand All @@ -20,3 +23,20 @@ def _reset_process_hardware_cache():
yield
clear_hardware_cache()
detect_cpu_model.cache_clear()


@pytest.fixture(autouse=True)
def _stop_leaked_schedulers():
"""Stop schedulers a test left running.

A tracker that is never stopped keeps re-arming a timer that then fires
into whatever test runs next. This is only a safety net: tests are still
expected to stop the trackers they start.
"""
yield
for thread in threading.enumerate():
if not isinstance(thread, threading.Timer):
continue
scheduler = getattr(thread.function, "__self__", None)
if isinstance(scheduler, PeriodicScheduler):
scheduler.stop()
12 changes: 5 additions & 7 deletions tests/test_emissions_tracker_flush.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@ class TestCarbonTrackerFlush(unittest.TestCase):
def setUp(self) -> None:
self.project_name = "project_TestCarbonTrackerFlush"
self.emissions_file = "emissions-test-TestCarbonTrackerFlush.csv"
self.emissions_path = tempfile.gettempdir()
# A per-test directory, so that two tests counting rows in "their" file
# can never end up counting rows in the same one, see #1371.
self._temp_dir = tempfile.TemporaryDirectory()
self.addCleanup(self._temp_dir.cleanup)
self.emissions_path = self._temp_dir.name
self.emissions_file_path = os.path.join(
self.emissions_path, self.emissions_file
)
if os.path.isfile(self.emissions_file_path):
os.remove(self.emissions_file_path)

def tearDown(self) -> None:
if os.path.isfile(self.emissions_file_path):
os.remove(self.emissions_file_path)

def test_carbon_tracker_online_flush(self):
tracker = EmissionsTracker(
Expand Down
27 changes: 22 additions & 5 deletions tests/test_logging_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import tempfile
import time
import unittest
from pathlib import Path

from codecarbon.emissions_tracker import (
EmissionsTracker,
Expand All @@ -25,28 +26,42 @@ class TestCarbonTrackerFlush(unittest.TestCase):
def setUp(self) -> None:
self.project_name = "project_TestCarbonLoggingOutput"
self.emissions_logfile = "emissions-test-TestCarbonLoggingOutput.log"
self.emissions_path = tempfile.gettempdir()
self._temp_dir = tempfile.TemporaryDirectory()
self.addCleanup(self._temp_dir.cleanup)
self.emissions_path = self._temp_dir.name
self.emissions_file_path = os.path.join(
self.emissions_path, self.emissions_logfile
)
if os.path.isfile(self.emissions_file_path):
os.remove(self.emissions_file_path)
self._test_logger = logging.getLogger(self.project_name)
_channel = logging.FileHandler(self.emissions_file_path)
self._test_logger.addHandler(_channel)
self._test_logger.setLevel(logging.INFO)
self.external_logger = LoggerOutput(self._test_logger, logging.INFO)
self._working_dir_csv = Path.cwd() / "emissions.csv"
self._working_dir_csv_size = self._read_working_dir_csv_size()

def tearDown(self) -> None:
for handler in self._test_logger.handlers[:]:
self._test_logger.removeHandler(handler)
handler.close()
if os.path.isfile(self.emissions_file_path):
os.remove(self.emissions_file_path)
# These tests only assert on the logger output, so they must not write
# the CSV in the working directory too. Sharing that file with the rest
# of the suite is what made them order dependent, see #1371.
self.assertEqual(
self._working_dir_csv_size,
self._read_working_dir_csv_size(),
"the tracker wrote to emissions.csv in the working directory",
)

def _read_working_dir_csv_size(self):
if not self._working_dir_csv.is_file():
return None
return self._working_dir_csv.stat().st_size

def test_carbon_tracker_online_logging_output(self):
tracker = EmissionsTracker(
project_name=self.project_name,
save_to_file=False,
save_to_logger=True,
logging_logger=self.external_logger,
)
Expand All @@ -64,6 +79,7 @@ def test_carbon_tracker_offline_logging_output(self):
tracker = OfflineEmissionsTracker(
project_name=self.project_name,
country_iso_code="USA",
save_to_file=False,
save_to_logger=True,
logging_logger=self.external_logger,
)
Expand All @@ -80,6 +96,7 @@ def test_carbon_tracker_offline_logging_output(self):
def test_decorator_flush(self):
@track_emissions(
project_name=self.project_name,
save_to_file=False,
save_to_logger=True,
logging_logger=self.external_logger,
)
Expand Down