# (c) cavaliba.com - tests / log2 - timed() context manager

from unittest.mock import patch

from django.test import TestCase

import app_home.cache as cache
from app_home.log import DEBUG, log2
from app_home.models import CavalibaEvent


class TestLog2Timed(TestCase):
    def setUp(self):
        cache.clear()
        log2.reset(channel="cli")

    def test_success_logs_ok_with_duration(self):
        # patch log.py's own reference to the time module, not time.monotonic itself:
        # Django's query timing also calls time.monotonic (e.g. with --debug-sql)
        with patch("app_home.log.time") as fake_time:
            fake_time.monotonic.side_effect = [10.0, 10.25]
            with log2.timed("test.timed", target=("job", "j1")):
                pass
        event = CavalibaEvent.objects.get(action="test.timed")
        self.assertEqual(event.outcome, "success")
        self.assertEqual(event.duration_ms, 250)
        self.assertEqual(event.target_id, "j1")

    def test_fields_set_in_block_are_stored(self):
        with log2.timed("test.timed", count=1) as ev:
            ev["count"] = 42
            ev["extra"] = {"done": True}
        event = CavalibaEvent.objects.get(action="test.timed")
        self.assertEqual(event.count, 42)
        self.assertEqual(event.extra, {"done": True})

    def test_exception_logs_fail_and_reraises(self):
        with self.assertRaises(ValueError):
            with log2.timed("test.timed"):
                raise ValueError("boom")
        event = CavalibaEvent.objects.get(action="test.timed")
        self.assertEqual(event.outcome, "failure")
        self.assertEqual(event.reason, "exception")
        self.assertEqual(event.message, "ValueError: boom")
        self.assertIsNotNone(event.duration_ms)

    def test_level_applies_to_success_only(self):
        with log2.timed("test.timed.ok", level=DEBUG):
            pass
        self.assertEqual(CavalibaEvent.objects.get(action="test.timed.ok").level, "DEBUG")
        with self.assertRaises(RuntimeError):
            with log2.timed("test.timed.ko", level=DEBUG):
                raise RuntimeError("boom")
        self.assertEqual(CavalibaEvent.objects.get(action="test.timed.ko").level, "ERROR")
