"""Testes do decorator que espaça as chamadas ao bridge do Premiere.""" import unittest from typing import Any from engine.integracoes.premiere.cliente_mcp import ClienteMCP from engine.integracoes.premiere.cliente_mcp_com_pausa import ClienteMCPComPausa from engine.integracoes.premiere.erros_mcp import ErroDeFerramentaMCP class _ClienteQueRegistra(ClienteMCP): """Dublê que só registra as chamadas recebidas e devolve um resultado fixo.""" def __init__(self, erro_a_levantar: Exception | None = None) -> None: self.chamadas: list[tuple[str, dict[str, Any]]] = [] self.erro_a_levantar = erro_a_levantar self.conectado = False def conectar(self) -> None: """Marca o dublê como conectado.""" self.conectado = True def desconectar(self) -> None: """Marca o dublê como desconectado.""" self.conectado = False def esta_conectado(self) -> bool: """Estado de conexão registrado pelo dublê.""" return self.conectado def chamar(self, nome_da_ferramenta: str, argumentos: dict[str, Any] | None = None) -> dict[str, Any]: """Registra a chamada e devolve um resultado fixo, ou levanta o erro configurado.""" self.chamadas.append((nome_da_ferramenta, argumentos or {})) if self.erro_a_levantar is not None: raise self.erro_a_levantar return {"ok": True} class _EsperaFalsa: """Substitui ``time.sleep`` registrando as pausas pedidas, sem esperar de verdade.""" def __init__(self) -> None: self.pausas: list[float] = [] def __call__(self, segundos: float) -> None: """Registra a pausa pedida.""" self.pausas.append(segundos) class TesteClienteMCPComPausa(unittest.TestCase): """Garante o espaçamento entre chamadas e a transparência do decorator.""" def setUp(self): self.interno = _ClienteQueRegistra() self.espera = _EsperaFalsa() self.cliente = ClienteMCPComPausa(self.interno, pausa_em_segundos=0.12, esperar=self.espera) def test_repassa_a_chamada_ao_cliente_interno(self): resultado = self.cliente.chamar("split_clip", {"time_seconds": 10.0}) self.assertEqual(resultado, {"ok": True}) self.assertEqual(self.interno.chamadas, [("split_clip", {"time_seconds": 10.0})]) def test_nao_pausa_antes_da_primeira_chamada(self): # A primeira chamada não precisa esperar: não há chamada anterior # ocupando o processo principal do Premiere. self.cliente.chamar("get_active_sequence") self.assertEqual(self.espera.pausas, []) def test_pausa_entre_chamadas_consecutivas(self): # Sem essa folga, uma rajada de round-trips síncronos de QE/ExtendScript # trava a UI do Premiere — foi o que se viu com um plano de 17 cortes. for _ in range(3): self.cliente.chamar("split_clip", {"time_seconds": 1.0}) self.assertEqual(self.espera.pausas, [0.12, 0.12]) def test_pausa_tambem_depois_de_uma_chamada_que_falhou(self): # Uma chamada que falhou ocupou o bridge do mesmo jeito; emendar a # próxima sem folga é justamente o que derruba a UI. interno = _ClienteQueRegistra(erro_a_levantar=ErroDeFerramentaMCP("recusado")) espera = _EsperaFalsa() cliente = ClienteMCPComPausa(interno, pausa_em_segundos=0.12, esperar=espera) for _ in range(2): with self.assertRaises(ErroDeFerramentaMCP): cliente.chamar("split_clip", {"time_seconds": 1.0}) self.assertEqual(espera.pausas, [0.12]) def test_conexao_e_delegada_sem_pausa(self): # Conectar/desconectar não são round-trips de edição; não precisam de folga. self.cliente.conectar() self.assertTrue(self.cliente.esta_conectado()) self.cliente.desconectar() self.assertFalse(self.cliente.esta_conectado()) self.assertEqual(self.espera.pausas, []) def test_pausa_negativa_e_recusada(self): with self.assertRaises(ValueError): ClienteMCPComPausa(self.interno, pausa_em_segundos=-0.1) if __name__ == "__main__": unittest.main()