"""PC adapters: grants, input cleanup, launcher reuse and native codec contract. Native tests require the bundled libraries; CI sets REQUIRE_NATIVE so a missing bundle is a failure, never a silent skip. No desktop consent or GPU is faked as successful real-host capture. The encoding tests need x264, which only CI's own builds bundle (it's GPL, so the installer leaves it out). FRAME_PC_REQUIRE_X264=1 makes its absence a failure; FRAME_PC_INSTALLER_BUNDLE=1 checks the installer's bundle instead. """ import ctypes import http.client import json import os from pathlib import Path import shutil import struct import subprocess import sys import threading import time import unittest from unittest import mock ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / 'ui')) import frame_pc_agent as agent import frame_pc_capture as capture import frame_pcview import frame_macview from frame_stream_stats import Stats from test_macview import WS class GrantsTests(unittest.TestCase): def test_source_bound_retry_ack_and_stop(self): g = agent.Grants('master') ticket = g.ticket('window:1') self.assertIsNone(g.redeem('window:2', {'t': ticket})) key = g.redeem('window:1', {'t': ticket}) self.assertEqual(key, g.redeem('window:1', {'t': ticket})) g.ack(key) self.assertIsNone(g.redeem('window:1', {'t': ticket})) self.assertEqual(key, g.redeem('window:1', {'r': key})) self.assertIsNone(g.redeem('window:2', {'r': key})) g.revoke('window:1') self.assertIsNone(g.redeem('window:1', {'r': key})) def test_expiry_and_stop_before_redeem(self): g = agent.Grants('master') with mock.patch.object(agent.time, 'monotonic', return_value=1): ticket = g.ticket('test') with mock.patch.object(agent.time, 'monotonic', return_value=62): self.assertIsNone(g.redeem('test', {'t': ticket})) ticket = g.ticket('test') g.revoke() self.assertIsNone(g.redeem('test', {'t': ticket})) class GatingTests(unittest.TestCase): """Experimental, Windows only, and off until the person turns it on.""" def view(self): return frame_pcview.PCView(['ssh'], mock.Mock(), 'frame') def test_only_windows_gets_the_pc_host(self): for platform, cls in (('win32', frame_pcview.PCView), ('linux', frame_macview.MacView), ('darwin', frame_macview.MacView)): with mock.patch.object(frame_pcview.sys, 'platform', platform): view = frame_pcview.host_view(['ssh'], mock.Mock(), 'frame') self.assertIs(type(view), cls, platform) def test_off_by_default_starts_nothing(self): view = self.view() with mock.patch.object(frame_pcview.sys, 'platform', 'win32'), \ mock.patch.object(frame_macview.subprocess, 'Popen', side_effect=AssertionError('started while off')): state = view.state() self.assertEqual(state, {'available': False, 'reason': frame_pcview.OFF, 'host': view.host, 'experimental': True, 'enabled': False}) with self.assertRaises(frame_macview.MacViewError): view.show('window:12') view.run.assert_not_called() def test_never_offered_off_windows_even_when_turned_on(self): view = self.view() view.enabled = True with mock.patch.object(frame_pcview.sys, 'platform', 'linux'): self.assertIn('only available on Windows', view.unavailable()) def test_turning_on_checks_for_the_bundled_libraries(self): view = self.view() missing = mock.Mock(is_file=mock.Mock(return_value=False)) with mock.patch.object(frame_pcview.sys, 'platform', 'win32'), \ mock.patch.object(frame_pcview, 'LIBRARY', missing): state = view.set_enabled(True) self.assertTrue(state['enabled']) self.assertFalse(state['available']) self.assertIn('libraries are missing', state['reason']) def test_turning_off_stops_streams_and_the_helper(self): view = self.view() view.enabled = True agent = mock.Mock() agent.poll.return_value = None view.agent, view.tunnel = agent, mock.Mock() tunnel = view.tunnel tunnel.poll.return_value = None view.stop = mock.Mock() with mock.patch.object(frame_pcview.sys, 'platform', 'win32'): state = view.set_enabled(False) view.stop.assert_called_once_with() agent.stdin.close.assert_called_once() agent.wait.assert_called() tunnel.terminate.assert_called_once() self.assertIsNone(view.agent) self.assertEqual((state['enabled'], state['reason']), (False, frame_pcview.OFF)) def test_server_enable_action(self): import sandbox # noqa: F401 (keeps the server off real data and services) import server with mock.patch.object(server, 'macview', frame_macview.MacView(['ssh'], mock.Mock(), 'frame')): with self.assertRaises(server.Failure) as e: server.macview_action({'action': 'enable', 'on': True}) self.assertIn('only available on Windows', str(e.exception)) view = self.view() view.set_enabled = mock.Mock(return_value={'enabled': True}) with mock.patch.object(server, 'macview', view): self.assertEqual(server.macview_action({'action': 'enable', 'on': True}), {'enabled': True}) server.macview_action({'action': 'enable', 'on': 'yes'}) # anything but true is off self.assertEqual([c.args for c in view.set_enabled.call_args_list], [(True,), (False,)]) class PageTests(unittest.TestCase): page = (ROOT / 'ui' / 'index.html').read_text(encoding='utf-8') def test_tool_link_is_windows_only_and_marked_experimental(self): self.assertIn('