def raop_conf_fixture(raop_device, raop_properties): service = ManualService("raop_id", Protocol.RAOP, raop_device.get_port(Protocol.RAOP), raop_properties) conf = AppleTV("127.0.0.1", "Apple TV") conf.add_service(service) yield conf
async def mock_pairing(event_loop): obj = MagicMock() service = ManualService(None, Protocol.DMAP, 0, {}) config = AppleTV("Apple TV", "127.0.0.1") config.add_service(service) zeroconf = zeroconf_stub.stub(pairing) async def _start(pin_code=PIN_CODE, pairing_guid=PAIRING_GUID, name=REMOTE_NAME, addresses=None): options = {"zeroconf": zeroconf} if pairing_guid: options["pairing_guid"] = pairing_guid if name: options["name"] = name if addresses: options["addresses"] = addresses obj.pairing = pairing.DmapPairingHandler(config, service, await http.create_session(), event_loop, **options) await obj.pairing.begin() obj.pairing.pin(pin_code) return obj.pairing, zeroconf, service yield _start await obj.pairing.finish() await obj.pairing.close()
async def test_connect_only_companion(self): conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") conf.add_service( CompanionService(self.fake_atv.get_port(Protocol.Companion))) with pytest.raises(exceptions.DeviceIdMissingError): await pyatv.connect(conf, loop=self.loop)
def _manual_device(args): config = AppleTV(IPv4Address(args.address), args.name) service = ManualService(args.id, args.protocol, args.port, {}) service.credentials = getattr(args, f"{args.protocol.name.lower()}_credentials") service.password = args.raop_password config.add_service(service) return config
async def setUpAsync(self): self.service = CompanionService(self.fake_atv.get_port(Protocol.Companion)) self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") self.conf.add_service( MrpService("mrp_id", self.fake_atv.get_port(Protocol.MRP)) ) self.conf.add_service(self.service)
def setUp(self): AioHTTPTestCase.setUp(self) self.service = MrpService(CLIENT_IDENTIFIER, self.fake_atv.get_port(Protocol.MRP)) self.conf = AppleTV("127.0.0.1", "Apple TV") self.conf.add_service(self.service)
async def setUpAsync(self): await super().setUpAsync() self.conf = AppleTV('127.0.0.1', 'Test device') self.conf.add_service(MrpService('mrp_id', self.fake_atv.port)) self.conf.add_service( AirPlayService('airplay_id', self.server.port, DEVICE_CREDENTIALS)) self.atv = await self.get_connected_device()
def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = AirPlayService("airplay_id", port=self.server.port) self.conf = AppleTV("127.0.0.1", "Apple TV") self.conf.add_service(self.service)
def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = AirPlayService('airplay_id', port=self.server.port) self.conf = AppleTV('127.0.0.1', 'Apple TV') self.conf.add_service(self.service)
async def setUpAsync(self): await super().setUpAsync() self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") self.conf.add_service( MrpService("mrp_id", self.fake_atv.get_port(Protocol.MRP))) self.conf.add_service( AirPlayService("airplay_id", self.server.port, DEVICE_CREDENTIALS)) self.atv = await self.get_connected_device()
async def get_connected_device(self, hsgid): self.dmap_service = DmapService("dmapid", hsgid, port=self.server.port) self.airplay_service = AirPlayService("airplay_id", self.server.port, DEVICE_CREDENTIALS) self.conf = AppleTV(ipaddress.IPv4Address("127.0.0.1"), "Apple TV") self.conf.add_service(self.dmap_service) self.conf.add_service(self.airplay_service) return await connect(self.conf, self.loop)
async def test_connect_only_companion(event_loop): service = ManualService(None, Protocol.Companion, 0, {}) # connect never happens conf = AppleTV("127.0.0.1", "Apple TV") conf.add_service(service) with pytest.raises(exceptions.DeviceIdMissingError): await pyatv.connect(conf, loop=event_loop)
class DmapPairFunctionalTest(AioHTTPTestCase): def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = DmapService("dmap_id", PAIRING_GUID, port=self.server.port) self.conf = AppleTV("127.0.0.1", "Apple TV") self.conf.add_service(self.service) # TODO: currently stubs internal method, should provide stub # for netifaces later pairing._get_private_ip_addresses = lambda: [ ipaddress.ip_address("10.0.0.1") ] self.zeroconf = zeroconf_stub.stub(pyatv.dmap.pairing) async def tearDownAsync(self): await self.pairing.close() await super().tearDownAsync() async def get_application(self, loop=None): self.fake_atv = FakeAppleTV(HSGID, PAIRING_GUID, SESSION_ID) self.usecase = AppleTVUseCases(self.fake_atv) return self.fake_atv.app async def initiate_pairing(self, name=REMOTE_NAME, pairing_guid=PAIRING_GUID): self.usecase.pairing_response(REMOTE_NAME, PAIRINGCODE) options = { "zeroconf": self.zeroconf, "name": name, "pairing_guid": pairing_guid, } self.pairing = await pyatv.pair(self.conf, Protocol.DMAP, self.loop, **options) @unittest_run_loop async def test_pairing_with_device(self): await self.initiate_pairing() self.assertFalse(self.pairing.device_provides_pin) await self.pairing.begin() self.pairing.pin(PIN_CODE) await self.usecase.act_on_bonjour_services(self.zeroconf) await self.pairing.finish() self.assertTrue(self.pairing.has_paired) self.assertEqual(self.service.credentials, PAIRING_GUID)
class PairFunctionalTest(AioHTTPTestCase): def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = AirPlayService('airplay_id', port=self.server.port) self.conf = AppleTV('127.0.0.1', 'Apple TV') self.conf.add_service(self.service) async def tearDownAsync(self): await self.pairing.close() await super().tearDownAsync() async def get_application(self, loop=None): self.fake_atv = FakeAirPlayDevice(self) self.usecase = AirPlayUseCases(self.fake_atv) return self.fake_atv.app async def do_pairing(self, pin=DEVICE_PIN): self.usecase.airplay_require_authentication() self.pairing = await pair(self.conf, Protocol.AirPlay, self.loop) self.assertTrue(self.pairing.device_provides_pin) await self.pairing.begin() if pin: self.pairing.pin(pin) self.assertFalse(self.pairing.has_paired) await self.pairing.finish() self.assertTrue(self.pairing.has_paired) self.assertEqual(self.service.credentials, DEVICE_CREDENTIALS) @unittest_run_loop async def test_pairing_exception_invalid_pin(self): with self.assertRaises(exceptions.PairingError): await self.do_pairing(9999) @unittest_run_loop async def test_pairing_exception_no_pin(self): with self.assertRaises(exceptions.PairingError): await self.do_pairing(None) @unittest_run_loop @patch('os.urandom') async def test_pairing_with_device_new_credentials(self, rand_func): rand_func.side_effect = predetermined_key await self.do_pairing() @unittest_run_loop async def test_pairing_with_device_existing_credentials(self): self.conf.get_service( Protocol.AirPlay).credentials = DEVICE_CREDENTIALS await self.do_pairing()
async def get_connected_device(self, hsgid): self.dmap_service = DmapService('dmap_id', hsgid, port=self.server.port) self.airplay_service = AirPlayService('airplay_id', self.server.port, DEVICE_CREDENTIALS) self.conf = AppleTV('127.0.0.1', 'Apple TV') self.conf.add_service(self.dmap_service) self.conf.add_service(self.airplay_service) return await pyatv.connect(self.conf, self.loop)
async def test_play_url_no_service(self): conf = AppleTV("127.0.0.1", "Apple TV") conf.add_service(self.dmap_service) atv = await connect(conf, self.loop) with self.assertRaises(exceptions.NotSupportedError): await atv.stream.play_url("http://123") atv.close()
async def setUpAsync(self): await super().setUpAsync() self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") self.conf.add_service( MrpService("mrp_id", self.fake_atv.get_port(Protocol.MRP))) self.conf.add_service( CompanionService( self.fake_atv.get_port(Protocol.Companion), credentials=CLIENT_CREDENTIALS, )) self.atv = await self.get_connected_device()
def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = DmapService("dmap_id", PAIRING_GUID, port=self.server.port) self.conf = AppleTV("127.0.0.1", "Apple TV") self.conf.add_service(self.service) self.zeroconf = zeroconf_stub.stub(pyatv.dmap.pairing)
class MrpAuthFunctionalTest(AioHTTPTestCase): def setUp(self): AioHTTPTestCase.setUp(self) self.service = MrpService(CLIENT_IDENTIFIER, self.fake_atv.port) self.conf = AppleTV('127.0.0.1', 'Apple TV') self.conf.add_service(self.service) async def tearDownAsync(self): await self.handle.close() await super().tearDownAsync() async def get_application(self, loop=None): self.fake_atv = FakeAppleTV(self, self.loop) self.usecase = AppleTVUseCases(self.fake_atv) return self.fake_atv.app @unittest_run_loop async def test_pairing_with_device(self): self.handle = await pyatv.pair(self.conf, Protocol.MRP, self.loop) self.assertTrue(self.handle.device_provides_pin) await self.handle.begin() self.handle.pin(PIN_CODE) await self.handle.finish() self.assertTrue(self.handle.has_paired) self.assertTrue(self.fake_atv.has_paired) @unittest_run_loop async def test_pairing_with_bad_pin(self): self.handle = await pyatv.pair(self.conf, Protocol.MRP, self.loop) self.assertTrue(self.handle.device_provides_pin) await self.handle.begin() self.handle.pin(PIN_CODE + 1) with self.assertRaises(exceptions.PairingError): await self.handle.finish() self.assertFalse(self.handle.has_paired) self.assertFalse(self.fake_atv.has_paired) @unittest_run_loop async def test_pairing_authentication(self): self.service.credentials = CLIENT_CREDENTIALS self.handle = await pyatv.connect(self.conf, self.loop) self.assertTrue(self.fake_atv.has_authenticated)
async def setUpAsync(self): await super().setUpAsync() self.service = ManualService( None, Protocol.Companion, self.fake_atv.get_port(Protocol.Companion), {} ) self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") self.conf.add_service( ManualService( "mrp_id", Protocol.MRP, self.fake_atv.get_port(Protocol.MRP), {} ) ) self.conf.add_service(self.service)
def companion_conf_fixture(companion_device): airplay = ManualService("airplayid", Protocol.AirPlay, 0, {}) service = ManualService( None, Protocol.Companion, companion_device.get_port(Protocol.Companion), {}, credentials=CLIENT_CREDENTIALS, ) conf = AppleTV("127.0.0.1", "Apple TV") conf.add_service(service) conf.add_service(airplay) yield conf
async def test_scan_mrp(self): zeroconf_stub.stub(pyatv, MRP_SERVICE_1, MRP_SERVICE_2) atvs = await pyatv.scan_for_apple_tvs(self.loop, only_usable=False, timeout=0) self.assertEqual(len(atvs), 2) dev1 = AppleTV(ipaddress.ip_address('10.0.0.4'), 'Apple TV 4') self.assertIn(dev1, atvs) dev2 = AppleTV(ipaddress.ip_address('10.0.0.5'), 'Apple TV 5') self.assertIn(dev2, atvs)
async def setUpAsync(self): await super().setUpAsync() self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device") self.conf.add_service( ManualService("mrp_id", Protocol.MRP, self.fake_atv.get_port(Protocol.MRP), {})) airplay_service = ManualService( "airplay_id", Protocol.AirPlay, self.server.port, properties={"features": "0x1"}, # AirPlayVideoV1 supported ) airplay_service.credentials = DEVICE_CREDENTIALS self.conf.add_service(airplay_service) self.atv = await self.get_connected_device()
async def connect( config: conf.AppleTV, loop: asyncio.AbstractEventLoop, protocol: Protocol = None, session: aiohttp.ClientSession = None, ) -> interface.AppleTV: """Connect to a device based on a configuration.""" if config.identifier is None: raise exceptions.DeviceIdMissingError("no device identifier") service = config.main_service(protocol=protocol) implementation = {Protocol.DMAP: DmapAppleTV, Protocol.MRP: MrpAppleTV}.get( service.protocol ) if not implementation: raise exceptions.UnsupportedProtocolError(str(service.protocol)) # AirPlay stream API is the same for both DMAP and MRP airplay = AirPlayStreamAPI(config, loop) atv = implementation(loop, await net.create_session(session), config, airplay) await atv.connect() return atv
def __init__( self, loop: asyncio.AbstractEventLoop, session_manager: ClientSessionManager, config: conf.AppleTV, airplay: Stream, ) -> None: """Initialize a new Apple TV.""" super().__init__() self._session_manager = session_manager self._config = config self._mrp_service = config.get_service(Protocol.MRP) assert self._mrp_service is not None self._connection = MrpConnection(config.address, self._mrp_service.port, loop, atv=self) self._srp = SRPAuthHandler() self._protocol = MrpProtocol(self._connection, self._srp, self._mrp_service) self._psm = PlayerStateManager(self._protocol, loop) self._mrp_remote = MrpRemoteControl(loop, self._psm, self._protocol) self._mrp_metadata = MrpMetadata(self._protocol, self._psm, config.identifier) self._mrp_power = MrpPower(loop, self._protocol, self._mrp_remote) self._mrp_push_updater = MrpPushUpdater(loop, self._mrp_metadata, self._psm) self._mrp_features = MrpFeatures(self._config, self._psm) self._airplay = airplay
def setup( loop: asyncio.AbstractEventLoop, config: conf.AppleTV, interfaces: Dict[Any, Relayer], device_listener: StateProducer, session_manager: ClientSessionManager, ) -> Optional[Tuple[Callable[[], Awaitable[None]], Callable[[], None], Set[FeatureName]]]: """Set up a new AirPlay service.""" service = config.get_service(Protocol.AirPlay) assert service is not None # TODO: Split up in connect/protocol and Stream implementation stream = AirPlayStream(config) interfaces[Features].register( AirPlayFeatures(cast(conf.AirPlayService, service)), Protocol.AirPlay) interfaces[Stream].register(stream, Protocol.AirPlay) async def _connect() -> None: pass def _close() -> None: stream.close() return _connect, _close, set([FeatureName.PlayUrl])
def __init__( self, loop, session_manager: ClientSessionManager, config: conf.AppleTV, airplay: Stream, ) -> None: """Initialize a new Apple TV.""" super().__init__() self._session_manager = session_manager self._config = config self._dmap_service = config.get_service(Protocol.DMAP) assert self._dmap_service is not None daap_http = net.HttpSession( session_manager.session, f"http://{config.address}:{self._dmap_service.port}/", ) self._requester = DaapRequester(daap_http, self._dmap_service.credentials) self._apple_tv = BaseDmapAppleTV(self._requester) self._dmap_remote = DmapRemoteControl(self._apple_tv) self._dmap_metadata = DmapMetadata(config.identifier, self._apple_tv) self._dmap_power = DmapPower() self._dmap_push_updater = DmapPushUpdater(loop, self._apple_tv, self) self._dmap_features = DmapFeatures(config, self._apple_tv) self._airplay = airplay
def setUp(self): AioHTTPTestCase.setUp(self) self.pairing = None self.service = DmapService('dmap_id', PAIRING_GUID, port=self.server.port) self.conf = AppleTV('127.0.0.1', 'Apple TV') self.conf.add_service(self.service) # TODO: currently stubs internal method, should provide stub # for netifaces later pairing._get_private_ip_addresses = \ lambda: [ipaddress.ip_address('10.0.0.1')] self.zeroconf = zeroconf_stub.stub(pyatv.dmap.pairing)
class MRPFunctionalTest(common_functional_tests.CommonFunctionalTests): async def setUpAsync(self): await super().setUpAsync() self.conf = AppleTV('127.0.0.1', 'Test device') self.conf.add_service(MrpService('mrp_id', self.fake_atv.port)) self.conf.add_service( AirPlayService('airplay_id', self.server.port, DEVICE_CREDENTIALS)) self.atv = await self.get_connected_device() async def tearDownAsync(self): await self.atv.close() await super().tearDownAsync() async def get_application(self, loop=None): self.fake_atv = FakeAppleTV(self, self.loop) self.usecase = AppleTVUseCases(self.fake_atv) return self.fake_atv.app async def get_connected_device(self): return await pyatv.connect(self.conf, loop=self.loop) @unittest_run_loop async def test_button_home(self): await self.atv.remote_control.home() await until(lambda: self.fake_atv.last_button_pressed == 'home') @unittest_run_loop async def test_button_volume_up(self): await self.atv.remote_control.volume_up() await until(lambda: self.fake_atv.last_button_pressed == 'volume_up') @unittest_run_loop async def test_button_volume_down(self): await self.atv.remote_control.volume_down() await until(lambda: self.fake_atv.last_button_pressed == 'volume_down') @unittest_run_loop async def test_button_suspend(self): await self.atv.remote_control.suspend() await until(lambda: self.fake_atv.last_button_pressed == 'suspend') @unittest_run_loop async def test_button_wakeup(self): await self.atv.remote_control.wakeup() await until(lambda: self.fake_atv.last_button_pressed == 'wakeup')
async def test_scan_for_apple_tvs(self): zeroconf_stub.stub(pyatv, HOMESHARING_SERVICE_1, HOMESHARING_SERVICE_2, MRP_SERVICE_1, AIRPLAY_SERVICE_1) atvs = await pyatv.scan_for_apple_tvs(self.loop, timeout=0) self.assertEqual(len(atvs), 3) # First device dev1 = AppleTV(ipaddress.ip_address('10.0.0.1'), 'Apple TV 1') self.assertIn(dev1, atvs) # Second device dev2 = AppleTV(ipaddress.ip_address('10.0.0.2'), 'Apple TV 2') self.assertIn(dev2, atvs) # Third device dev3 = AppleTV(ipaddress.ip_address('10.0.0.4'), 'Apple TV 4') self.assertIn(dev3, atvs)