# (c) cavaliba.com - tests / log2 - DB storage gates and export fallback

from unittest.mock import patch

from django.test import TestCase, override_settings

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


class TestLog2StorageGates(TestCase):
    def setUp(self):
        cache.clear()
        log2.reset(channel="web", client_ip="10.9.9.9")

    def tearDown(self):
        # configuration rows roll back with the test, the in-memory cache does not
        cache.clear()

    def _exclude(self, value):
        CavalibaConfiguration.objects.update_or_create(
            appname="home", keyname="LOG_EXCLUDED_IP", defaults={"value": value}
        )
        cache.clear()

    def test_event_stored_whatever_the_export_level(self):
        # export to stdout is off under manage.py test: storage must not depend on it
        log2.access("test.store")
        self.assertTrue(CavalibaEvent.objects.filter(action="test.store").exists())

    @override_settings(CAVALIBA_LOG_DB=False)
    def test_db_switch_off_still_exports(self):
        with self.assertLogs("cavaliba.event", level="DEBUG") as captured:
            log2.ok("test.nodb")
        self.assertFalse(CavalibaEvent.objects.filter(action="test.nodb").exists())
        self.assertEqual(captured.records[0].event["action"], "test.nodb")

    def test_excluded_ip_not_stored(self):
        self._exclude("10.1.1.1 10.9.9.9")
        log2.ok("test.excluded")
        self.assertFalse(CavalibaEvent.objects.filter(action="test.excluded").exists())

    def test_other_ip_stored(self):
        self._exclude("10.1.1.1")
        log2.ok("test.kept")
        self.assertTrue(CavalibaEvent.objects.filter(action="test.kept").exists())

    def test_star_excludes_everything(self):
        self._exclude("*")
        log2.ok("test.star")
        self.assertFalse(CavalibaEvent.objects.filter(action="test.star").exists())

    def test_db_failure_still_exports_with_error(self):
        with patch.object(CavalibaEvent.objects, "create", side_effect=RuntimeError("db down")):
            with self.assertLogs("cavaliba.event", level="DEBUG") as captured:
                event = log2.fail("test.dbfail")
        self.assertEqual(event["db_error"], "db down")
        self.assertNotIn("id", event)
        self.assertEqual(captured.records[0].event["db_error"], "db down")
