class OMXPlayerTests(unittest.TestCase): TEST_FILE_NAME = "./test.mp4" TEST_URL = "rtmp://192.168.0.1/live/mystream" def test_opens_file_in_omxplayer(self, popen, *args): self.patch_and_run_omxplayer() devnull = MOCK_OPEN() popen.assert_called_once_with(['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=devnull, stdout=devnull) @patch('time.sleep') def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args): # TODO: Shouldn't this be DBusConnectionError not SystemError with self.assertRaises(SystemError): dbus_connection = Mock(side_effect=DBusConnectionError) self.patch_and_run_omxplayer(Connection=dbus_connection) self.assertEqual(50, self.player.tries) def test_dbus_failure_kills(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process dbus_connection = Mock(side_effect=DBusConnectionError) with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): with self.assertRaises(SystemError): self.patch_and_run_omxplayer(Connection=dbus_connection) killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_thread_failure_kills(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process with patch('threading.Thread', Mock(side_effect=RuntimeError)): with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): with self.assertRaises(RuntimeError): self.patch_and_run_omxplayer() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) @parameterized.expand([['can_quit', 'CanQuit', [], []], ['can_set_fullscreen', 'CanSetFullscreen', [], []], ['identity', 'Identity', [], []]]) def test_root_interface_properties(self, popen, sleep, isfile, killpg, atexit, command_name, property_name, command_args, expected_dbus_call_args): self.patch_and_run_omxplayer() self.player._root_interface.dbus_interface = "org.mpris.MediaPlayer2" interface = self.player._properties_interface interface.reset_mock() self.patch_interface_and_run_command(command_name, command_args) expected_call = call.Get("org.mpris.MediaPlayer2", property_name, *expected_dbus_call_args) interface.assert_has_calls([expected_call]) @parameterized.expand( [['pause', 'Pause', [], []], ['stop', 'Stop', [], []], ['seek', 'Seek', [100], [dbus.Int64(100 * 1e6)]], [ 'set_position', 'SetPosition', [1], [dbus.ObjectPath("/not/used"), dbus.Int64(1000000)] ], ['set_layer', 'SetLayer', [1], [dbus.Int64(1)]], ['list_subtitles', 'ListSubtitles', [], []], ['mute', 'Mute', [], []], ['unmute', 'Unmute', [], []], ['action', 'Action', ['p'], ['p']]]) def test_player_interface_commands(self, popen, sleep, isfile, killpg, atexit, command_name, interface_command_name, command_args, expected_dbus_call_args): self.patch_and_run_omxplayer() self.player._player_interface.dbus_interface = "org.mpris.MediaPlayer2" interface = self.player._player_interface interface.reset_mock() self.patch_interface_and_run_command(command_name, command_args) expected_call = getattr( call, interface_command_name)(*expected_dbus_call_args) interface.assert_has_calls([expected_call]) @parameterized.expand([ ['can_play', 'CanPlay', True, dbus.Boolean(True)], ['can_seek', 'CanSeek', False, dbus.Boolean(False)], ['can_control', 'CanControl', True, dbus.Boolean(True)], [ 'playback_status', 'PlaybackStatus', "playing", dbus.String("playing") ], ['position', 'Position', 1.2, dbus.Int64(1.2 * 1000 * 1000)], ['duration', 'Duration', 10.1, dbus.Int64(10.1 * 1000 * 1000)], ['volume', 'Volume', 10, dbus.Int64(10)], ['minimum_rate', 'MinimumRate', 0.1, dbus.Double(0.1)], ['maximum_rate', 'MaximumRate', 4.0, dbus.Double(4.0)], ]) def test_player_interface_properties(self, popen, sleep, isfile, killpg, atexit, command_name, property_name, expected_result, property_result): interface_address = "org.mpris.MediaPlayer2" self.patch_and_run_omxplayer() self.player._root_interface.dbus_interface = interface_address interface = self.player._properties_interface interface.reset_mock() mock = interface.Get mock.configure_mock(return_value=property_result) result = self.patch_interface_and_run_command(command_name, []) interface.assert_has_calls([(call.Get(interface_address, property_name))]) self.assertEqual(expected_result, result) def test_quitting(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.player.quit() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_quitting_waits_for_omxplayer_to_die(self, popen, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid'): self.player.quit() omxplayer_process.wait.assert_has_calls([call()]) def test_quitting_when_already_dead(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() # Pretend the process is already dead killpg.configure_mock(side_effect=OSError) with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): # This tests that quit handles the OSError self.player.quit() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_quitting_twice(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): # This should not raise, and call killpg once self.player.quit() self.player.quit() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_check_process_still_exists_before_dbus_call(self, *args): self.patch_and_run_omxplayer() self.player._process = process = Mock(return_value=None) process.poll.return_value = None self.player.can_quit() process.poll.assert_called_once_with() def test_stop_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.stopEvent += callback self.player.stop() callback.assert_called_once_with(self.player) def test_play_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.play() callback.assert_called_once_with(self.player) def test_pause_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.pause() callback.assert_called_once_with(self.player) def test_play_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.pause() # play self.player.play_pause() callback.assert_called_once_with(self.player) def test_pause_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.play() # pause self.player.play_pause() callback.assert_called_once_with(self.player) def test_seek_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.seekEvent += callback self.player.seek(3.4) callback.assert_called_once_with(self.player, 3.4) def test_position_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.positionEvent += callback self.player.set_position(5.01) callback.assert_called_once_with(self.player, 5.01) def patch_interface_and_run_command(self, command_name, command_args): self.player._process.poll = Mock(return_value=None) result = getattr(self.player, command_name)(*command_args) return result # Must have the prefix 'patch' for the decorators to take effect def patch_and_run_omxplayer(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_URL, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def test_load(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.patch_and_run_omxplayer(active=True) # initial load self.assertEqual(self.player.get_filename(), './test.mp4') killpg.assert_not_called() popen.assert_called_once_with(['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=MOCK_OPEN(), stdout=MOCK_OPEN()) # load new video in same OMXPlayer instance self.player.load('./test2.mp4') # verify new video is registered in OMXPlayer self.assertEqual(self.player.get_filename(), './test2.mp4') # verify omxplayer process for previous video was killed killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) # verify a new process was started for the second time self.assertEqual(popen.call_count, 2) def test_init_without_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.assertEqual(pause_method.call_count, 0) def test_init_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: # self.patch_and_run_omxplayer(pause=False) bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Mock(), pause=True) self.assertEqual(pause_method.call_count, 1) def test_load_and_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4', pause=True) self.assertEqual(pause_method.call_count, 1) def test_load_without_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4') self.assertEqual(pause_method.call_count, 0) def test_register_quit_handler_atexit(self, popen, sleep, isfile, killpg, atexit): self.patch_and_run_omxplayer() atexit.assert_called_once_with(self.player.quit)
class OMXPlayerTests(unittest.TestCase): TEST_FILE_NAME = "./test.mp4" TEST_URL = "rtmp://192.168.0.1/live/mystream" def test_opens_file_in_omxplayer(self, popen, *args): self.patch_and_run_omxplayer() devnull = MOCK_OPEN() popen.assert_called_once_with( ['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=devnull, stdout=devnull) @patch('time.sleep') def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args): # TODO: Shouldn't this be DBusConnectionError not SystemError with self.assertRaises(SystemError): dbus_connection = Mock(side_effect=DBusConnectionError) self.patch_and_run_omxplayer(Connection=dbus_connection) self.assertEqual(50, self.player.tries) @parameterized.expand([ ['can_quit', 'CanQuit', [], []], ['can_set_fullscreen', 'CanSetFullscreen', [], []], ['identity', 'Identity', [], []] ]) def test_root_interface_properties(self, popen, sleep, isfile, killpg, atexit, command_name, property_name, command_args, expected_dbus_call_args): self.patch_and_run_omxplayer() self.player._root_interface.dbus_interface = "org.mpris.MediaPlayer2" interface = self.player._properties_interface interface.reset_mock() self.patch_interface_and_run_command(command_name, command_args) expected_call = call.Get("org.mpris.MediaPlayer2", property_name, *expected_dbus_call_args) interface.assert_has_calls([expected_call]) @parameterized.expand([ ['pause', 'Pause', [], []], ['stop', 'Stop', [], []], ['seek', 'Seek', [100], [dbus.Int64(100 * 1e6)]], ['set_position', 'SetPosition', [1], [dbus.ObjectPath("/not/used"), dbus.Int64(1000000)]], ['list_subtitles', 'ListSubtitles', [], []], ['mute', 'Mute', [], []], ['unmute', 'Unmute', [], []], ['action', 'Action', ['p'], ['p']] ]) def test_player_interface_commands(self, popen, sleep, isfile, killpg, atexit, command_name, interface_command_name, command_args, expected_dbus_call_args): self.patch_and_run_omxplayer() self.player._player_interface.dbus_interface = "org.mpris.MediaPlayer2" interface = self.player._player_interface interface.reset_mock() self.patch_interface_and_run_command(command_name, command_args) expected_call = getattr(call, interface_command_name)(*expected_dbus_call_args) interface.assert_has_calls([expected_call]) @parameterized.expand([ ['can_play', 'CanPlay', True, dbus.Boolean(True)], ['can_seek', 'CanSeek', False, dbus.Boolean(False)], ['can_control', 'CanControl', True, dbus.Boolean(True)], ['playback_status', 'PlaybackStatus', "playing", dbus.String("playing")], ['position', 'Position', 1.2, dbus.Int64(1.2 * 1000 * 1000)], ['duration', 'Duration', 10.1, dbus.Int64(10.1 * 1000 * 1000)], ['volume', 'Volume', 10, dbus.Int64(10)], ['minimum_rate', 'MinimumRate', 0.1, dbus.Double(0.1)], ['maximum_rate', 'MaximumRate', 4.0, dbus.Double(4.0)], ]) def test_player_interface_properties(self, popen, sleep, isfile, killpg, atexit, command_name, property_name, expected_result, property_result): interface_address = "org.mpris.MediaPlayer2" self.patch_and_run_omxplayer() self.player._root_interface.dbus_interface = interface_address interface = self.player._properties_interface interface.reset_mock() mock = interface.Get mock.configure_mock(return_value=property_result) result = self.patch_interface_and_run_command(command_name, []) interface.assert_has_calls([(call.Get(interface_address, property_name))]) self.assertEqual(expected_result, result) def test_quitting(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.player.quit() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_quitting_waits_for_omxplayer_to_die(self, popen, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid'): self.player.quit() omxplayer_process.wait.assert_has_calls([call()]) def test_check_process_still_exists_before_dbus_call(self, *args): self.patch_and_run_omxplayer() self.player._process = process = Mock(return_value=None) process.poll.return_value = None self.player.can_quit() process.poll.assert_called_once_with() def test_stop_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.stopEvent += callback self.player.stop() callback.assert_called_once_with(self.player) def test_play_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.play() callback.assert_called_once_with(self.player) def test_pause_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.pause() callback.assert_called_once_with(self.player) def test_play_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.pause() # play self.player.play_pause() callback.assert_called_once_with(self.player) def test_pause_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.play() # pause self.player.play_pause() callback.assert_called_once_with(self.player) def test_seek_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.seekEvent += callback self.player.seek(3.4) callback.assert_called_once_with(self.player, 3.4) def test_position_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.positionEvent += callback self.player.set_position(5.01) callback.assert_called_once_with(self.player, 5.01) def patch_interface_and_run_command(self, command_name, command_args): self.player._process.poll = Mock(return_value=None) result = getattr(self.player, command_name)(*command_args) return result # Must have the prefix 'patch' for the decorators to take effect def patch_and_run_omxplayer(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_URL, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def test_load(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.patch_and_run_omxplayer(active=True) # initial load self.assertEqual(self.player.get_filename(), './test.mp4') killpg.assert_not_called() popen.assert_called_once_with(['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=MOCK_OPEN(), stdout=MOCK_OPEN()) # load new video in same OMXPlayer instance self.player.load('./test2.mp4') # verify new video is registered in OMXPlayer self.assertEqual(self.player.get_filename(), './test2.mp4') # verify omxplayer process for previous video was killed killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) # verify a new process was started for the second time self.assertEqual(popen.call_count, 2) def test_init_without_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.assertEqual(pause_method.call_count, 0) def test_init_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: # self.patch_and_run_omxplayer(pause=False) bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Mock(), pause=True) self.assertEqual(pause_method.call_count, 1) def test_load_and_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4', pause=True) self.assertEqual(pause_method.call_count, 1) def test_load_without_pause(self, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4') self.assertEqual(pause_method.call_count, 0) def test_register_quit_handler_atexit(self, popen, sleep, isfile, killpg, atexit): self.patch_and_run_omxplayer() atexit.assert_called_once_with(self.player.quit)
class OMXPlayerTests(unittest.TestCase): TEST_FILE_NAME = "./test.mp4" TEST_URL = "rtmp://192.168.0.1/live/mystream" def test_opens_file_in_omxplayer(self, popen, *args): self.patch_and_run_omxplayer() devnull = MOCK_OPEN() popen.assert_called_once_with( ['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=devnull, stdout=devnull) @patch('time.sleep') def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args): # TODO: Shouldn't this be DBusConnectionError not SystemError with self.assertRaises(SystemError): dbus_connection = Mock(side_effect=DBusConnectionError) self.patch_and_run_omxplayer(Connection=dbus_connection) self.assertEqual(50, self.player.tries) @parameterized.expand([ ['can_quit', 'CanQuit', [], []], ['can_set_fullscreen', 'CanSetFullscreen', [], []], ['identity', 'Identity', [], []] ]) def test_root_interface_commands(self, popen, sleep, isfile, killpg, command_name, interface_command_name, *args): self.patch_and_run_omxplayer() self.patch_interface_and_run_command('_get_root_interface', command_name, interface_command_name, *args) @parameterized.expand([ ['pause', 'Pause', [], []], ['stop', 'Stop', [], []], ['seek', 'Seek', [100], [100]], ['set_position', 'SetPosition', [1], [dbus.ObjectPath("/not/used"), dbus.Int64(1000000)]], ['list_subtitles', 'ListSubtitles', [], []], ['action', 'Action', ['p'], ['p']] ]) def test_player_interface_commands(self, popen, sleep, isfile, killpg, command_name, interface_command_name, *args): self.patch_and_run_omxplayer() self.patch_interface_and_run_command('_get_player_interface', command_name, interface_command_name, *args) @parameterized.expand([ ['can_play', 'CanPlay', [], []], ['can_seek', 'CanSeek', [], []], ['can_control', 'CanControl', [], []], ['playback_status', 'PlaybackStatus', [], []], ['volume', 'Volume', [], []], ['mute', 'Mute', [], []], ['unmute', 'Unmute', [], []], ['position', 'Position', [], []], ['duration', 'Duration', [], []], ['minimum_rate', 'MinimumRate', [], []], ['maximum_rate', 'MaximumRate', [], []], ]) def test_properties_interface_commands(self, popen, sleep, isfile, killpg, command_name, interface_command_name, *args): self.patch_and_run_omxplayer() self.patch_interface_and_run_command('_get_properties_interface', command_name, interface_command_name, *args) def test_quitting(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.player.quit() killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) def test_quitting_waits_for_omxplayer_to_die(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process self.patch_and_run_omxplayer() with patch('os.getpgid'): self.player.quit() omxplayer_process.wait.assert_has_calls([call()]) def test_check_process_still_exists_before_dbus_call(self, *args): self.patch_and_run_omxplayer() self.player._process = process = Mock(return_value=None) process.poll.return_value = None self.player.can_quit() process.poll.assert_called_once_with() def test_checks_media_file_exists_before_launching_player(self, *args): with patch('os.path') as ospath: self.patch_and_run_omxplayer() ospath.isfile.assert_called_once_with(self.TEST_FILE_NAME) def test_player_doesnt_check_source_path_exists_for_a_url(self, *args): with patch('os.path') as ospath: self.patch_and_run_omxplayer_url() ospath.isfile.assert_not_called() def test_stop_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.stopEvent += callback self.player.stop() callback.assert_called_once_with(self.player) def test_play_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.play() callback.assert_called_once_with(self.player) def test_pause_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.pause() callback.assert_called_once_with(self.player) def test_play_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.playEvent += callback with patch.object(self.player, 'is_playing', return_value=False): self.player.pause() # play self.player.play_pause() callback.assert_called_once_with(self.player) def test_pause_event_by_play_pause(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.pauseEvent += callback with patch.object(self.player, 'is_playing', return_value=True): self.player.play() # pause self.player.play_pause() callback.assert_called_once_with(self.player) def test_seek_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.seekEvent += callback self.player.seek(3.4) callback.assert_called_once_with(self.player, 3.4) def test_position_event(self, *args): self.patch_and_run_omxplayer(active=True) callback = Mock() self.player.positionEvent += callback self.player.set_position(5.01) callback.assert_called_once_with(self.player, 5.01) def patch_interface_and_run_command(self, interface_name, command_name, interface_command_name, command_args, expected_args): self.player._process.poll = Mock(return_value=None) with patch.object(self.player, interface_name) as interface: self.run_command(command_name, *command_args) # generates a call of the form `call().CanQuit` expected_call = getattr(call(), interface_command_name)(*expected_args) interface.assert_has_calls([expected_call]) def run_command(self, command_name, *args): command = getattr(self.player, command_name) command(*args) # Must have the prefix 'patch' for the decorators to take effect def patch_and_run_omxplayer(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False): bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_URL, bus_address_finder=bus_address_finder, Connection=Connection) if active: self.player._process.poll = Mock(return_value=None) def test_load(self, popen, sleep, isfile, killpg, *args): omxplayer_process = Mock() popen.return_value = omxplayer_process with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)): self.patch_and_run_omxplayer(active=True) # initial load self.assertEqual(self.player.get_filename(), './test.mp4') killpg.assert_not_called() popen.assert_called_once_with(['omxplayer', './test.mp4'], preexec_fn=os.setsid, stdin=MOCK_OPEN(), stdout=MOCK_OPEN()) # load new video in same OMXPlayer instance self.player.load('./test2.mp4') # verify new video is registered in OMXPlayer self.assertEqual(self.player.get_filename(), './test2.mp4') # verify omxplayer process for previous video was killed killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM) # verify a new process was started for the second time self.assertEqual(popen.call_count, 2) def test_init_without_pause(self, popen, sleep, isfile, killpg, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method: self.patch_and_run_omxplayer() self.assertEqual(mock_method.call_count, 0) def test_init_pause(self, popen, sleep, isfile, killpg, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method: # self.patch_and_run_omxplayer(pause=False) bus_address_finder = Mock() bus_address_finder.get_address.return_val = "example_bus_address" self.player = OMXPlayer(self.TEST_FILE_NAME, bus_address_finder=bus_address_finder, Connection=Mock(), pause=True) self.assertEqual(mock_method.call_count, 1) def test_load_and_pause(self, popen, sleep, isfile, killpg, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4', pause=True) self.assertEqual(mock_method.call_count, 1) def test_load_without_pause(self, popen, sleep, isfile, killpg, *args): with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method: self.patch_and_run_omxplayer() self.player.load('./test2.mp4') self.assertEqual(mock_method.call_count, 0)
class Main: # Gobal Variable to store RFID reader strings and bools dataString = "" addRfidTag = False #Set debug logging parameters level = logging.DEBUG/ERROR/WARNING logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') #Define serialport and parameters - aotumate later or add to setings try: ultrasoundProbe = serial.Serial(port='/dev/ttyUSB0', baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) except Exception as e: logging.debug(e) #Add send command to device # To do # After the combo boxes have been initialized we set them to have the same selected value # as during the last run def load_settings(self, filename): try: pickle_file = open(filename, 'rb') list_import = pickle.load(pickle_file) self.list_store1.clear() for i in range(len(list_import)): logging.debug("item " + str(list_import[i])) self.list_store1.append(list_import[i]) pickle_file.close() except Exception as e: logging.debug(e) # Pickle the settings data for use in the next run def save_settings(self, filename): pickle_file = open(filename, 'wb') list_iter = self.list_store1.get_iter_root() list_dump = [] while (list_iter): tup = self.list_store1.get(list_iter, 0, 1, 2) list_dump.append(list(tup)) list_iter = self.list_store1.iter_next(list_iter) pickle.dump(list_dump, pickle_file) pickle_file.close() def gtk_main_quit(self, window): self.save_settings(sys.path[0] + "/settings.p") gtk.main_quit() def cb_quit(self, window, event): self.save_settings(sys.path[0] + "/settings.p") gtk.main_quit() def cb_about_press(self, window): response = self.about_dialog.run() self.about_dialog.hide() return response != 1 def cb_settings_press(self, window): self.set_add_rfid_tag_active(True) response = self.settings_dialog.run() self.settings_dialog.hide() if response == gtk.RESPONSE_DELETE_EVENT: self.set_add_rfid_tag_active(False) logging.debug("close event on settings press") return response != 1 def cb_add_scan_press(self, window): response = self.add_scan_dialog.run() self.add_scan_dialog.hide() return response != 1 def settings_cancel_clicked(self, window): self.set_add_rfid_tag_active(False) logging.debug("Set tag false on settings exit") def cb_add_scan_apply_clicked(self, window): new_name = self.name_entry.get_text() new_rfid = self.rfid_entry.get_text() new_filename = self.filechooser.get_filename() self.list_store1.append([new_name, new_rfid, new_filename]) return True # Callback to run when load settings button is pressed # Will open a window, prompt for files and update the filename variable def cb_load_settings_press(self, window): response = self.load_settings_filechooserdialog.run() self.load_settings_filechooserdialog.hide() if response == 1: self.load_settings( self.load_settings_filechooserdialog.get_filename()) return response != 1 # Callback to run when save settings button is pressed # Will open a window, prompt for files and update the filename variable def cb_save_settings_press(self, window): response = self.save_settings_filechooserdialog.run() self.save_settings_filechooserdialog.hide() if response == 1: self.save_settings( self.save_settings_filechooserdialog.get_filename()) return response != 1 # Opting to add a whole directory full of videos at once. def cb_quick_add_press(self, window): response = self.quick_add_dialog.run() self.quick_add_dialog.hide() return response != 1 def cb_quick_add_ok_press(self, window): # Get a list of all files in the directory quick_add_dir = self.filechooser_quick.get_filename() quick_add_files = os.listdir(quick_add_dir) # For each of the files in the directory we will try to add a scan for filename in quick_add_files: new_filename = quick_add_dir + '/' + filename new_name = filename self.quick_add_cur_filename.set_text(filename) # Need to grab the focus back into the text ectry box so every scan will end by prompting fo rthe next scan self.rfid_quick_entry.grab_focus() response = self.quick_add_item.run() # If OK was clicked (or the scan triggered the default action) if response == 1: new_rfid = self.rfid_quick_entry.get_text() self.list_store1.append([new_name, new_rfid, new_filename]) # The button was clicked, the default action is then to skip this file and read the next one elif response == 2: break # Blank the text entry box and get ready for new text self.rfid_quick_entry.set_text('') # The scan is done so hide the directory self.quick_add_item.hide() return True def cb_remove_scan_press(self, button): # Obtain selection sel = self.tree.get_selection() # If nothing is selected, return. if sel.count_selected_rows == 0: return # Get selected path (model, rows) = sel.get_selected_rows() for row in reversed(rows): iter1 = model.get_iter(row) model.remove(iter1) return #Messenger dialog box def message_dialog_show(self, message): self.message_dialog.set_property("text", message) response = self.message_dialog.run() self.message_dialog.hide() def on_key_press_event(self, widget, event): try: keyname = gtk.gdk.keyval_name(event.keyval) # Grab the letter q to stop the current movie if keyname == 'q' or keyname == 'Q': if (self.check_active_player()): self.player.quit() #Pause on spacebar if keyname == 'space': self.player.play_pause() #Strings from the reader end with a new line... so we take in all characters and process the last 10 on a newline if keyname == 'Return': rfid_string_scanned = self.dataString[-10::] self.dataString = '' except Exception as e: print(e) # Play video def play_video(self, filename): if self.check_active_player(): self.player.quit() print "Playing " + filename VIDEO_PATH = Path("" + filename + "") self.player = OMXPlayer(VIDEO_PATH, args=['-b']) # Catch exception if process is not running when checking activity def check_active_player(self): try: playerStatus = self.player.playback_status() if playerStatus == 'Playing' or playerStatus == 'Paused': return True except: return False print "Exception thrown on inactive player" # Callback for radio button def toggle_fs(self, widget, data=None): logging.debug("Fullscreen %s" % (("OFF", "ON")[widget.get_active()])) if widget.get_active(): self.mainWindow.fullscreen() else: self.mainWindow.unfullscreen() def listen_serial(self): try: if (self.ultrasoundProbe.inWaiting() > 0): s = '' s += self.ultrasoundProbe.read(16) self.ultrasoundProbe.flushInput() self.dataString = s if (self.addRfidTag): self.handle_rfid_tag_text() return True else: self.handle_video_playing() logging.debug(self.dataString) return True else: if self.check_active_player(): self.player.quit() logging.debug("No Tag in Range") return True except Exception as e: logging.debug(e) self.message_dialog_show(e) # Serial rfid tag to gui def handle_rfid_tag_text(self): rfid_string_scanned = self.dataString.strip() logging.debug(rfid_string_scanned) #Setting both add quick and add normal RFID fields to current read tag self.rfid_entry.set_text(rfid_string_scanned) self.rfid_quick_entry.set_text(rfid_string_scanned) self.dataString = '' # Continuously read rfid tags def handle_video_playing(self): logging.debug("read rfid for video playing") rfid_string_scanned = self.dataString.strip() logging.debug(rfid_string_scanned) self.dataString = '' # This code aims to check if the file is already playing so we don't continually start # the movie over if we are on the border of one of the tags # Need to check this sometimes, so always call it if self.check_active_player(): current_file = str(self.player.get_filename()) else: current_file = None #Search for the matching rfid string and play the associated file # Get the tree to iterate over list_iter = self.list_store1.get_iter_root() while (list_iter): rfid_entry = self.list_store1.get_value(list_iter, 1) rfid_entry = rfid_entry.strip() if rfid_entry == rfid_string_scanned: filename = self.list_store1.get_value(list_iter, 2) # If we are not playing a video start the one requested if current_file == None: self.play_video(filename) return filename # If this filename doesn't match the current playing one, fire it up elif filename.find(current_file) == -1: self.play_video(filename) return filename else: logging.debug( "Not playing %s because it is already playing" % filename) return True list_iter = self.list_store1.iter_next(list_iter) logging.debug("Tag not stored in settings file yet!!") # return True #Flag for scanning to play video or read tag into gui textbox def set_add_rfid_tag_active(self, flag=False): self.addRfidTag = flag logging.debug("add rfid status flag " + str(self.addRfidTag)) def __init__(self): #Glade compomnents intialise self.builder = gtk.Builder() self.builder.add_from_file(sys.path[0] + "/EDUS2.glade") #Interval timer to loop listen_serial while return is true self.timer = gtk.timeout_add(200, self.listen_serial) self.window = self.builder.get_object("window1") self.settings_dialog = self.builder.get_object("settings_dialog") self.add_scan_dialog = self.builder.get_object("add_scan_dialog") self.quick_add_dialog = self.builder.get_object("quick_add_dialog") self.quick_add_item = self.builder.get_object("quick_add_item") self.about_dialog = self.builder.get_object("aboutdialog1") self.tree = self.builder.get_object("treeview2") self.list_store1 = self.builder.get_object("treeview") self.rfid_entry = self.builder.get_object("rfid_entry") self.rfid_quick_entry = self.builder.get_object("rfid_quick_entry") self.name_entry = self.builder.get_object("name_entry") self.quick_add_cur_filename = self.builder.get_object( "quick_add_cur_filename") self.filechooser = self.builder.get_object("filechooserbutton1") self.filechooser_quick = self.builder.get_object( "filechooserbutton_quick") self.load_settings_filechooserdialog = self.builder.get_object( "load_settings_filechooserdialog") self.save_settings_filechooserdialog = self.builder.get_object( "save_settings_filechooserdialog") self.message_dialog = self.builder.get_object("message_dialog") self.load_settings(sys.path[0] + "/settings.p") self.builder.connect_signals(self) # Set up treeView to allow multiple item selection for better delete self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.mainWindow = self.builder.get_object("window1") self.mainWindow.connect("key-press-event", self.on_key_press_event) self.window.show_all() self.mainWindow.fullscreen()