Ctrl K
ComunidadGuías…

test_blink_engine_notification_webhook.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Webhook sortant (issue GitHub #11) : vérifie l'appel réel depuis
un_passage() pour les deux sources (USB et cloud), pas seulement par lecture
du code. Fixture calquée sur test_suppression_auto_pendant_lot.py, qui
exerce déjà ce même passage réussi pour les deux sources."""

import contextlib
import datetime as dt
import io
import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest import mock

import blink_engine
import blink_models
import blink_registre
import runtime


def _boite(nom, contenu=b""):
    return (len(contenu) + 8).to_bytes(4, "big") + nom + contenu


VIDEO = (
    _boite(b"ftyp", b"isom\x00\x00\x02\x00isomiso2")
    + _boite(b"moov") + _boite(b"mdat", b"video-simulee")
)


class NotificationWebhookUnPassageTests(unittest.IsolatedAsyncioTestCase):
    async def _executer(self, source):
        with tempfile.TemporaryDirectory(prefix="blink-notif-webhook-") as dossier:
            racine = Path(dossier)
            sync = SimpleNamespace(sync_id=10, network_id=7)

            class Clip:
                def __init__(self, numero, camera):
                    self.id = str(numero)
                    self.name = camera
                    self.network_id = 7
                    self.device_id = "cam-" + camera
                    self.created_at = dt.datetime(
                        2026, 9, 7, 10, numero, tzinfo=dt.timezone.utc)
                    self.size = 1

                async def download_to(self, _blink, target):
                    target.parent.mkdir(parents=True, exist_ok=True)
                    target.write_bytes(VIDEO)
                    return True

                async def delete_video(self, _blink):
                    return True

            clip = Clip(1, "Jardin")
            arguments = SimpleNamespace(
                since=None, camera=None, command="download",
                output=racine / "clips", hub=None, overwrite=False,
                source=source, loop=None,
            )

            async def telecharger_usb(blink, clip, target, _overwrite):
                await clip.download_to(blink, target)
                return "downloaded"

            with contextlib.ExitStack() as patches:
                patches.enter_context(mock.patch.object(
                    runtime, "app_dir", return_value=racine))
                runtime.ecrire_suppression_auto(set())
                for nom in ("read_local_manifest", "read_cloud_manifest"):
                    patches.enter_context(mock.patch.object(
                        blink_models, nom, new=mock.AsyncMock(return_value=[clip])))
                patches.enter_context(mock.patch.object(
                    blink_engine, "download_clip", side_effect=telecharger_usb))
                patches.enter_context(mock.patch.object(
                    blink_engine, "hub_lock", side_effect=lambda *_a: contextlib.nullcontext()))
                patches.enter_context(mock.patch.object(
                    blink_engine.md, "valid_mp4_complet",
                    side_effect=blink_engine.md.valid_mp4))
                patches.enter_context(mock.patch.object(runtime, "travail"))
                for nom in ("marquer", "toast"):
                    patches.enter_context(mock.patch.object(runtime, nom))
                patches.enter_context(mock.patch.object(
                    runtime, "lire_langue", return_value="fr"))
                patches.enter_context(mock.patch.object(
                    runtime, "lire_reglages", return_value={"port": 8765}))
                notifier = patches.enter_context(
                    mock.patch.object(runtime, "notifier_nouveau_media"))
                patches.enter_context(contextlib.redirect_stdout(io.StringIO()))
                code = await blink_engine.un_passage(
                    object(), arguments, [("Maison", sync)])
                self.assertEqual(code, 0)
                return notifier

    async def test_clip_usb_telecharge_declenche_la_notification(self):
        notifier = await self._executer("usb")
        notifier.assert_called_once()
        camera, chemin, type_media = notifier.call_args.args
        self.assertEqual(camera, "Jardin")
        self.assertEqual(type_media, "clip")
        self.assertTrue(str(chemin).endswith(".mp4"))

    async def test_clip_cloud_telecharge_declenche_la_notification(self):
        notifier = await self._executer("cloud")
        notifier.assert_called_once()
        camera, chemin, type_media = notifier.call_args.args
        self.assertEqual(camera, "Jardin")
        self.assertEqual(type_media, "clip")
        self.assertTrue(str(chemin).endswith(".mp4"))


if __name__ == "__main__":
    unittest.main()