@bharper/atv-js 0.2.6 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +89 -9
- package/dist/index.js.map +1 -1
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +96 -11
- package/dist/mdns.js.map +1 -1
- package/examples/print-device-json.js +22 -0
- package/package.json +2 -3
- package/pyatv/.codecov.yml +38 -0
- package/pyatv/.github/FUNDING.yml +3 -0
- package/pyatv/.github/ISSUE_TEMPLATE/bug_report.yml +80 -0
- package/pyatv/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/pyatv/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
- package/pyatv/.github/ISSUE_TEMPLATE/implementation-proposal.yml +29 -0
- package/pyatv/.github/ISSUE_TEMPLATE/investigation.yml +16 -0
- package/pyatv/.github/ISSUE_TEMPLATE/minor-change.yml +10 -0
- package/pyatv/.github/ISSUE_TEMPLATE/question-or-idea.yml +11 -0
- package/pyatv/.github/dependabot.yml +26 -0
- package/pyatv/.github/workflows/codeql-analysis.yml +71 -0
- package/pyatv/.github/workflows/release.yml +160 -0
- package/pyatv/.github/workflows/tests.yml +104 -0
- package/pyatv/.gitpod.yml +23 -0
- package/pyatv/CHANGES.md +3708 -0
- package/pyatv/CODE_OF_CONDUCT.md +76 -0
- package/pyatv/CONTRIBUTING.md +72 -0
- package/pyatv/CONTRIBUTORS.md +3 -0
- package/pyatv/Dockerfile +15 -0
- package/pyatv/LICENSE.md +9 -0
- package/pyatv/MANIFEST.in +14 -0
- package/pyatv/README.md +111 -0
- package/pyatv/base_versions.txt +13 -0
- package/pyatv/chickn.yaml +75 -0
- package/pyatv/docs/404.html +24 -0
- package/pyatv/docs/CNAME +1 -0
- package/pyatv/docs/Gemfile +31 -0
- package/pyatv/docs/_config.yml +121 -0
- package/pyatv/docs/_includes/api +10 -0
- package/pyatv/docs/_includes/atvremote_scan +32 -0
- package/pyatv/docs/_includes/code +6 -0
- package/pyatv/docs/_includes/issue +14 -0
- package/pyatv/docs/_includes/pypi +5 -0
- package/pyatv/docs/_layouts/template.html +109 -0
- package/pyatv/docs/api/pyatv.conf.html +312 -0
- package/pyatv/docs/api/pyatv.const.html +974 -0
- package/pyatv/docs/api/pyatv.convert.html +106 -0
- package/pyatv/docs/api/pyatv.exceptions.html +489 -0
- package/pyatv/docs/api/pyatv.helpers.html +102 -0
- package/pyatv/docs/api/pyatv.html +120 -0
- package/pyatv/docs/api/pyatv.interface.html +2369 -0
- package/pyatv/docs/api/pyatv.settings.html +484 -0
- package/pyatv/docs/api/pyatv.storage.file_storage.html +102 -0
- package/pyatv/docs/api/pyatv.storage.html +186 -0
- package/pyatv/docs/api/pyatv.storage.memory_storage.html +83 -0
- package/pyatv/docs/assets/css/custom.css +19 -0
- package/pyatv/docs/assets/css/hljs.css +1 -0
- package/pyatv/docs/assets/css/normalize.css +349 -0
- package/pyatv/docs/assets/css/pdoc.css +287 -0
- package/pyatv/docs/assets/css/sanitize.css +566 -0
- package/pyatv/docs/assets/css/style.scss +9 -0
- package/pyatv/docs/assets/img/logo.svg +63 -0
- package/pyatv/docs/assets/js/highlight.9.12.0.min.js +3 -0
- package/pyatv/docs/assets/js/mermaid.8.9.2.min.js +32 -0
- package/pyatv/docs/assets/js/mermaid.min.js.map +1 -0
- package/pyatv/docs/development/apps.md +81 -0
- package/pyatv/docs/development/audio.md +42 -0
- package/pyatv/docs/development/control.md +56 -0
- package/pyatv/docs/development/development.md +15 -0
- package/pyatv/docs/development/device_info.md +36 -0
- package/pyatv/docs/development/examples.md +44 -0
- package/pyatv/docs/development/features.md +70 -0
- package/pyatv/docs/development/keyboard.md +51 -0
- package/pyatv/docs/development/listeners.md +144 -0
- package/pyatv/docs/development/logging.md +55 -0
- package/pyatv/docs/development/metadata.md +115 -0
- package/pyatv/docs/development/power_management.md +53 -0
- package/pyatv/docs/development/scan_pair_and_connect.md +331 -0
- package/pyatv/docs/development/services.md +9 -0
- package/pyatv/docs/development/storage.md +259 -0
- package/pyatv/docs/development/stream.md +241 -0
- package/pyatv/docs/development/testing.md +9 -0
- package/pyatv/docs/documentation/atvlog.md +64 -0
- package/pyatv/docs/documentation/atvproxy.md +244 -0
- package/pyatv/docs/documentation/atvremote.md +639 -0
- package/pyatv/docs/documentation/atvscript.md +275 -0
- package/pyatv/docs/documentation/concepts.md +168 -0
- package/pyatv/docs/documentation/documentation.md +130 -0
- package/pyatv/docs/documentation/getting_started.md +248 -0
- package/pyatv/docs/documentation/protocols.md +1959 -0
- package/pyatv/docs/documentation/supported_features.md +246 -0
- package/pyatv/docs/documentation/tutorial.md +1062 -0
- package/pyatv/docs/documentation/workspace.code-workspace +7 -0
- package/pyatv/docs/favicon.ico +0 -0
- package/pyatv/docs/index.md +109 -0
- package/pyatv/docs/internals/design.md +354 -0
- package/pyatv/docs/internals/documentation.md +84 -0
- package/pyatv/docs/internals/interfaces.md +95 -0
- package/pyatv/docs/internals/internals.md +157 -0
- package/pyatv/docs/internals/submit_pr.md +56 -0
- package/pyatv/docs/internals/testing.md +176 -0
- package/pyatv/docs/internals/tools.md +574 -0
- package/pyatv/docs/pdoc_templates/config.mako +46 -0
- package/pyatv/docs/pdoc_templates/html.mako +454 -0
- package/pyatv/docs/support/acknowledgements.md +87 -0
- package/pyatv/docs/support/faq.md +214 -0
- package/pyatv/docs/support/migration.md +138 -0
- package/pyatv/docs/support/scanning_issues.md +110 -0
- package/pyatv/docs/support/support.md +18 -0
- package/pyatv/docs/support/troubleshooting.md +83 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeMessage_pb2.pyi +37 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFadeResponseMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage.proto +5 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/AudioFormatSettingsMessage_pb2.pyi +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage.proto +16 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ClientUpdatesConfigMessage_pb2.pyi +44 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo.proto +117 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandInfo_pb2.pyi +325 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions.proto +36 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CommandOptions_pb2.pyi +115 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Common.proto +79 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Common_pb2.pyi +228 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ConfigureConnectionMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem.proto +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata.proto +213 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItemMetadata_pb2.pyi +630 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ContentItem_pb2.pyi +94 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/CryptoPairingMessage_pb2.pyi +46 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage.proto +69 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/DeviceInfoMessage_pb2.pyi +226 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GenericMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetKeyboardSessionMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage.proto +10 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetRemoteTextInputSessionMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/GetVolumeResultMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage.proto +88 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/KeyboardMessage_pb2.pyi +261 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption.proto +9 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/LanguageOption_pb2.pyi +42 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ModifyOutputContextRequestMessage_pb2.pyi +86 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NotificationMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingClient_pb2.pyi +49 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo.proto +24 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingInfo_pb2.pyi +79 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/NowPlayingPlayer_pb2.pyi +45 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Origin.proto +17 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/OriginClientPropertiesMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/Origin_pb2.pyi +63 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueCapabilities_pb2.pyi +33 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext.proto +5 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueContext_pb2.pyi +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage.proto +29 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueueRequestMessage_pb2.pyi +87 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlaybackQueue_pb2.pyi +53 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerClientPropertiesMessage_pb2.pyi +37 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/PlayerPath_pb2.pyi +39 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage.proto +171 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/ProtocolMessage_pb2.pyi +377 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage.proto +18 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterForGameControllerEventsMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterHIDDeviceResultMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RegisterVoiceInputDeviceResponseMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoteTextInputMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveEndpointsMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemoveOutputDevicesMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/RemovePlayerMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendButtonEventMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage.proto +16 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandMessage_pb2.pyi +43 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage.proto +100 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendCommandResultMessage_pb2.pyi +286 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage.proto +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendHIDEventMessage_pb2.pyi +63 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage.proto +24 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendPackedVirtualTouchEventMessage_pb2.pyi +64 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage.proto +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SendVoiceInputMessage_pb2.pyi +134 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetArtworkMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage.proto +18 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetConnectionStateMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage.proto +28 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDefaultSupportedCommandsMessage_pb2.pyi +74 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetDiscoveryModeMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetHiliteModeMessage_pb2.pyi +32 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetNowPlayingPlayerMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage.proto +17 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetRecordingStateMessage_pb2.pyi +54 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage.proto +27 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetStateMessage_pb2.pyi +72 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SetVolumeMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/SupportedCommands_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TextInputMessage_pb2.pyi +76 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey.proto +6 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionKey_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage.proto +15 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionMessage_pb2.pyi +42 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPacket_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets.proto +7 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/TransactionPackets_pb2.pyi +30 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateClientMessage_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemArtworkMessage_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateContentItemMessage_pb2.pyi +41 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage.proto +25 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateEndPointsMessage_pb2.pyi +74 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage.proto +88 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdateOutputDeviceMessage_pb2.pyi +277 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath.proto +12 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/UpdatePlayerPath_pb2.pyi +34 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage.proto +8 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VirtualTouchDeviceDescriptorMessage_pb2.pyi +36 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage.proto +8 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VoiceInputDeviceDescriptorMessage_pb2.pyi +35 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage.proto +23 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlAvailabilityMessage_pb2.pyi +71 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage.proto +14 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeControlCapabilitiesDidChangeMessage_pb2.pyi +40 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage.proto +13 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/VolumeDidChangeMessage_pb2.pyi +38 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage.proto +11 -0
- package/pyatv/pyatv/protocols/mrp/protobuf/WakeDeviceMessage_pb2.pyi +26 -0
- package/pyatv/pyatv/py.typed +0 -0
- package/pyatv/pylintrc +49 -0
- package/pyatv/pyproject.toml +74 -0
- package/pyatv/requirements/requirements.txt +14 -0
- package/pyatv/requirements/requirements_docs.txt +2 -0
- package/pyatv/requirements/requirements_test.txt +20 -0
- package/pyatv/scripts/build_docs.sh +17 -0
- package/pyatv/scripts/setup_dev_env.sh +83 -0
- package/pyatv/setup.cfg +14 -0
- package/pyatv/tests/data/README +23 -0
- package/pyatv/tests/data/audio_10_frames.wav +0 -0
- package/pyatv/tests/data/audio_1_packet_metadata.wav +0 -0
- package/pyatv/tests/data/audio_3_packets.wav +0 -0
- package/pyatv/tests/data/only_metadata.wav +0 -0
- package/pyatv/tests/data/only_title.wav +0 -0
- package/pyatv/tests/data/static_3sec.ogg +0 -0
- package/pyatv/tests/data/testfile.txt +1 -0
- package/pyatv/tests/support/pyatv.code-workspace +14 -0
- package/src/index.ts +122 -8
- package/src/mdns.ts +64 -11
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: template
|
|
3
|
+
title: Internals
|
|
4
|
+
permalink: /internals/
|
|
5
|
+
link_group: internals
|
|
6
|
+
---
|
|
7
|
+
# :microscope: Table of Contents
|
|
8
|
+
{:.no_toc}
|
|
9
|
+
* TOC
|
|
10
|
+
{:toc}
|
|
11
|
+
|
|
12
|
+
# Internals
|
|
13
|
+
|
|
14
|
+
Welcome to the developer documentation for pyatv, i.e. the documentation explaining how
|
|
15
|
+
pyatv works (internally) and how to extend it. This section used to reside in the
|
|
16
|
+
GitHub wiki, but has moved to the general documentation for greater availability. It is
|
|
17
|
+
still under heavy development, so beware of missing and/or outdated content as it is
|
|
18
|
+
migrated from the wiki.
|
|
19
|
+
|
|
20
|
+
# Setting up a New Environment
|
|
21
|
+
|
|
22
|
+
## Linux/macOS/*NIX
|
|
23
|
+
|
|
24
|
+
You can run the script `scripts/setup_dev_env.sh` to set up a complete development environment. It will make sure that everything works as expected by running `chickn`, building documentation (with docker), etc.
|
|
25
|
+
|
|
26
|
+
```shell
|
|
27
|
+
$ ./scripts/setup_dev_env.sh
|
|
28
|
+
$ ./scripts/chickn.py
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Windows
|
|
32
|
+
|
|
33
|
+
There's no helper script for windows, but you can get started manually like this:
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
$ git clone https://github.com/postlund/pyatv.git
|
|
37
|
+
$ cd pyatv
|
|
38
|
+
$ python3 -m venv venv
|
|
39
|
+
$ source venv/Scripts/activate
|
|
40
|
+
$ python setup.py develop
|
|
41
|
+
$ pip install pyyaml -r requirements/requirements_test.txt -r requirements/requirements_docs.txt
|
|
42
|
+
$ python scripts/chickn.py
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
# Testing Changes
|
|
46
|
+
|
|
47
|
+
If you followed the instructions above, then pyatv will be installed as "develop". This means that you can keep doing updates without having to do `python setup.py install` between changes.
|
|
48
|
+
|
|
49
|
+
## Testing with chickn
|
|
50
|
+
|
|
51
|
+
To test everything, just run `./scripts/chickn.py`:
|
|
52
|
+
|
|
53
|
+
```shell
|
|
54
|
+
$ ./scripts/chickn.py
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This will make sure that tests pass, you have followed coding guidelines (pylint, flake8, etc), verify protobuf messages and generate coverage data. `chickn` is developed for pyatv and the documentation for it is
|
|
58
|
+
[here](tools/#chickn). The configuration file is [here](https://github.com/postlund/pyatv/blob/master/pyatv/chickn.yaml)
|
|
59
|
+
|
|
60
|
+
You can run steps individually as well:
|
|
61
|
+
|
|
62
|
+
| What | Command |
|
|
63
|
+
| ---- | ------- |
|
|
64
|
+
| tests | ./scripts/chickn.py pytest
|
|
65
|
+
| pylint | ./scripts/chickn.py pylint
|
|
66
|
+
| protobuf | ./scripts/chickn.py protobuf
|
|
67
|
+
| api | ./scripts/chickn.py api
|
|
68
|
+
|
|
69
|
+
All available steps can be listed with `./scripts/chickn.py -l`:
|
|
70
|
+
|
|
71
|
+
```raw
|
|
72
|
+
$ ./scripts/chickn.py -l
|
|
73
|
+
clean, fixup, pylint, api, protobuf, flake8, black, pydocstyle, isort, cs_docs, cs_code, typing, pytest, report, dist
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `fixup` will run black and isort to clean up basic mistakes before running rest of the commands.
|
|
77
|
+
So it can be convenient to enable that step with the `fixup` tag:
|
|
78
|
+
|
|
79
|
+
```raw
|
|
80
|
+
./scripts/chickn.py -t fixup
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Generally, `chickn` will install the latest version of all dependencies. There's however a
|
|
84
|
+
wish to verify that everything works the lowest version that pyatv supports. This is denoted
|
|
85
|
+
as "regression" in GitHub actions. These versions are listed in {% include code file="../base_versions.txt" %}
|
|
86
|
+
and can be manually overridden when needed:
|
|
87
|
+
|
|
88
|
+
```raw
|
|
89
|
+
$ ./scripts/chickn.py -v requirements_file=base_versions.txt
|
|
90
|
+
2021-10-24 11:16:19 [INFO] Installing dependencies
|
|
91
|
+
2021-10-24 11:16:19 [INFO] Re-installing packages with mismatching versions: aiohttp==3.1.0 (3.7.4), bitarray==2.1.2 (2.3.4), cryptography==2.6 (35.0.0), netifaces==0.10.0 (0.11.0), protobuf==3.18.0 (3.19.0), srptools==0.2.0 (1.0.1), zeroconf==0.28.2 (0.36.8)
|
|
92
|
+
...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
You generally do not need to do this yourself as it is tested automatically by GitHub Actions.
|
|
96
|
+
|
|
97
|
+
## Updating protobuf Definitions
|
|
98
|
+
|
|
99
|
+
If you have made changes to the protobuf messages in `pyatv/mrp/protobuf`, you can make sure everything is updated by running:
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
$ ./scripts/protobuf.py --download generate
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
See [Protobuf](tools#protobuf) for more details.
|
|
106
|
+
|
|
107
|
+
## Running Tests
|
|
108
|
+
|
|
109
|
+
Recommended way to run unit tests:
|
|
110
|
+
|
|
111
|
+
```shell
|
|
112
|
+
$ pytest --log-level=debug --disable-warnings
|
|
113
|
+
$ ./scripts/chickn.py pytests # Can be run via chickn
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Warnings are disabled because of deprecated `loop` argument in lots of places. This flag will be lifted eventually. See [Testing](testing) for details regarding tests.
|
|
117
|
+
|
|
118
|
+
## Re-formatting code
|
|
119
|
+
|
|
120
|
+
All python code is formatted using [black](https://github.com/psf/black), so you don't have to care about how the code looks. Just let black take care of it:
|
|
121
|
+
|
|
122
|
+
```shell
|
|
123
|
+
$ black .
|
|
124
|
+
All done! ✨ 🍰 ✨
|
|
125
|
+
77 files left unchanged.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Code formatting is checked by `chickn`, so it's not possible to check in code if it doesn't comply with black.
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
**NB: This step currently requires docker and is only tested on Linux!**
|
|
133
|
+
|
|
134
|
+
To serve a local running web server that performs incremental updates of the documentation,
|
|
135
|
+
run:
|
|
136
|
+
|
|
137
|
+
```shell
|
|
138
|
+
$ ./scripts/build_doc.sh
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Navigate to [http://localhost:4000](http://localhost:4000) to see the result.
|
|
142
|
+
|
|
143
|
+
The `cs_docs` step (`./scripts/chickn.py cs_docs`) will do basic spell checking of the documentation
|
|
144
|
+
using [codespell](https://github.com/codespell-project/codespell).
|
|
145
|
+
|
|
146
|
+
# Cheat Sheet
|
|
147
|
+
|
|
148
|
+
Here are a few convenient commands in short form:
|
|
149
|
+
|
|
150
|
+
| Command | What
|
|
151
|
+
| ------- | ----
|
|
152
|
+
| pytest --disable-warnings --log-level=debug -k XXX | Run tests matching XXX
|
|
153
|
+
| black . | Re-format code with black
|
|
154
|
+
| ./scripts/protobuf.py --download generate | Update protobuf definitions
|
|
155
|
+
| ./scripts/build_doc.sh | Serve web server with documentation at [http://127.0.0.1:4000](http://127.0.0.1:4000)
|
|
156
|
+
| ./scripts/api.sh generate | Update generate API `documentation in docs/api`
|
|
157
|
+
| ./scripts/features.sh | Generate `pyatv.const.FeatureName` (you need to copy-paste it) and print next free index
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: template
|
|
3
|
+
title: Submit a PR
|
|
4
|
+
permalink: /internals/submit-pr
|
|
5
|
+
link_group: internals
|
|
6
|
+
---
|
|
7
|
+
# :star: Submit a PR
|
|
8
|
+
|
|
9
|
+
* Fork this repository
|
|
10
|
+
* Make changes and push to fork
|
|
11
|
+
* Make sure that tests, linting, etc. pass by running `chickn` locally
|
|
12
|
+
* New code shall have [type hints](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)
|
|
13
|
+
* Update documentation if needed
|
|
14
|
+
* PR cannot be merged if any check in `chickn` fails
|
|
15
|
+
* Open a new PR
|
|
16
|
+
* If you are fixing a bug, please reference it with "Fixes #xxx" (alternatively "Relates
|
|
17
|
+
to #xxx") in commit message or pull request message to connect them
|
|
18
|
+
* Prefix the commit message with a topic, see [topics](#topics)
|
|
19
|
+
* Await review comments
|
|
20
|
+
* Fix potential comments
|
|
21
|
+
* Wait for PR to be merged
|
|
22
|
+
|
|
23
|
+
## Topics
|
|
24
|
+
|
|
25
|
+
To make it easier to see where a commit makes changes, add a prefix topic to the commit message. Here are a few topics that are used (suggest new if necessary):
|
|
26
|
+
|
|
27
|
+
| Topic | What/where you have changed |
|
|
28
|
+
| ----- | --------------------------- |
|
|
29
|
+
| airplay | Something related to `AirPlay`, likely in {% include code file="airplay" %}.
|
|
30
|
+
| companion | Something related to `Companion`, likely in {% include code file="companion" %}.
|
|
31
|
+
| cq | Code Quality, e.g, clean ups, added documentation, refactoring.
|
|
32
|
+
| docs | Documentation in `docs`.
|
|
33
|
+
| gha | GitHub Actions (`.github/workflows`).
|
|
34
|
+
| dmap | Something related to `DMAP`, likely in {% include code file="dmap" %}.
|
|
35
|
+
| if | Interface related changes (e.g. {% include code file="interface.py" %}).
|
|
36
|
+
| mrp | Something related to `MRP`, likely in {% include code file="mrp" %}.
|
|
37
|
+
| raop | Something related to `RAOP`, likely in {% include code file="raop" %}.
|
|
38
|
+
| scan | Scanning related code, likely {% include code file="support/scan.py" %}.
|
|
39
|
+
|
|
40
|
+
Try so split changes over multiple commits if possible, to keep them small (e.g. one for adding interface, one for implementing `MRP`, one for `DMAP` and one for documentation).
|
|
41
|
+
|
|
42
|
+
Some examples of first lines in commit messages:
|
|
43
|
+
|
|
44
|
+
```raw
|
|
45
|
+
cq: Add typing hints to public interface
|
|
46
|
+
if: Add interface for device information
|
|
47
|
+
raop: Send feedback if supported by receiver
|
|
48
|
+
test: Migrate from asynctest to pytest-asyncio
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
# Known Issues
|
|
52
|
+
|
|
53
|
+
There are currently two known issues with GitHub Actions:
|
|
54
|
+
|
|
55
|
+
* pytest sometimes fails with an "internal error". Reason is still unknown, restart jobs until it succeeds.
|
|
56
|
+
* pip sometimes fails due to files being broken (bad CRC or BadGzipFile), not sure how to fix that
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: template
|
|
3
|
+
title: Testing
|
|
4
|
+
permalink: /internals/testing
|
|
5
|
+
link_group: internals
|
|
6
|
+
---
|
|
7
|
+
# :ok_hand: Table of Contents
|
|
8
|
+
{:.no_toc}
|
|
9
|
+
* TOC
|
|
10
|
+
{:toc}
|
|
11
|
+
|
|
12
|
+
# Testing
|
|
13
|
+
|
|
14
|
+
Testing is an important part of pyatv and there are a lots of tests. The intention is not to have full test coverage, i.e. 100% line coverage (since branch coverage is not supported). The reasoning behind this is that it costs too much when it comes to maintaining the tests and the benefits too low. This does *not* mean that it is OK to not test, it just means that some parts might be easier to inspect manually rather than writing tests for. If the code is easy to test, it should be tested!
|
|
15
|
+
|
|
16
|
+
*NB: Tests are being re-written to `pytest`-like tests, instead of using regular `unittest` tests. You might see a mix of variants until the work is done, see [#443](https://github.com/postlund/pyatv/issues/443).*
|
|
17
|
+
|
|
18
|
+
# Running Tests
|
|
19
|
+
|
|
20
|
+
For running tests, please see [Development Environment](Development-Environment#testing-changes).
|
|
21
|
+
|
|
22
|
+
# Test Structure
|
|
23
|
+
|
|
24
|
+
All tests reside in `tests` and follow the same structure as in the code directory (`pyatv/`). `AirPlay` tests can for instance be found in `tests/airplay`. Most tests are regular unit tests, but there are also functional tests that tests pyatv on interface level (see [Types of Tests](#types-of-tests) for more details). They have `functional` in their file names:
|
|
25
|
+
|
|
26
|
+
| File name | Test Suite |
|
|
27
|
+
| --------- | ---------- |
|
|
28
|
+
| `tests/common_functional_tests.py` | Common tests that are *identical* to all protocols (i.e. inherited)
|
|
29
|
+
| `tests/companion/test_companion_functional.py` | Functional tests for `Companion`
|
|
30
|
+
| `tests/dmap/test_dmap_functional.py` | Functional tests for `DMAP`
|
|
31
|
+
| `tests/mrp/test_mrp_functional.py` | Functional tests for `MRP`
|
|
32
|
+
| `tests/raop/test_raop_functional.py` | Functional tests for `RAOP`
|
|
33
|
+
| `tests/support/test_mdns_functional.py` | Functional tests for MDNS
|
|
34
|
+
| `tests/test_scan_functional.py` | Functional tests for scanning routines
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Generally, if something protocol specific is to be tested it should be added to the protocol specific test suite. But ideally, as many test cases as possible should be added to `common_functional_tests.py` as this will make sure the interface is identical for all protocols.
|
|
39
|
+
|
|
40
|
+
## Fake Device and Usecases
|
|
41
|
+
|
|
42
|
+
Testing on interface level, i.e. using the same interface as a developer using pyatv would, comes with the big benefit of flexibility. It allows for great freedom when changing code internally within pyatv without breaking a lot of tests, so that is why these kinds of tests are preferred. They are called *functional tests* in this context. Some details are however hard to test using functional tests, so unit tests can be used in those cases.
|
|
43
|
+
|
|
44
|
+
For functional tests to work, pyatv needs something to connect to. For this reason a *fake device* is used. It acts like a real devices, but takes a lot of shortcus, implement limited functionality and are only meant to be compatible with pyatv (for now). The fake device starts web servers or open TCP ports, depending on what the protocol uses and the test then sets everything up and connects to it. It short, it looks a bit like this:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
async def setUpAsync(self):
|
|
48
|
+
await super().setUpAsync()
|
|
49
|
+
self.conf = AppleTV(IPv4Address("127.0.0.1"), "Test device")
|
|
50
|
+
self.conf.add_service(
|
|
51
|
+
MrpService("mrp_id", self.fake_atv.get_port(Protocol.MRP))
|
|
52
|
+
)
|
|
53
|
+
self.conf.add_service(
|
|
54
|
+
AirPlayService("airplay_id", self.server.port, DEVICE_CREDENTIALS)
|
|
55
|
+
)
|
|
56
|
+
self.atv = await self.get_connected_device()
|
|
57
|
+
|
|
58
|
+
async def get_application(self, loop=None):
|
|
59
|
+
self.fake_atv = FakeAppleTV(self.loop)
|
|
60
|
+
self.state, self.usecase = self.fake_atv.add_service(Protocol.MRP)
|
|
61
|
+
self.airplay_state, self.airplay_usecase = self.fake_atv.add_service(
|
|
62
|
+
Protocol.AirPlay
|
|
63
|
+
)
|
|
64
|
+
return self.fake_atv.app
|
|
65
|
+
|
|
66
|
+
async def get_connected_device(self):
|
|
67
|
+
return await pyatv.connect(self.conf, loop=self.loop)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The fake device is assigned to `self.fake_atv` and can be used to for instance get some internal state, like the last pressed button. Notice that `pyatv.connect` is used to connect to it. Also notice that scanning is not tested by the functional tests. There are other tests, that stubs zeroconf, for that.
|
|
71
|
+
|
|
72
|
+
Another concept that is introduced here is `usecase`. A usecase is used to alter the state of a fake device, with some level of abstraction. So instead of modifying the fake device directly, a usecase can be used to for instance change what is currently playing:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
@unittest_run_loop
|
|
76
|
+
async def test_metadata_video_paused(self):
|
|
77
|
+
self.usecase.video_playing(
|
|
78
|
+
paused=True, title="dummy", total_time=100, position=3
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
with faketime("pyatv", 0):
|
|
82
|
+
playing = await self.playing(title="dummy")
|
|
83
|
+
self.assertEqual(playing.media_type, MediaType.Video)
|
|
84
|
+
self.assertEqual(playing.device_state, DeviceState.Paused)
|
|
85
|
+
self.assertEqual(playing.title, "dummy")
|
|
86
|
+
self.assertEqual(playing.total_time, 100)
|
|
87
|
+
self.assertEqual(playing.position, 3)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Here the fake device is configured to play video with some properties set. The properties are then fetched via the public interface and verified. There are other usecases as well, just look at the implementations. Keeping this abstractions makes it a lot easier to write tests that are shared amongst protocol and is also easier to read. Please note that there's currently no explicit usecase "interface", so it's tricky to see which usescases are shared between all protocols. This would be nice to improve in the future...
|
|
91
|
+
|
|
92
|
+
Previously one fake device existed per protocol. This has been changed to one fake device that can support multiple services (protocols) instead. To add a service to a fake device, call `add_service`. The state and usecase object for that service will be returned.
|
|
93
|
+
|
|
94
|
+
Also, there are two new concepts introduced here: polling for a state (`await self.playing(...)`) and `faketime`. These are covered next.
|
|
95
|
+
|
|
96
|
+
## Illustration of Functional Tests
|
|
97
|
+
|
|
98
|
+
Here is a simple illustration of how to think of a functional test case:
|
|
99
|
+
|
|
100
|
+
```raw
|
|
101
|
+
+-----------------+ +-----------------------+
|
|
102
|
+
| | video_playing | |
|
|
103
|
+
| Test case |--------------->| AppleTVUseCases |
|
|
104
|
+
| | | |
|
|
105
|
+
+--------+--------+ +-----------------------+
|
|
106
|
+
^ |
|
|
107
|
+
| metadata.playing() |
|
|
108
|
+
v |
|
|
109
|
+
+-------------+ |
|
|
110
|
+
| | |
|
|
111
|
+
| pyatv | |
|
|
112
|
+
| | |
|
|
113
|
+
+-------------+ |
|
|
114
|
+
^ |
|
|
115
|
+
| DMAP/AirPlay/MRP/... |
|
|
116
|
+
v |
|
|
117
|
+
+-------------------+ |
|
|
118
|
+
| | configure video |
|
|
119
|
+
| FakeAppleTV |<--------------------------+
|
|
120
|
+
| |
|
|
121
|
+
+-------------------+
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Polling Active State
|
|
125
|
+
|
|
126
|
+
Because the fake devices uses regular communication protocols, like TCP and HTTP, there are delays in the system. It takes time for messages to be exchanged and everything to be updated correctly, so it's not always possible to assert values like in normal unit tests. Because of this the tests will have to poll the fake device until some expected state is reached. Here is an example:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
@unittest_run_loop
|
|
130
|
+
async def test_button_up(self):
|
|
131
|
+
await self.atv.remote_control.up()
|
|
132
|
+
await until(lambda: self.fake_atv.last_button_pressed == "up")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `up` button is pressed and `self.fake_atv.last_button_pressed` is polled using `await until`, until the correct button is set. The `until` function just calls the provided function until it returns `True`, with a short sleep between each call and a timeout (5s). There's also a convenience method for polling the playing state:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
@unittest_run_loop
|
|
139
|
+
async def test_seek_in_playing_media(self):
|
|
140
|
+
self.usecase.video_playing(
|
|
141
|
+
paused=False, title="dummy", total_time=40, position=10
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
with faketime("pyatv", 0):
|
|
145
|
+
await self.atv.remote_control.set_position(30)
|
|
146
|
+
playing = await self.playing(position=30)
|
|
147
|
+
self.assertEqual(playing.position, 30)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Awaiting `self.playing` will continue fetching `self.atv.metadata.playing` and verify that all the provided properties have the specified value. Here, it will continue to poll until `position` is set to 30. The corresponding `interface.Playing` object with all information is returned to simplify further investigation.
|
|
151
|
+
|
|
152
|
+
## Fake Time
|
|
153
|
+
|
|
154
|
+
Due to `MRP` using real time to calculate current position, time has to be faked. Basically current position is calculated according to `current_time - time_when_something_started_to_play`. I will have to do a better write-up here later, but just use `with faketime("pyatv", 0):` and you'll be fine...
|
|
155
|
+
|
|
156
|
+
# Types of Tests
|
|
157
|
+
|
|
158
|
+
Summary of types of tests in pyatv.
|
|
159
|
+
|
|
160
|
+
## Unit Tests
|
|
161
|
+
|
|
162
|
+
For simple standalone modules, consider writing unit tests. Write them `pytest`-style. You can then just write some functional tests when integrating it (usually one or a few is enough), to make sure it works with rest of pyatv.
|
|
163
|
+
|
|
164
|
+
## Functional Tests
|
|
165
|
+
|
|
166
|
+
When adding features, focus on adding testing on interface level, i.e. write *functional tests*. In the functional tests and extend the fake device to support whatever function you need. The
|
|
167
|
+
test case will automatically set the fake device up and make pyatv connect to it, so you can access the public interface. A simple test case might look like this:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
@unittest_run_loop
|
|
171
|
+
async def test_button_previous(self):
|
|
172
|
+
await self.atv.remote_control.previous()
|
|
173
|
+
await until(lambda: self.fake_atv.last_button_pressed == "previtem")
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The `previous` button is called with pyatv and the fake device is polled until the button is pressed. Polling is needed because communication is done over TCP, just like with a real device. So it takes some time before the event loop has processed everything. More on this later.
|