class EventConnectionTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = EventConnection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_read_a_system_event(self): x = 1 if 'MYTH_SNIFFER' in os.environ: x = 9999999 for i in xrange(x): msg = self.conn.readEvent() print(msg) log.debug(msg)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.bus = EventBus() self.domainCache = Mock() pools['dbPool'] = Pool( MythDatabaseFactory(settings=self.settings, translator=self.translator, domainCache=self.domainCache)) pools['connPool'] = Pool( ConnectionFactory(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus))
def test_verifyRecordingDirs_InvalidDirThrowsSettingsException(self): try: MythSettings.verifyRecordingDirs( os.path.join('someBogusDir', 'anotherBogusDir')) self.fail('expected failure') except SettingsException, se: log.debug('PASS: %s' % se)
class MythEventPublisherTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.bus = EventBus() self.domainCache = Mock() pools['dbPool'] = Pool(MythDatabaseFactory(settings=self.settings, translator=self.translator, domainCache=self.domainCache)) pools['connPool'] = Pool(ConnectionFactory(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus)) def tearDown(self): pools['connPool'].shutdown() pools['dbPool'].shutdown() def test_event_publisher(self): publisher = MythEventPublisher(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus) publisher.startup() time.sleep(5) publisher.shutdown()
def test_getRecordingDirs_ManyDirectories(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) settings = MythSettings(self.platform, self.translator) settings.put("paths_recordedprefix", os.pathsep.join(["a", "b", "c"])) log.debug("Recording prefix = %s" % settings.get("paths_recordedprefix")) dirs = settings.getRecordingDirs() self.assertEquals(3, len(dirs)) self.assertEquals(["a", "b", "c"], dirs)
def test_verifyRecordingDirs_OneInvalidOutOfManyOKThrowsSettingsException(self): try: MythSettings.verifyRecordingDirs( tempfile.gettempdir() + os.pathsep + "someBogusDir" + os.pathsep + os.getcwd() ) self.fail("expected failure") except SettingsException, se: log.debug("PASS: %s" % se)
def test_getRecordingDirs_SingleDirectory(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) settings = MythSettings(self.platform, self.translator) settings.put("paths_recordedprefix", "/mnt/mythtv") log.debug("Recording prefix = %s" % settings.get("paths_recordedprefix")) dirs = settings.getRecordingDirs() self.assertEquals(1, len(dirs)) self.assertEquals("/mnt/mythtv", dirs[0])
def test_verifyBoolean_AllValuesThatShouldRaiseException(self): badValues = ('true', 'false', '', '2', 'crap') for b in badValues: try: MythSettings.verifyBoolean(b, 'blah') self.fail('should have throws SettingsException') except SettingsException, se: log.debug('PASS: %s %s' % (b, se))
def test_saveSettings_LoadedDefaultsCreatesNewSettingsFile(self): filename = "settings.xml" filepath = os.path.join(self.sandbox, filename) when(self.platform).getScriptDataDir().thenReturn(self.sandbox) self.assertFalse(os.path.exists(filepath)) s = MythSettings(self.platform, self.translator) s.save() self.assertTrue(os.path.exists(filepath))
def test_verifyBoolean_AllValuesThatShouldRaiseException(self): badValues = ("true", "false", "", "2", "crap") for b in badValues: try: MythSettings.verifyBoolean(b, "blah") self.fail("should have throws SettingsException") except SettingsException, se: log.debug("PASS: %s %s" % (b, se))
def test_saveSettings_LoadedDefaultsCreatesNewSettingsFile(self): filename = 'settings.xml' filepath = os.path.join(self.sandbox, filename) when(self.platform).getScriptDataDir().thenReturn(self.sandbox) self.assertFalse(os.path.exists(filepath)) s = MythSettings(self.platform, self.translator) s.save() self.assertTrue(os.path.exists(filepath))
def test_verifyRecordingDirs_OneInvalidOutOfManyOKThrowsSettingsException( self): try: MythSettings.verifyRecordingDirs(tempfile.gettempdir() + os.pathsep + 'someBogusDir' + os.pathsep + os.getcwd()) self.fail('expected failure') except SettingsException, se: log.debug('PASS: %s' % se)
def test_When_existing_setting_changed_to_different_value_Then_event_published_to_bus(self): # Setup when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator, bus=self.bus) # Test s.get("mysql_host") s.put("mysql_host", "foo") # Verify verify(self.bus, 1).publish(any(dict))
def setUp(self): translator = mockito.Mock() platform = mockito.Mock() bus = mockito.Mock() settings = MythSettings(platform, translator) privateConfig = OnDemandConfig() settings.put('mysql_host', privateConfig.get('mysql_host')) settings.put('mysql_password', privateConfig.get('mysql_password')) settings.put('mysql_database', privateConfig.get('mysql_database')) self.db = MythDatabase(settings, translator) self.conn = Connection(settings, translator, platform, bus, self.db) self.brain = FileLiveTvBrain(self.conn, self.db)
def setUp(self): p = Platform() langInfo = util_mock.XBMCLangInfo(p) translator = util_mock.Translator(p, langInfo) settings = MythSettings(p, translator) domainCache = Mock() privateConfig = OnDemandConfig() settings.put('mysql_host', privateConfig.get('mysql_host')) settings.put('mysql_database', privateConfig.get('mysql_database')) settings.put('mysql_user', privateConfig.get('mysql_user')) settings.put('mysql_password', privateConfig.get('mysql_password')) self.dbPool = pool.pools['dbPool'] = pool.Pool(MythDatabaseFactory(settings=settings, translator=translator, domainCache=domainCache))
class MythDatabaseTest(unittest.TestCase): def setUp(self): self.platform = Platform() # self.translator = Mock() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.bus = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put("mysql_host", privateConfig.get("mysql_host")) self.settings.put("mysql_database", privateConfig.get("mysql_database")) self.settings.put("mysql_password", privateConfig.get("mysql_password")) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): # self.db.close() self.conn.close() def test_saveSchedule_NewSchedule(self): now = datetime.datetime.now() programs = self.db.getTVGuideDataFlattened(now, now, self.db.getChannels()) if len(programs) == 0: log.warn("Cannot run unit tests without program listings in the database") return schedule = RecordingSchedule.fromProgram(programs[0], self.translator) log.debug("Test schedule = %s" % schedule) result = self.db.saveSchedule(schedule) log.debug("Save schedule result = %s" % result) def test_addJob_UserJob1(self): recordings = self.conn.getAllRecordings() if not recordings: log.warn("Cannot run unit tests without program listings in the database") return job = Job.fromProgram(recordings[-1], JobType.USERJOB & JobType.USERJOB1) log.debug(job) self.assertIsNone(job.id) self.db.addJob(job) log.debug(job) self.assertIsNotNone(job.id)
def test_When_setting_has_a_unicode_value_Then_saving_and_loading_should_still_work( self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator) unicodeStr = u'Königreich der Himmel' s.put('recordings_selected_group', unicodeStr) s.save() s2 = MythSettings(self.platform, self.translator) actualStr = s2.get('recordings_selected_group') self.assertTrue(unicodeStr == actualStr) self.assertTrue(isinstance(unicodeStr, unicode))
class MythThumbnailResolverTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) log.debug('%s' % self.settings) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_store_download_thumbnail(self): # Setup recordings = self.conn.getRecordings() self.assertTrue(recordings, 'Recordings needed in to run test') downloader = MythThumbnailResolver(self.conn, self.db) dest = os.path.sep.join([ tempfile.gettempdir(), 'thumbnail_' + str(random.randint(1, 999999)) + '.png' ]) # Test downloader.store(recordings[-1], dest) # Verify log.debug('Downloaded %s to %s' % (safe_str(recordings[-1].title()), dest)) self.assertTrue(os.path.exists(dest)) self.assertTrue(os.path.isfile(dest)) self.assertTrue(os.path.getsize(dest) > 0) # Cleanup os.remove(dest)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = EventConnection(self.settings, self.translator, self.platform, self.bus, self.db)
def setUp(self): self.platform = Platform() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.settings = MythSettings(self.platform, self.translator) self.protocol = protocol.Protocol56() privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.put('mysql_database', privateConfig.get('mysql_database')) self.settings.put('mysql_user', privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.domainCache = Mock() self.db = MythDatabase(self.settings, self.translator, self.domainCache)
def test_constructor_NonExistentSettingsFilesLoadsDefaults(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator) self.assertEquals('localhost', s.get('mysql_host')) self.assertEquals('3306', s.get('mysql_port')) self.assertEquals('mythconverg', s.get('mysql_database')) self.assertEquals('mythtv', s.get('mysql_user')) self.assertEquals('change_me', s.get('mysql_password'))
class MythThumbnailResolverTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) log.debug('%s' % self.settings) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_store_download_thumbnail(self): # Setup recordings = self.conn.getRecordings() self.assertTrue(recordings, 'Recordings needed in to run test') downloader = MythThumbnailResolver(self.conn, self.db) dest = os.path.sep.join([tempfile.gettempdir(), 'thumbnail_' + str(random.randint(1, 999999)) + '.png']) # Test downloader.store(recordings[-1], dest) # Verify log.debug('Downloaded %s to %s' % (safe_str(recordings[-1].title()), dest)) self.assertTrue(os.path.exists(dest)) self.assertTrue(os.path.isfile(dest)) self.assertTrue(os.path.getsize(dest) > 0) # Cleanup os.remove(dest)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) log.debug('%s' % self.settings) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db)
class MythEventPublisherTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.bus = EventBus() self.domainCache = Mock() pools['dbPool'] = Pool( MythDatabaseFactory(settings=self.settings, translator=self.translator, domainCache=self.domainCache)) pools['connPool'] = Pool( ConnectionFactory(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus)) def tearDown(self): pools['connPool'].shutdown() pools['dbPool'].shutdown() def test_event_publisher(self): publisher = MythEventPublisher(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus) publisher.startup() time.sleep(5) publisher.shutdown()
class MythDatabaseTest(unittest.TestCase): def setUp(self): self.platform = Platform() #self.translator = Mock() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.bus = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_database', privateConfig.get('mysql_database')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): #self.db.close() self.conn.close() def test_saveSchedule_NewSchedule(self): now = datetime.datetime.now() programs = self.db.getTVGuideDataFlattened(now, now, self.db.getChannels()) if len(programs) == 0: log.warn( 'Cannot run unit tests without program listings in the database' ) return schedule = RecordingSchedule.fromProgram(programs[0], self.translator) log.debug('Test schedule = %s' % schedule) result = self.db.saveSchedule(schedule) log.debug('Save schedule result = %s' % result) def test_addJob_UserJob1(self): recordings = self.conn.getAllRecordings() if not recordings: log.warn( 'Cannot run unit tests without program listings in the database' ) return job = Job.fromProgram(recordings[-1], JobType.USERJOB & JobType.USERJOB1) log.debug(job) self.assertIsNone(job.id) self.db.addJob(job) log.debug(job) self.assertIsNotNone(job.id)
def setUp(self): self.platform = Platform() #self.translator = Mock() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.bus = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_database', privateConfig.get('mysql_database')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db)
def test_When_setting_has_a_unicode_value_Then_saving_and_loading_should_still_work(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator) unicodeStr = u"Königreich der Himmel" s.put("recordings_selected_group", unicodeStr) s.save() s2 = MythSettings(self.platform, self.translator) actualStr = s2.get("recordings_selected_group") self.assertTrue(unicodeStr == actualStr) self.assertTrue(isinstance(unicodeStr, unicode))
def test_constructor_NonExistentSettingsFilesLoadsDefaults(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator) self.assertEquals("localhost", s.get("mysql_host")) self.assertEquals("3306", s.get("mysql_port")) self.assertEquals("mythconverg", s.get("mysql_database")) self.assertEquals("mythtv", s.get("mysql_user")) self.assertEquals("change_me", s.get("mysql_password"))
def setUp(self): self.data = { 'title' : 'Bonanza', 'subtitle' : 'The Shootout', 'description' : 'Yee haw!', 'starttime' : datetime.datetime(2008, 11, 21, 14), 'endtime' : datetime.datetime(2008, 11, 21, 14), 'channum' : '23', 'hdtv' : True } self.translator = Mock() self.platform = Platform() self.protocol = TEST_PROTOCOL self.settings = MythSettings(self.platform, self.translator)
def test_getRecordingDirs_SingleDirectory(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) settings = MythSettings(self.platform, self.translator) settings.put('paths_recordedprefix', '/mnt/mythtv') log.debug("Recording prefix = %s" % settings.get('paths_recordedprefix')) dirs = settings.getRecordingDirs() self.assertEquals(1, len(dirs)) self.assertEquals('/mnt/mythtv', dirs[0])
def test_getRecordingDirs_ManyDirectories(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) settings = MythSettings(self.platform, self.translator) settings.put('paths_recordedprefix', os.pathsep.join(['a', 'b', 'c'])) log.debug("Recording prefix = %s" % settings.get('paths_recordedprefix')) dirs = settings.getRecordingDirs() self.assertEquals(3, len(dirs)) self.assertEquals(['a', 'b', 'c'], dirs)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.bus = EventBus() self.domainCache = Mock() pools['dbPool'] = Pool(MythDatabaseFactory(settings=self.settings, translator=self.translator, domainCache=self.domainCache)) pools['connPool'] = Pool(ConnectionFactory(settings=self.settings, translator=self.translator, platform=self.platform, bus=self.bus))
def test_constructor_LoadExistingSettingsFile(self): # Setup settingsDir = os.path.join('resources', 'test') settingsFile = 'test_mythtv_settings.xml' when(self.platform).getScriptDataDir().thenReturn(settingsDir) # Test s = MythSettings(self.platform, self.translator, settingsFile) # Verify self.assertEquals('test_host', s.get('mysql_host')) self.assertEquals('9999', s.get('mysql_port')) self.assertEquals('test_database', s.get('mysql_database')) self.assertEquals('test_user', s.get('mysql_user')) self.assertEquals('test_password', s.get('mysql_password'))
def test_When_existing_setting_changed_to_different_value_Then_event_published_to_bus( self): # Setup when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator, bus=self.bus) # Test s.get('mysql_host') s.put('mysql_host', 'foo') # Verify verify(self.bus, 1).publish(any(dict))
def setUp(self): self.platform = Platform() # self.translator = Mock() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.bus = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.put("mysql_host", privateConfig.get("mysql_host")) self.settings.put("mysql_database", privateConfig.get("mysql_database")) self.settings.put("mysql_password", privateConfig.get("mysql_password")) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db)
def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) self.settings.put('streaming_enabled', 'False') privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db)
def test_constructor_LoadExistingSettingsFile(self): # Setup settingsDir = os.path.join("resources", "test") settingsFile = "test_mythtv_settings.xml" when(self.platform).getScriptDataDir().thenReturn(settingsDir) # Test s = MythSettings(self.platform, self.translator, settingsFile) # Verify self.assertEquals("test_host", s.get("mysql_host")) self.assertEquals("9999", s.get("mysql_port")) self.assertEquals("test_database", s.get("mysql_database")) self.assertEquals("test_user", s.get("mysql_user")) self.assertEquals("test_password", s.get("mysql_password"))
def test_verifyMySQLUser_OK(self): MythSettings.verifyMySQLUser("someUser")
class MythChannelIconResolverTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_store_When_channel_has_icon_Then_download_icon(self): # Setup channels = filter(lambda x: x.getIconPath(), self.db.getChannels()) # filter out channels that don't have an icon self.assertTrue(len(channels) > 0, 'Channels with icon needed in db to run test') downloader = MythChannelIconResolver(self.conn) # Test - download icons for first 5 channels for channel in channels[:min(5, len(channels))]: if channel.getIconPath(): dest = os.path.sep.join([tempfile.gettempdir(), 'channel_' + str(channel.getChannelId()) + channel.getCallSign() + str(time.time()) + '.png']) downloader.store(channel, dest) # Verify log.debug('Downloaded %s to %s' % (channel.getIconPath(), dest)) self.assertTrue(os.path.exists(dest)) self.assertTrue(os.path.isfile(dest)) self.assertTrue(os.path.getsize(dest) > 0) # Cleanup os.remove(dest) def test_store_When_channel_has_no_icon_Then_do_nothing(self): # Setup channel = Channel({'name':'Bogus Channel', 'icon':None, 'chanid': '9', 'callsign': 'WXYZ'}) conn = Mock() downloader = MythChannelIconResolver(conn) # Test downloader.store(channel, 'bogusDestDir') # Verify verifyZeroInteractions(conn) def test_store_When_channel_has_iconpath_but_filename_misspelled_Then_do_nothing(self): # Setup channel = Channel({'name':'Bogus Channel', 'icon': 'bogusIcon.png', 'chanid': '9', 'callsign': 'WXYZ'}) downloader = MythChannelIconResolver(self.conn) # Test - download icons for first 5 channels dest = os.path.sep.join([tempfile.gettempdir(), str(channel.getChannelId()) + channel.getCallSign() + str(time.time()) + ".png"]) downloader.store(channel, dest) # Verify self.assertFalse(os.path.exists(dest))
def test_verifyRecordingDirs_OKManyDirectories(self): MythSettings.verifyRecordingDirs( self.sandbox + os.pathsep + os.getcwd() + os.pathsep + self.sandbox + os.pathsep + os.getcwd() )
def test_verifyBoolean_AllValuesThatShouldNotRaiseException(self): MythSettings.verifyBoolean('True', 'blah') MythSettings.verifyBoolean('False', 'blah') MythSettings.verifyBoolean('1', 'blah') MythSettings.verifyBoolean('0', 'blah')
def bootstrapSettings(self): self.stage = 'Initializing Settings' from mythbox.settings import MythSettings self.settings = MythSettings(self.platform, self.translator, 'settings.xml', self.bus) #from fanart import FanArt #self.log.debug('Settings = \n %s' % self.settings) class DelayedInstantiationProxy(object): '''Could use a little introspection to sort this out but eh...''' def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.fanArt = None def requireDelegate(self): if self.fanArt is None: from fanart import FanArt self.fanArt = FanArt(*self.args, **self.kwargs) def getSeasonAndEpisode(self, program): self.requireDelegate() return self.fanArt.getSeasonAndEpisode(program) def getRandomPoster(self, program): self.requireDelegate() return self.fanArt.getRandomPoster(program) def getPosters(self, program): self.requireDelegate() return self.fanArt.getPosters(program) def hasPosters(self, program): self.requireDelegate() return self.fanArt.hasPosters(program) def clear(self): self.requireDelegate() self.fanArt.clear() def shutdown(self): self.requireDelegate() self.fanArt.shutdown() def configure(self, settings): self.requireDelegate() self.fanArt.configure(settings) def onEvent(self, event): self.requireDelegate() self.fanArt.onEvent(event) from fanart import FanArt self.fanArt = FanArt(self.platform, self.httpCache, self.settings, self.bus) #self.fanArt = DelayedInstantiationProxy(self.platform, self.httpCache, self.settings, self.bus) try: import socket socket.setdefaulttimeout(float(os.getenv('MYTHBOX_TIMEOUT', '30'))) except: self.log.exception('Error setting socket timeout') self.bus.register(self) # Generate fake event to reflect value in settings.xml instead of mythbox_log.ini from bus import Event self.onEvent({ 'id': Event.SETTING_CHANGED, 'tag': 'logging_enabled', 'old': 'DontCare', 'new': self.settings.get('logging_enabled') })
class MythDatabaseTest(unittest.TestCase): def setUp(self): self.platform = Platform() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.settings = MythSettings(self.platform, self.translator) self.protocol = protocol.Protocol56() privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.put('mysql_database', privateConfig.get('mysql_database')) self.settings.put('mysql_user', privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.domainCache = Mock() self.db = MythDatabase(self.settings, self.translator, self.domainCache) def tearDown(self): try: self.db.close() except: pass def test_constructor(self): self.assertTrue(self.db) def test_toBackend(self): master = self.db.getMasterBackend() self.assertEqual(master, self.db.toBackend(master.hostname)) self.assertEqual(master, self.db.toBackend(master.ipAddress)) self.assertTrue(master, self.db.toBackend('bogus')) self.assertEqual(master, self.db.toBackend(master.hostname.upper())) self.assertEqual(master, self.db.toBackend(master.hostname.lower())) def test_getBackends(self): bes = self.db.getBackends() self.assertTrue(len(bes) >= 1) def test_getMasterBackend(self): mbe = self.db.getMasterBackend() log.debug(mbe) self.assertTrue(mbe.hostname) self.assertTrue(mbe.ipAddress) self.assertTrue(mbe.port) self.assertTrue(mbe.master) self.assertFalse(mbe.slave) def test_getSlaveBackends(self): slaves = self.db.getSlaveBackends() for slave in slaves: log.debug(slave) self.assertFalse(slave.master) self.assertTrue(slave.slave) def test_getChannels(self): channels = self.db.getChannels() for i, channel in enumerate(channels): log.debug("%d - %s"%(i+1, channel)) self.assertTrue('Expected int but was %s' % type(channel.getChannelId()), isinstance(channel.getChannelId(), int)) self.assertTrue('Expected str but was %s' % type(channel.getChannelNumber()), isinstance(channel.getChannelNumber(), str)) self.assertTrue('Expected str but was %s' % type(channel.getCallSign()), isinstance(channel.getCallSign(), str)) self.assertTrue('Expected str but was %s' % type(channel.getChannelName()), isinstance(channel.getChannelName(), str)) self.assertTrue('Expected str but was %s' % type(channel.getIconPath()), isinstance(channel.getIconPath(), str)) self.assertTrue('Expected int but was %s' % type(channel.getTunerId()), isinstance(channel.getTunerId(), int)) def test_getRecordingProfileNames(self): self.assertTrue(self.db.getRecordingProfileNames()) def test_getRecordingGroups(self): groups = self.db.getRecordingGroups() self.assertTrue('Default' in groups) def test_getRecordingTitles_InAllGroups(self): titles = self.db.getRecordingTitles('All Groups') self.assertTrue(len(titles) > 0) total = titles[0][1] for i, title in enumerate(titles): titleName = title[0] titleCount = title[1] log.debug('%d - %s x %s' %(i+1, titleCount, titleName)) def test_getRecordingTitles_ForNonExistantRecordingGroupReturnsAllShowsWithCountOfZero(self): titles = self.db.getRecordingTitles('bogus group') self.assertEquals(1, len(titles)) self.assertEquals('All Shows', titles[0][0]) self.assertEquals(0, titles[0][1]) def test_getRecordingTitles_ForDeletedRecordingsGroup(self): deleted = self.db.getRecordingTitles('Deleted') for i, title in enumerate(deleted): titleName = title[0] titleCount = title[1] log.debug('%d - Deleted recording %s recorded %s times' % (i+1, titleName, titleCount)) self.assertTrue(len(deleted) > 0) def test_getTuners(self): tuners = self.db.getTuners() self.assertTrue(len(tuners) > 0, 'No tuners found') for i, tuner in enumerate(tuners): log.debug('%d - %s' %(i+1, tuner)) self.assertIsNotNone(tuner.tunerId) self.assertIsNotNone(tuner.hostname) self.assertIsNotNone(tuner.signalTimeout) self.assertIsNotNone(tuner.channelTimeout) self.assertIsNotNone(tuner.domainCache) def test_getMythSetting_KeyOnly_Found(self): s = self.db.getMythSetting('mythfilldatabaseLastRunStatus') log.debug('mythfillstatus = %s' % s) self.assertFalse(s is None) def test_getMythSetting_KeyOnly_NotFound(self): s = self.db.getMythSetting('blahblah') self.assertTrue(s is None) def test_getMythSetting_KeyWithHostname_Found(self): # TODO pass def test_getMythSetting_KeyWithHostname_NotFound(self): s = self.db.getMythSetting('blahblah', 'foobar') self.assertTrue(s is None) def test_getRecordingSchedules_All(self): schedules = self.db.getRecordingSchedules() for i, s in enumerate(schedules): log.debug('%d - %s' % (i+1, s)) self.assertTrue(schedules) def test_getRecordingSchedules_By_Channel(self): # TODO pass def test_getRecordingSchedules_By_ScheduleId(self): # Setup schedules = self.db.getRecordingSchedules() if len(schedules) == 0: self.fail('Need schedules to run test') expectedSchedule = schedules.pop() # Test actualSchedules = self.db.getRecordingSchedules(scheduleId=expectedSchedule.getScheduleId()) # Verify self.assertEquals(1, len(actualSchedules)) self.assertEquals(expectedSchedule.getScheduleId(), actualSchedules.pop().getScheduleId()) def test_getJobs_All(self): when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() self.assertTrue(jobs is not None) for index, job in enumerate(jobs): log.debug('job %d = %s' % (index, job)) def test_getJobs_ForProgram(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[-1] # last job data = [''] * self.protocol.recordSize() data[4] = job.channelId data[11] = time.mktime(job.startTime.timetuple()) program = RecordedProgram(data=data, settings=Mock(), translator=Mock(), platform=Mock(), protocol=self.protocol, conn=Mock()) # Test jobs = self.db.getJobs(program=program) # Verify self.assertTrue(len(jobs) > 0) for index, actual in enumerate(jobs): log.debug('job %d = %s' % (index, actual)) self.assertEquals(job.channelId, actual.channelId) self.assertEquals(job.startTime, actual.startTime) def test_getJobs_ByJobType(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[0] # Test jobs = self.db.getJobs(jobType=job.jobType) # Verify self.assertTrue(len(jobs) > 0) for index, j2 in enumerate(jobs): log.debug('job %d = %s' % (index, j2)) self.assertEquals(job.jobType, j2.jobType) def test_getJobs_ForProgram_ByJobType(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[-1] # last job data = [''] * self.protocol.recordSize() data[4] = job.channelId data[11] = time.mktime(job.startTime.timetuple()) program = RecordedProgram(data=data, settings=Mock(), translator=Mock(), platform=Mock(), protocol=self.protocol, conn=Mock()) # Test jobs = self.db.getJobs(program=program, jobType=job.jobType) # Verify self.assertTrue(len(jobs) > 0) for index, actual in enumerate(jobs): log.debug('job %d = %s' % (index, actual)) self.assertEquals(job.channelId, actual.channelId) self.assertEquals(job.startTime, actual.startTime) self.assertEquals(job.jobType, actual.jobType) def test_getUserJobs(self): userJobs = self.db.getUserJobs() for j in userJobs: log.debug(j) self.assertEqual(4, len(userJobs)) def test_getTVGuideDataFlattened(self): # TODO: Convert to mocks w/ assertions channels = self.db.getChannels()[:2] programs = self.db.getTVGuideDataFlattened( datetime.datetime.now(), datetime.datetime.now() + datetime.timedelta(hours=4), channels) for p in programs: log.debug(p) def test_getFramerate(self): from mythbox.mythtv.conn import Connection from mythbox.util import safe_str from mythbox.mythtv.enums import RecordingStatus conn = Connection(settings=self.settings, translator=Mock(), platform=Mock(), bus=Mock(), db=self.db) try: recordings = conn.getAllRecordings()[-10:] for r in recordings: if r.isCommFlagged() and r.getRecordingStatus() == RecordingStatus.RECORDED: fps = self.db.getFramerate(r) log.debug('%s - %s - %s %d' % (safe_str(r.title()), safe_str(r.subtitle()), fps, r.getRecordingStatus())) self.assertGreaterEqual(fps, 0.0, fps) finally: conn.close()
def bootstrapSettings(self): self.stage = 'Initializing Settings' from mythbox.settings import MythSettings self.settings = MythSettings(self.platform, self.translator, 'settings.xml', self.bus) #from fanart import FanArt #self.log.debug('Settings = \n %s' % self.settings) class DelayedInstantiationProxy(object): '''Could use a little introspection to sort this out but eh...''' def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.fanArt = None def requireDelegate(self): if self.fanArt is None: from fanart import FanArt self.fanArt = FanArt(*self.args, **self.kwargs) def getSeasonAndEpisode(self, program): self.requireDelegate() return self.fanArt.getSeasonAndEpisode(program) def getRandomPoster(self, program): self.requireDelegate() return self.fanArt.getRandomPoster(program) def getPosters(self, program): self.requireDelegate() return self.fanArt.getPosters(program) def hasPosters(self, program): self.requireDelegate() return self.fanArt.hasPosters(program) def clear(self): self.requireDelegate() self.fanArt.clear() def shutdown(self): self.requireDelegate() self.fanArt.shutdown() def configure(self, settings): self.requireDelegate() self.fanArt.configure(settings) def onEvent(self, event): self.requireDelegate() self.fanArt.onEvent(event) from fanart import FanArt self.fanArt = FanArt(self.platform, self.httpCache, self.settings, self.bus) #self.fanArt = DelayedInstantiationProxy(self.platform, self.httpCache, self.settings, self.bus) try: import socket socket.setdefaulttimeout(float(os.getenv('MYTHBOX_TIMEOUT', '30'))) except: self.log.exception('Error setting socket timeout') self.bus.register(self) # Generate fake event to reflect value in settings.xml instead of mythbox_log.ini from bus import Event self.onEvent({'id': Event.SETTING_CHANGED, 'tag':'logging_enabled', 'old':'DontCare', 'new':self.settings.get('logging_enabled')})
class MythChannelIconResolverTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) privateConfig = OnDemandConfig() self.settings.setMySqlHost(privateConfig.get('mysql_host')) self.settings.setMySqlPort(privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.setMySqlPassword(privateConfig.get('mysql_password')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_store_When_channel_has_icon_Then_download_icon(self): # Setup channels = filter(lambda x: x.getIconPath(), self.db.getChannels() ) # filter out channels that don't have an icon self.assertTrue( len(channels) > 0, 'Channels with icon needed in db to run test') downloader = MythChannelIconResolver(self.conn) # Test - download icons for first 5 channels for channel in channels[:min(5, len(channels))]: if channel.getIconPath(): dest = os.path.sep.join([ tempfile.gettempdir(), 'channel_' + str(channel.getChannelId()) + channel.getCallSign() + str(time.time()) + '.png' ]) downloader.store(channel, dest) # Verify log.debug('Downloaded %s to %s' % (channel.getIconPath(), dest)) self.assertTrue(os.path.exists(dest)) self.assertTrue(os.path.isfile(dest)) self.assertTrue(os.path.getsize(dest) > 0) # Cleanup os.remove(dest) def test_store_When_channel_has_no_icon_Then_do_nothing(self): # Setup channel = Channel({ 'name': 'Bogus Channel', 'icon': None, 'chanid': '9', 'callsign': 'WXYZ' }) conn = Mock() downloader = MythChannelIconResolver(conn) # Test downloader.store(channel, 'bogusDestDir') # Verify verifyZeroInteractions(conn) def test_store_When_channel_has_iconpath_but_filename_misspelled_Then_do_nothing( self): # Setup channel = Channel({ 'name': 'Bogus Channel', 'icon': 'bogusIcon.png', 'chanid': '9', 'callsign': 'WXYZ' }) downloader = MythChannelIconResolver(self.conn) # Test - download icons for first 5 channels dest = os.path.sep.join([ tempfile.gettempdir(), str(channel.getChannelId()) + channel.getCallSign() + str(time.time()) + ".png" ]) downloader.store(channel, dest) # Verify self.assertFalse(os.path.exists(dest))
def test_toString(self): when(self.platform).getScriptDataDir().thenReturn(self.sandbox) s = MythSettings(self.platform, self.translator) log.debug('MythSettings = \n%s' % s)
class ConnectionTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) self.settings.put('streaming_enabled', 'False') privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_getServerVersion(self): sock = self.conn.connect(announce=None) try: version = self.conn.getServerVersion() log.debug('Server Protcol = %s'%version) self.assertTrue(version > 0) finally: sock.close() def test_negotiateProtocol_RaisesProtocolException_When_ClientVersion_NotSupported_By_Server(self): sock = self.conn.connect(announce=None) try: try: self.conn.negotiateProtocol(sock, clientVersion=8, versionToken='') self.fail('Should have thrown ProtocolException') except ProtocolException, pe: log.debug('PASS: %s', pe) finally: sock.close() def test_getSetting(self): reply = self.conn.getSetting('mythfillstatus', 'none') log.debug('reply = %s' % reply) if reply[0] == "-1": pass # fail else: pass # success # TODO : Left off here! def test_getTunerStatus_Success(self): tuners = self.db.getTuners() if len(tuners) == 0: log.warn('SKIPPING: need tuners to run test') return status = self.conn.getTunerStatus(tuners.pop()) log.debug('Tuner status = %s' % status) self.assertFalse(status is None) def test_getDiskUsage(self): du = self.conn.getDiskUsage() log.debug('Disk usage = %s' % du) self.assertTrue(du['hostname'] is not None) self.assertTrue(du['dir'] is not None) self.assertTrue(du['total'] is not None) self.assertTrue(du['used'] is not None) self.assertTrue(du['free'] is not None) def test_getLoad(self): load = self.conn.getLoad() log.debug('CPU Load = %s' % load) self.assertEquals(3, len(load)) self.assertTrue(load['1']) self.assertTrue(load['5']) self.assertTrue(load['15']) def test_getUptime(self): uptime = self.conn.getUptime() log.debug('Uptime = %s' % uptime) self.assertFalse(uptime is None) def test_getGuideDataStatus(self): guideStatus = self.conn.getGuideDataStatus() log.debug('Guide data status = %s' % guideStatus) self.assertFalse(guideStatus is None) def test_getAllRecordings(self): recordings = self.conn.getAllRecordings() log.debug('Num Recordings = %s' % len(recordings)) self.assertTrue(len(recordings) > 0) def test_getRecordings_AllRecordingGroupsAndTitles(self): recordings = self.conn.getRecordings() log.debug('Num Recordings = %s' % len(recordings)) for i, r in enumerate(recordings): log.debug('%d - %s' %(i+1, r)) self.assertTrue(len(recordings) > 0) def test_getRecording_Found(self): expected = self.getRecordings().pop() actual = self.conn.getRecording(expected.getChannelId(), expected.recstarttime()) self.assertEquals(expected, actual) def test_getRecording_NotFound(self): recording = self.getRecordings().pop() actual = self.conn.getRecording(32, recording.recstarttime()) self.assertTrue(actual is None) def test_getUpcomingRecordings_When_no_args_Then_returns_only_programs_that_will_be_recorded(self): upcoming = self.conn.getUpcomingRecordings() log.debug('Num upcoming recordings = %d' % (len(upcoming))) for i,program in enumerate(upcoming): log.debug('%d: tuner=%s %s' % (i, program.getTunerId(), program)) #program.dumpData() for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.SCHEDULED) self.assertTrue(program.getTunerId() >= 0) def test_getUpcomingRecordings_When_filter_is_scheduled_Then_returns_only_program_that_will_be_recorded(self): upcoming = self.conn.getUpcomingRecordings(Upcoming.SCHEDULED) log.debug('Num upcoming recordings (filter = Upcoming.SCHEDULED) = %d' % (len(upcoming))) for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.SCHEDULED) def test_getUpcomingRecordings_When_filter_is_conflict_Then_returns_only_program_that_will_not_be_recorded_because_of_a_conflict(self): upcoming = self.conn.getUpcomingRecordings(Upcoming.CONFLICTS) log.debug('Num upcoming recordings (filter = Upcoming.CONFLICTS) = %d' % (len(upcoming))) for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.CONFLICTS) def test_getScheduledRecordings(self): scheduled = self.conn.getScheduledRecordings() log.debug('Num scheduled recordings = %d' % (len(scheduled))) for i,program in enumerate(scheduled): log.debug('%d: %s' % (i, program)) self.assertFalse(scheduled is None) def test_getTunerShowing_NoCardsAreWatchingOrRecordingThePassedInShow(self): tunerId = self.conn.getTunerShowing('bogusshow') self.assertEquals(-1, tunerId, 'Expected no encoder to be watching or recording a bogus tv show') def test_getTunerShowing_ReturnCardThatShowIsBeingWatchedOn(self): log.warn("TODO: Write unit test - mockito") def test_getTunerShowing_ReturnCardThatShowIsBeingWatchedAndRecordedOn(self): log.warn("TODO: Write unit test - mockito") def test_getFreeTuner(self): tunerId, hostname, port = self.conn.getFreeTuner() if tunerId == -1: log.debug('No free tuners available') self.assertEquals('', hostname) self.assertEquals(-1, port) else: log.debug('Free tuner = id: %d hostname: %s port: %d'%(tunerId, hostname, port)) self.assertTrue(tunerId >= 0) self.assertTrue(len(hostname) > 0) self.assertTrue(port > 0) def test_getNextFreeTuner(self): tunerId, hostname, port = self.conn.getNextFreeTuner(-1) if tunerId is None: pass else: log.debug('Next free tuner = id:%d hostname:%s port:%d'%(tunerId, hostname, port)) # TODO: valid assertions when tuner free and not available def test_isOk_OKMessageReturnsTrue(self): self.assertTrue(self.conn._isOk(['OK'])) def test_isOk_OKMessageWithAdditionPayloadReturnsTrue(self): self.assertTrue(self.conn._isOk(['OK','foo', 'bar', 'baz'])) def test_isOk_NoneMessageReturnsFalse(self): self.assertFalse(self.conn._isOk(None)) def test_isOk_EmptyMessageReturnsFalse(self): self.assertFalse(self.conn._isOk([])) def test_isOk_BadMessageReturnsFalse(self): self.assertFalse(self.conn._isOk(['Bad'])) def test_isTunerRecording(self): for t in self.conn.getTuners(): log.debug('isTunerRecording(%d) = %s' % (t.tunerId, self.conn.isTunerRecording(t))) def test_getBookmark_Success(self): # TODO: only check bookmarked recordings recording = self.getRecordings()[0] log.debug('Getting bookmark for %s' % recording) bookmark = self.conn.getBookmark(recording) log.debug('bookmark = %s seconds' % bookmark) self.assertTrue(bookmark >= 0) def test_setBookmark_Success(self): p = self.getRecordings().pop() log.debug('Setting bookmark for %s' % p) self.conn.setBookmark(p, 1000) self.assertEquals(1000, self.conn.getBookmark(p)) def test_setBookmark_ChannelIdInvalid(self): p = self.getRecordings().pop() p.setChannelId(999) self.assertEquals(999, p.getChannelId()) self.assertRaises(ServerException, self.conn.setBookmark, p, 500) def test_getCommercialBreaks(self): recordings = reversed(self.conn.getAllRecordings()) foundRecordingWithCommBreaks = False for r in recordings: if r.hasCommercials(): foundRecordingWithCommBreaks = True log.debug('Recording %s has comm breaks' % r) breaks = self.conn.getCommercialBreaks(r) for j, b in enumerate(breaks): log.debug(' %d - comm break = %s' % (j+1, b)) return if not foundRecordingWithCommBreaks: log.warn('Could not find any comm flagged recordings to run unit test against') def test_getNumFreeTuners(self): cnt = self.conn.getNumFreeTuners() log.debug('Num free tuners = %d' % cnt) self.assertTrue(cnt >= 0) def test_getTuners(self): tuners = self.conn.getTuners() for i,t in enumerate(tuners): log.debug('Tuner %d = %s' % (i, t.tunerType)) self.assertTrue(t.conn != None) def test_generateThumbnail_ReturnsTrue(self): recording = self.getRecordings()[-1] log.debug('Generating thumbnail for program: %s' % recording) result = self.conn.generateThumbnail(recording, self.db.getMasterBackend().ipAddress) self.assertTrue(result) def test_generateThumbnail_WithSpecificSize(self): recording = self.getRecordings()[-1] log.debug('Generating thumbnail for program: %s' % recording.title()) result = self.conn.generateThumbnail(recording, self.db.getMasterBackend().ipAddress, 1280/4, 720/4) log.debug(result) self.assertTrue(result) def test_getThumbnailCreationTime_ThumbnailExists(self): recording = self.getRecordings()[0] log.debug('Getting thumbnail creation time for: %s' % recording.title()) dt = self.conn.getThumbnailCreationTime(recording, self.db.getMasterBackend().ipAddress) log.debug('datetime = %s' % dt) def test_getThumbNailCreationTime_ThumbnailDoesNotExist(self): # TODO pass def test_rescheduleNotify_Successful(self): schedules = self.db.getRecordingSchedules() self.conn.rescheduleNotify(schedules.pop()) log.debug('reschedule notify OK') def test_rescheduleNotify_Does_Something_Else_When_ScheduleId_missing(self): """ @todo: fixme """ pass def test_transferFile_FileExistsOnBackend_Success(self): # Setup recording = self.getRecordings()[-1] if not self.conn.getThumbnailCreationTime(recording, recording.hostname()): # generate thumbnail if necessary log.debug('Generating thumbnail...') self.conn.generateThumbnail(recording, recording.hostname()) recording = self.conn.getRecording(recording.getChannelId(), recording.recstarttime()) backendPath = recording.getBareFilename() if self.conn.protocol.genPixMapPreviewFilename(recording) != '<EMPTY>': backendPath += '.640x360' backendPath += '.png' destPath = os.path.join(tempfile.gettempdir(), recording.getBareFilename() + ".png") # Test try: log.debug('Transferring file %s to %s' % (backendPath, destPath)) result = self.conn.transferFile(backendPath, destPath, recording.hostname()) # Verify self.assertTrue(result) self.assertTrue(os.path.exists(destPath)) self.assertTrue(os.path.isfile(destPath)) finally: try: os.remove(destPath); except: pass def test_transferFile_When_file_does_not_exist_on_backend_Then_transfer_aborted(self): dest = tempfile.mktemp('bogusfile.mpg') backendPath = "myth://" + self.db.getMasterBackend().ipAddress + ":" + str(self.db.getMasterBackend().port) + "/bogusfile.mpg" result = self.conn.transferFile(backendPath, dest, self.db.getMasterBackend().ipAddress) self.assertFalse(os.path.exists(dest)) self.assertFalse(result) def test_transferFile_When_partial_transfer_requested_Then_only_send_part_of_file(self): # Setup recording = self.getRecordings()[-1] dest = tempfile.mktemp('.mpg', 'test_partial_transfer_') print dest try: # Test result = self.conn.transferFile(recording.getFilename(), dest, recording.hostname(), 1024 * 1000) # Verify self.assertTrue(result) self.assertTrue(os.path.exists(dest)) self.assertEquals(1024*1000, os.path.getsize(dest)) finally: try: os.remove(dest) except: pass def getRecordings(self): recordings = self.conn.getRecordings() self.assertTrue(recordings, 'Recordings required to run this test') return recordings
class ConnectionTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) self.settings.put('streaming_enabled', 'False') privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_getServerVersion(self): sock = self.conn.connect(announce=None) try: version = self.conn.getServerVersion() log.debug('Server Protcol = %s' % version) self.assertTrue(version > 0) finally: sock.close() def test_negotiateProtocol_RaisesProtocolException_When_ClientVersion_NotSupported_By_Server( self): sock = self.conn.connect(announce=None) try: try: self.conn.negotiateProtocol(sock, clientVersion=8, versionToken='') self.fail('Should have thrown ProtocolException') except ProtocolException, pe: log.debug('PASS: %s', pe) finally: sock.close() def test_getSetting(self): reply = self.conn.getSetting('mythfillstatus', 'none') log.debug('reply = %s' % reply) if reply[0] == "-1": pass # fail else: pass # success # TODO : Left off here! def test_getTunerStatus_Success(self): tuners = self.db.getTuners() if len(tuners) == 0: log.warn('SKIPPING: need tuners to run test') return status = self.conn.getTunerStatus(tuners.pop()) log.debug('Tuner status = %s' % status) self.assertFalse(status is None) def test_getDiskUsage(self): du = self.conn.getDiskUsage() log.debug('Disk usage = %s' % du) self.assertTrue(du['hostname'] is not None) self.assertTrue(du['dir'] is not None) self.assertTrue(du['total'] is not None) self.assertTrue(du['used'] is not None) self.assertTrue(du['free'] is not None) def test_getLoad(self): load = self.conn.getLoad() log.debug('CPU Load = %s' % load) self.assertEquals(3, len(load)) self.assertTrue(load['1']) self.assertTrue(load['5']) self.assertTrue(load['15']) def test_getUptime(self): uptime = self.conn.getUptime() log.debug('Uptime = %s' % uptime) self.assertFalse(uptime is None) def test_getGuideDataStatus(self): guideStatus = self.conn.getGuideDataStatus() log.debug('Guide data status = %s' % guideStatus) self.assertFalse(guideStatus is None) def test_getAllRecordings(self): recordings = self.conn.getAllRecordings() log.debug('Num Recordings = %s' % len(recordings)) self.assertTrue(len(recordings) > 0) def test_getRecordings_AllRecordingGroupsAndTitles(self): recordings = self.conn.getRecordings() log.debug('Num Recordings = %s' % len(recordings)) for i, r in enumerate(recordings): log.debug('%d - %s' % (i + 1, r)) self.assertTrue(len(recordings) > 0) def test_getRecording_Found(self): expected = self.getRecordings().pop() actual = self.conn.getRecording(expected.getChannelId(), expected.recstarttime()) self.assertEquals(expected, actual) def test_getRecording_NotFound(self): recording = self.getRecordings().pop() actual = self.conn.getRecording(32, recording.recstarttime()) self.assertTrue(actual is None) def test_getUpcomingRecordings_When_no_args_Then_returns_only_programs_that_will_be_recorded( self): upcoming = self.conn.getUpcomingRecordings() log.debug('Num upcoming recordings = %d' % (len(upcoming))) for i, program in enumerate(upcoming): log.debug('%d: tuner=%s %s' % (i, program.getTunerId(), program)) #program.dumpData() for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.SCHEDULED) self.assertTrue(program.getTunerId() >= 0) def test_getUpcomingRecordings_When_filter_is_scheduled_Then_returns_only_program_that_will_be_recorded( self): upcoming = self.conn.getUpcomingRecordings(Upcoming.SCHEDULED) log.debug( 'Num upcoming recordings (filter = Upcoming.SCHEDULED) = %d' % (len(upcoming))) for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.SCHEDULED) def test_getUpcomingRecordings_When_filter_is_conflict_Then_returns_only_program_that_will_not_be_recorded_because_of_a_conflict( self): upcoming = self.conn.getUpcomingRecordings(Upcoming.CONFLICTS) log.debug( 'Num upcoming recordings (filter = Upcoming.CONFLICTS) = %d' % (len(upcoming))) for program in upcoming: self.assertTrue(program.getRecordingStatus() in Upcoming.CONFLICTS) def test_getScheduledRecordings(self): scheduled = self.conn.getScheduledRecordings() log.debug('Num scheduled recordings = %d' % (len(scheduled))) for i, program in enumerate(scheduled): log.debug('%d: %s' % (i, program)) self.assertFalse(scheduled is None) def test_getTunerShowing_NoCardsAreWatchingOrRecordingThePassedInShow( self): tunerId = self.conn.getTunerShowing('bogusshow') self.assertEquals( -1, tunerId, 'Expected no encoder to be watching or recording a bogus tv show') def test_getTunerShowing_ReturnCardThatShowIsBeingWatchedOn(self): log.warn("TODO: Write unit test - mockito") def test_getTunerShowing_ReturnCardThatShowIsBeingWatchedAndRecordedOn( self): log.warn("TODO: Write unit test - mockito") def test_getFreeTuner(self): tunerId, hostname, port = self.conn.getFreeTuner() if tunerId == -1: log.debug('No free tuners available') self.assertEquals('', hostname) self.assertEquals(-1, port) else: log.debug('Free tuner = id: %d hostname: %s port: %d' % (tunerId, hostname, port)) self.assertTrue(tunerId >= 0) self.assertTrue(len(hostname) > 0) self.assertTrue(port > 0) def test_getNextFreeTuner(self): tunerId, hostname, port = self.conn.getNextFreeTuner(-1) if tunerId is None: pass else: log.debug('Next free tuner = id:%d hostname:%s port:%d' % (tunerId, hostname, port)) # TODO: valid assertions when tuner free and not available def test_isOk_OKMessageReturnsTrue(self): self.assertTrue(self.conn._isOk(['OK'])) def test_isOk_OKMessageWithAdditionPayloadReturnsTrue(self): self.assertTrue(self.conn._isOk(['OK', 'foo', 'bar', 'baz'])) def test_isOk_NoneMessageReturnsFalse(self): self.assertFalse(self.conn._isOk(None)) def test_isOk_EmptyMessageReturnsFalse(self): self.assertFalse(self.conn._isOk([])) def test_isOk_BadMessageReturnsFalse(self): self.assertFalse(self.conn._isOk(['Bad'])) def test_isTunerRecording(self): for t in self.conn.getTuners(): log.debug('isTunerRecording(%d) = %s' % (t.tunerId, self.conn.isTunerRecording(t))) def test_getBookmark_Success(self): # TODO: only check bookmarked recordings recording = self.getRecordings()[0] log.debug('Getting bookmark for %s' % recording) bookmark = self.conn.getBookmark(recording) log.debug('bookmark = %s seconds' % bookmark) self.assertTrue(bookmark >= 0) def test_setBookmark_Success(self): p = self.getRecordings().pop() log.debug('Setting bookmark for %s' % p) self.conn.setBookmark(p, 1000) self.assertEquals(1000, self.conn.getBookmark(p)) def test_setBookmark_ChannelIdInvalid(self): p = self.getRecordings().pop() p.setChannelId(999) self.assertEquals(999, p.getChannelId()) self.assertRaises(ServerException, self.conn.setBookmark, p, 500) def test_getCommercialBreaks(self): recordings = reversed(self.conn.getAllRecordings()) foundRecordingWithCommBreaks = False for r in recordings: if r.hasCommercials(): foundRecordingWithCommBreaks = True log.debug('Recording %s has comm breaks' % r) breaks = self.conn.getCommercialBreaks(r) for j, b in enumerate(breaks): log.debug(' %d - comm break = %s' % (j + 1, b)) return if not foundRecordingWithCommBreaks: log.warn( 'Could not find any comm flagged recordings to run unit test against' ) def test_getNumFreeTuners(self): cnt = self.conn.getNumFreeTuners() log.debug('Num free tuners = %d' % cnt) self.assertTrue(cnt >= 0) def test_getTuners(self): tuners = self.conn.getTuners() for i, t in enumerate(tuners): log.debug('Tuner %d = %s' % (i, t.tunerType)) self.assertTrue(t.conn != None) def test_generateThumbnail_ReturnsTrue(self): recording = self.getRecordings()[-1] log.debug('Generating thumbnail for program: %s' % recording) result = self.conn.generateThumbnail( recording, self.db.getMasterBackend().ipAddress) self.assertTrue(result) def test_generateThumbnail_WithSpecificSize(self): recording = self.getRecordings()[-1] log.debug('Generating thumbnail for program: %s' % recording.title()) result = self.conn.generateThumbnail( recording, self.db.getMasterBackend().ipAddress, 1280 / 4, 720 / 4) log.debug(result) self.assertTrue(result) def test_getThumbnailCreationTime_ThumbnailExists(self): recording = self.getRecordings()[0] log.debug('Getting thumbnail creation time for: %s' % recording.title()) dt = self.conn.getThumbnailCreationTime( recording, self.db.getMasterBackend().ipAddress) log.debug('datetime = %s' % dt) def test_getThumbNailCreationTime_ThumbnailDoesNotExist(self): # TODO pass def test_rescheduleNotify_Successful(self): schedules = self.db.getRecordingSchedules() self.conn.rescheduleNotify(schedules.pop()) log.debug('reschedule notify OK') def test_rescheduleNotify_Does_Something_Else_When_ScheduleId_missing( self): """ @todo: fixme """ pass def test_transferFile_FileExistsOnBackend_Success(self): # Setup recording = self.getRecordings()[-1] if not self.conn.getThumbnailCreationTime( recording, recording.hostname()): # generate thumbnail if necessary log.debug('Generating thumbnail...') self.conn.generateThumbnail(recording, recording.hostname()) recording = self.conn.getRecording(recording.getChannelId(), recording.recstarttime()) backendPath = recording.getBareFilename() if self.conn.protocol.genPixMapPreviewFilename(recording) != '<EMPTY>': backendPath += '.640x360' backendPath += '.png' destPath = os.path.join(tempfile.gettempdir(), recording.getBareFilename() + ".png") # Test try: log.debug('Transferring file %s to %s' % (backendPath, destPath)) result = self.conn.transferFile(backendPath, destPath, recording.hostname()) # Verify self.assertTrue(result) self.assertTrue(os.path.exists(destPath)) self.assertTrue(os.path.isfile(destPath)) finally: try: os.remove(destPath) except: pass def test_transferFile_When_file_does_not_exist_on_backend_Then_transfer_aborted( self): dest = tempfile.mktemp('bogusfile.mpg') backendPath = "myth://" + self.db.getMasterBackend( ).ipAddress + ":" + str( self.db.getMasterBackend().port) + "/bogusfile.mpg" result = self.conn.transferFile(backendPath, dest, self.db.getMasterBackend().ipAddress) self.assertFalse(os.path.exists(dest)) self.assertFalse(result) def test_transferFile_When_partial_transfer_requested_Then_only_send_part_of_file( self): # Setup recording = self.getRecordings()[-1] dest = tempfile.mktemp('.mpg', 'test_partial_transfer_') print dest try: # Test result = self.conn.transferFile(recording.getFilename(), dest, recording.hostname(), 1024 * 1000) # Verify self.assertTrue(result) self.assertTrue(os.path.exists(dest)) self.assertEquals(1024 * 1000, os.path.getsize(dest)) finally: try: os.remove(dest) except: pass def getRecordings(self): recordings = self.conn.getRecordings() self.assertTrue(recordings, 'Recordings required to run this test') return recordings
class BootStrapper(object): def __init__(self, splash): self.log = None self.platform = None self.stage = 'Initializing' self.shell = None self.splash = splash self.failSilent = False def run(self): try: try: self.bootstrapLogger() self.bootstrapPlatform() self.bootstrapEventBus() self.bootstrapCaches() self.bootstrapSettings() self.bootstrapUpdater() self.bootstrapFeeds() # TODO: Re-enable when twisted not loaded from dist-packages #self.bootstrapDebugShell() self.bootstrapHomeScreen() except Exception, ex: if not self.failSilent: self.handleFailure(ex) finally: if self.splash: self.splash.close() def handleFailure(self, cause): msg = 'MythBox:%s - Error: %s' % (self.stage, cause) xbmc.log(msg) print traceback.print_exc() if self.log: self.log.exception(str(cause)) xbmcgui.Dialog().ok('MythBox Error', 'Stage: %s' % self.stage, 'Exception: %s' % str(cause)) def updateProgress(self, msg): self.log.info(msg) def bootstrapLogger(self): import logging import logging.config self.stage = 'Initializing Logger' import xbmcaddon scriptDir = xbmcaddon.Addon('script.mythbox').getAddonInfo('path') loggerIniFile = os.path.join(scriptDir, 'mythbox_log.ini') # needs to be in local scope for fileConfig to find it from mythbox.log import XbmcLogHandler xbmc.log('MythBox: loggerIniFile = %s' % loggerIniFile) logging.config.fileConfig(loggerIniFile) self.log = logging.getLogger('mythbox.core') self.log.info('Mythbox Logger Initialized') def bootstrapPlatform(self): self.stage = 'Initializing Platform' import mythbox.platform self.platform = mythbox.platform.getPlatform() self.platform.addLibsToSysPath() sys.setcheckinterval(0) cacheDir = self.platform.getCacheDir() from mythbox.util import requireDir requireDir(cacheDir) self.log.info('MythBox %s Initialized' % self.platform.addonVersion()) def bootstrapEventBus(self): self.bus = EventBus() def bootstrapCaches(self): self.stage = 'Initializing Caches' from mythbox.util import NativeTranslator from mythbox.filecache import FileCache, HttpResolver, MythThumbnailFileCache from mythbox.mythtv.resolver import MythChannelIconResolver, MythThumbnailResolver from os.path import join from mythbox.mythtv.cache import DomainCache self.domainCache = DomainCache(bus=self.bus) cacheDir = self.platform.getCacheDir() self.translator = NativeTranslator(self.platform.getScriptDir()) self.mythThumbnailCache = MythThumbnailFileCache( join(cacheDir, 'thumbnail'), MythThumbnailResolver(), self.bus, self.domainCache) self.mythChannelIconCache = FileCache(join(cacheDir, 'channel'), MythChannelIconResolver()) self.httpCache = FileCache(join(cacheDir, 'http'), HttpResolver()) self.cachesByName = { 'mythThumbnailCache': self.mythThumbnailCache, 'mythChannelIconCache': self.mythChannelIconCache, 'httpCache': self.httpCache, 'domainCache': self.domainCache } def bootstrapSettings(self): self.stage = 'Initializing Settings' from mythbox.settings import MythSettings self.settings = MythSettings(self.platform, self.translator, 'settings.xml', self.bus) #from fanart import FanArt #self.log.debug('Settings = \n %s' % self.settings) class DelayedInstantiationProxy(object): '''Could use a little introspection to sort this out but eh...''' def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.fanArt = None def requireDelegate(self): if self.fanArt is None: from fanart import FanArt self.fanArt = FanArt(*self.args, **self.kwargs) def getSeasonAndEpisode(self, program): self.requireDelegate() return self.fanArt.getSeasonAndEpisode(program) def getRandomPoster(self, program): self.requireDelegate() return self.fanArt.getRandomPoster(program) def getPosters(self, program): self.requireDelegate() return self.fanArt.getPosters(program) def hasPosters(self, program): self.requireDelegate() return self.fanArt.hasPosters(program) def clear(self): self.requireDelegate() self.fanArt.clear() def shutdown(self): self.requireDelegate() self.fanArt.shutdown() def configure(self, settings): self.requireDelegate() self.fanArt.configure(settings) def onEvent(self, event): self.requireDelegate() self.fanArt.onEvent(event) from fanart import FanArt self.fanArt = FanArt(self.platform, self.httpCache, self.settings, self.bus) #self.fanArt = DelayedInstantiationProxy(self.platform, self.httpCache, self.settings, self.bus) try: import socket socket.setdefaulttimeout(float(os.getenv('MYTHBOX_TIMEOUT', '30'))) except: self.log.exception('Error setting socket timeout') self.bus.register(self) # Generate fake event to reflect value in settings.xml instead of mythbox_log.ini from bus import Event self.onEvent({ 'id': Event.SETTING_CHANGED, 'tag': 'logging_enabled', 'old': 'DontCare', 'new': self.settings.get('logging_enabled') }) def bootstrapUpdater(self): self.stage = 'Initializing Updater' from mythbox.updater import UpdateChecker UpdateChecker(self.platform).run() def bootstrapFeeds(self): from mythbox.feeds import FeedHose self.feedHose = FeedHose(self.settings, self.bus) def bootstrapDebugShell(self): # debug shell only packaged with bin/package-debug-zip try: from mythbox.shell import DebugShell globals()['bootstrapper'] = self self.shell = DebugShell(self.bus, namespace=globals()) self.shell.start() except ImportError: self.log.debug('Punting on debug shell -- not packaged') def bootstrapXbmcShutdownListener(self): from threading import Thread class XbmcShutdownListener(Thread): def __init__(self, home, bus, log): Thread.__init__(self) self.home = home self.log = log self.shutdownReceived = False bus.register(self) def onEvent(self, event): from bus import Event if event['id'] == Event.SHUTDOWN: self.shutdownReceived = True self.join() xbmc.log('Joined shutdown listener') def run(self): import time xbmc.log('XbmcShutdownListener thread running..') cnt = 1 while not xbmc.abortRequested and not self.shutdownReceived: #xbmc.sleep(1000) time.sleep(1) xbmc.log( 'XbmcShutdownListner abort = %s user = %s tick %d ...' % (xbmc.abortRequested, self.shutdownReceived, cnt)) cnt += 1 if xbmc.abortRequested: xbmc.log('XBMC requested shutdown..') self.home.shutdown() xbmc.log('XBMC requested shutdown complete') xbmc.log('XbmcShutdownListener thread terminating') self.shutdownListener = XbmcShutdownListener(self.home, self.bus, self.log) self.shutdownListener.start() def bootstrapHomeScreen(self): from mythbox.ui.home import HomeWindow self.home = HomeWindow('mythbox_home.xml', self.platform.getScriptDir(), settings=self.settings, translator=self.translator, platform=self.platform, fanArt=self.fanArt, cachesByName=self.cachesByName, bus=self.bus, feedHose=self.feedHose) if self.splash: self.splash.close() #self.bootstrapXbmcShutdownListener() self.home.doModal() def onEvent(self, event): from bus import Event # # Apply changes to logger when user turns debug logging on/off # if event['id'] == Event.SETTING_CHANGED and event[ 'tag'] == 'logging_enabled': import logging logging.root.debug('Setting changed: %s %s %s' % (event['tag'], event['old'], event['new'])) if event['new'] == 'True': level = logging.DEBUG else: level = logging.WARN loggerNames = 'unittest mysql core method skin ui perf fanart settings cache event'.split( ) # wire inject'.split() for name in loggerNames: logger = logging.getLogger('mythbox.%s' % name) logger.setLevel(level)
def test_verifyMySQLUser_EmptyStringThrowsSettingsException(self): try: MythSettings.verifyMySQLUser("") except SettingsException, se: log.debug("PASS: %s" % se)
class DeleteOrphansTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) self.settings.put('streaming_enabled', 'False') privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_getAllRecordings(self): recordings = self.conn.getAllRecordings() log.debug('Num Recordings = %s' % len(recordings)) for i,r in enumerate(recordings): print i,r.getBareFilename() dirs = ['/usr2/mythtv','/usr2/mythtv2', '/usr2/mythtv3'] mpgs = [] for d in dirs: files = os.listdir(d) for f in files: if f.endswith('.mpg'): mpgs.append(f) print f print 'Recs total = ', len(recordings) print 'Files total = ', len(mpgs) print 'Extras = ', len(mpgs) - len(recordings) todelete = mpgs[:] for r in recordings: if r.getBareFilename() in mpgs: todelete.remove(r.getBareFilename()) print 'Todelete = ', len(todelete) bucket = [] import datetime for f in todelete: for d in dirs: path = os.path.join(d,f) if os.path.exists(path): bucket.append(path) print path, os.path.getsize(path) print 'Bucket = ', len(bucket) sorted(bucket) total = 0 for f in bucket: s = os.path.getsize(f) total += s print total/1000000000 import shutil for src in bucket[:25]: dest = '/usr2/mythtv/backup/' + os.path.basename(src) print src,' -> ', dest
class BootStrapper(object): def __init__(self, splash): self.log = None self.platform = None self.stage = 'Initializing' self.shell = None self.splash = splash self.failSilent = False def run(self): try: try: self.bootstrapLogger() self.bootstrapPlatform() self.bootstrapEventBus() self.bootstrapCaches() self.bootstrapSettings() self.bootstrapUpdater() self.bootstrapFeeds() # TODO: Re-enable when twisted not loaded from dist-packages #self.bootstrapDebugShell() self.bootstrapHomeScreen() except Exception, ex: if not self.failSilent: self.handleFailure(ex) finally: if self.splash: self.splash.close() def handleFailure(self, cause): msg = 'MythBox:%s - Error: %s' % (self.stage, cause) xbmc.log(msg) print traceback.print_exc() if self.log: self.log.exception(str(cause)) xbmcgui.Dialog().ok('MythBox Error', 'Stage: %s' % self.stage, 'Exception: %s' % str(cause)) def updateProgress(self, msg): self.log.info(msg) def bootstrapLogger(self): import logging import logging.config self.stage = 'Initializing Logger' import xbmcaddon scriptDir = xbmcaddon.Addon('script.mythbox').getAddonInfo('path') loggerIniFile = os.path.join(scriptDir, 'mythbox_log.ini') # needs to be in local scope for fileConfig to find it from mythbox.log import XbmcLogHandler xbmc.log('MythBox: loggerIniFile = %s' % loggerIniFile) logging.config.fileConfig(loggerIniFile) self.log = logging.getLogger('mythbox.core') self.log.info('Mythbox Logger Initialized') def bootstrapPlatform(self): self.stage = 'Initializing Platform' import mythbox.platform self.platform = mythbox.platform.getPlatform() self.platform.addLibsToSysPath() sys.setcheckinterval(0) cacheDir = self.platform.getCacheDir() from mythbox.util import requireDir requireDir(cacheDir) self.log.info('MythBox %s Initialized' % self.platform.addonVersion()) def bootstrapEventBus(self): self.bus = EventBus() def bootstrapCaches(self): self.stage = 'Initializing Caches' from mythbox.util import NativeTranslator from mythbox.filecache import FileCache, HttpResolver, MythThumbnailFileCache from mythbox.mythtv.resolver import MythChannelIconResolver, MythThumbnailResolver from os.path import join from mythbox.mythtv.cache import DomainCache self.domainCache = DomainCache(bus=self.bus) cacheDir = self.platform.getCacheDir() self.translator = NativeTranslator(self.platform.getScriptDir()) self.mythThumbnailCache = MythThumbnailFileCache(join(cacheDir, 'thumbnail'), MythThumbnailResolver(), self.bus, self.domainCache) self.mythChannelIconCache = FileCache(join(cacheDir, 'channel'), MythChannelIconResolver()) self.httpCache = FileCache(join(cacheDir, 'http'), HttpResolver()) self.cachesByName = { 'mythThumbnailCache' : self.mythThumbnailCache, 'mythChannelIconCache': self.mythChannelIconCache, 'httpCache' : self.httpCache, 'domainCache' : self.domainCache } def bootstrapSettings(self): self.stage = 'Initializing Settings' from mythbox.settings import MythSettings self.settings = MythSettings(self.platform, self.translator, 'settings.xml', self.bus) #from fanart import FanArt #self.log.debug('Settings = \n %s' % self.settings) class DelayedInstantiationProxy(object): '''Could use a little introspection to sort this out but eh...''' def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.fanArt = None def requireDelegate(self): if self.fanArt is None: from fanart import FanArt self.fanArt = FanArt(*self.args, **self.kwargs) def getSeasonAndEpisode(self, program): self.requireDelegate() return self.fanArt.getSeasonAndEpisode(program) def getRandomPoster(self, program): self.requireDelegate() return self.fanArt.getRandomPoster(program) def getPosters(self, program): self.requireDelegate() return self.fanArt.getPosters(program) def hasPosters(self, program): self.requireDelegate() return self.fanArt.hasPosters(program) def clear(self): self.requireDelegate() self.fanArt.clear() def shutdown(self): self.requireDelegate() self.fanArt.shutdown() def configure(self, settings): self.requireDelegate() self.fanArt.configure(settings) def onEvent(self, event): self.requireDelegate() self.fanArt.onEvent(event) from fanart import FanArt self.fanArt = FanArt(self.platform, self.httpCache, self.settings, self.bus) #self.fanArt = DelayedInstantiationProxy(self.platform, self.httpCache, self.settings, self.bus) try: import socket socket.setdefaulttimeout(float(os.getenv('MYTHBOX_TIMEOUT', '30'))) except: self.log.exception('Error setting socket timeout') self.bus.register(self) # Generate fake event to reflect value in settings.xml instead of mythbox_log.ini from bus import Event self.onEvent({'id': Event.SETTING_CHANGED, 'tag':'logging_enabled', 'old':'DontCare', 'new':self.settings.get('logging_enabled')}) def bootstrapUpdater(self): self.stage = 'Initializing Updater' from mythbox.updater import UpdateChecker UpdateChecker(self.platform).run() def bootstrapFeeds(self): from mythbox.feeds import FeedHose self.feedHose = FeedHose(self.settings, self.bus) def bootstrapDebugShell(self): # debug shell only packaged with bin/package-debug-zip try: from mythbox.shell import DebugShell globals()['bootstrapper'] = self self.shell = DebugShell(self.bus, namespace=globals()) self.shell.start() except ImportError: self.log.debug('Punting on debug shell -- not packaged') def bootstrapXbmcShutdownListener(self): from threading import Thread class XbmcShutdownListener(Thread): def __init__(self, home, bus, log): Thread.__init__(self) self.home = home self.log = log self.shutdownReceived = False bus.register(self) def onEvent(self, event): from bus import Event if event['id'] == Event.SHUTDOWN: self.shutdownReceived = True self.join() xbmc.log('Joined shutdown listener') def run(self): import time xbmc.log('XbmcShutdownListener thread running..') cnt = 1 while not xbmc.abortRequested and not self.shutdownReceived: #xbmc.sleep(1000) time.sleep(1) xbmc.log('XbmcShutdownListner abort = %s user = %s tick %d ...' % (xbmc.abortRequested, self.shutdownReceived, cnt)) cnt += 1 if xbmc.abortRequested: xbmc.log('XBMC requested shutdown..') self.home.shutdown() xbmc.log('XBMC requested shutdown complete') xbmc.log('XbmcShutdownListener thread terminating') self.shutdownListener = XbmcShutdownListener(self.home, self.bus, self.log) self.shutdownListener.start() def bootstrapHomeScreen(self): from mythbox.ui.home import HomeWindow self.home = HomeWindow( 'mythbox_home.xml', self.platform.getScriptDir(), settings=self.settings, translator=self.translator, platform=self.platform, fanArt=self.fanArt, cachesByName=self.cachesByName, bus=self.bus, feedHose=self.feedHose) if self.splash: self.splash.close() #self.bootstrapXbmcShutdownListener() self.home.doModal() def onEvent(self, event): from bus import Event # # Apply changes to logger when user turns debug logging on/off # if event['id'] == Event.SETTING_CHANGED and event['tag'] == 'logging_enabled': import logging logging.root.debug('Setting changed: %s %s %s' % (event['tag'], event['old'], event['new'])) if event['new'] == 'True': level = logging.DEBUG else: level = logging.WARN loggerNames = 'unittest mysql core method skin ui perf fanart settings cache event'.split() # wire inject'.split() for name in loggerNames: logger = logging.getLogger('mythbox.%s' % name) logger.setLevel(level)
class MythDatabaseTest(unittest.TestCase): def setUp(self): self.platform = Platform() self.langInfo = util_mock.XBMCLangInfo(self.platform) self.translator = util_mock.Translator(self.platform, self.langInfo) self.settings = MythSettings(self.platform, self.translator) self.protocol = protocol.Protocol56() privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.put('mysql_database', privateConfig.get('mysql_database')) self.settings.put('mysql_user', privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.domainCache = Mock() self.db = MythDatabase(self.settings, self.translator, self.domainCache) def tearDown(self): try: self.db.close() except: pass def test_constructor(self): self.assertTrue(self.db) def test_toBackend(self): master = self.db.getMasterBackend() self.assertEqual(master, self.db.toBackend(master.hostname)) self.assertEqual(master, self.db.toBackend(master.ipAddress)) self.assertTrue(master, self.db.toBackend('bogus')) self.assertEqual(master, self.db.toBackend(master.hostname.upper())) self.assertEqual(master, self.db.toBackend(master.hostname.lower())) def test_getBackends(self): bes = self.db.getBackends() self.assertTrue(len(bes) >= 1) def test_getMasterBackend(self): mbe = self.db.getMasterBackend() log.debug(mbe) self.assertTrue(mbe.hostname) self.assertTrue(mbe.ipAddress) self.assertTrue(mbe.port) self.assertTrue(mbe.master) self.assertFalse(mbe.slave) def test_getSlaveBackends(self): slaves = self.db.getSlaveBackends() for slave in slaves: log.debug(slave) self.assertFalse(slave.master) self.assertTrue(slave.slave) def test_getChannels(self): channels = self.db.getChannels() for i, channel in enumerate(channels): log.debug("%d - %s" % (i + 1, channel)) self.assertTrue( 'Expected int but was %s' % type(channel.getChannelId()), isinstance(channel.getChannelId(), int)) self.assertTrue( 'Expected str but was %s' % type(channel.getChannelNumber()), isinstance(channel.getChannelNumber(), str)) self.assertTrue( 'Expected str but was %s' % type(channel.getCallSign()), isinstance(channel.getCallSign(), str)) self.assertTrue( 'Expected str but was %s' % type(channel.getChannelName()), isinstance(channel.getChannelName(), str)) self.assertTrue( 'Expected str but was %s' % type(channel.getIconPath()), isinstance(channel.getIconPath(), str)) self.assertTrue( 'Expected int but was %s' % type(channel.getTunerId()), isinstance(channel.getTunerId(), int)) def test_getRecordingProfileNames(self): self.assertTrue(self.db.getRecordingProfileNames()) def test_getRecordingGroups(self): groups = self.db.getRecordingGroups() self.assertTrue('Default' in groups) def test_getRecordingTitles_InAllGroups(self): titles = self.db.getRecordingTitles('All Groups') self.assertTrue(len(titles) > 0) total = titles[0][1] for i, title in enumerate(titles): titleName = title[0] titleCount = title[1] log.debug('%d - %s x %s' % (i + 1, titleCount, titleName)) def test_getRecordingTitles_ForNonExistantRecordingGroupReturnsAllShowsWithCountOfZero( self): titles = self.db.getRecordingTitles('bogus group') self.assertEquals(1, len(titles)) self.assertEquals('All Shows', titles[0][0]) self.assertEquals(0, titles[0][1]) def test_getRecordingTitles_ForDeletedRecordingsGroup(self): deleted = self.db.getRecordingTitles('Deleted') for i, title in enumerate(deleted): titleName = title[0] titleCount = title[1] log.debug('%d - Deleted recording %s recorded %s times' % (i + 1, titleName, titleCount)) self.assertTrue(len(deleted) > 0) def test_getTuners(self): tuners = self.db.getTuners() self.assertTrue(len(tuners) > 0, 'No tuners found') for i, tuner in enumerate(tuners): log.debug('%d - %s' % (i + 1, tuner)) self.assertIsNotNone(tuner.tunerId) self.assertIsNotNone(tuner.hostname) self.assertIsNotNone(tuner.signalTimeout) self.assertIsNotNone(tuner.channelTimeout) self.assertIsNotNone(tuner.domainCache) def test_getMythSetting_KeyOnly_Found(self): s = self.db.getMythSetting('mythfilldatabaseLastRunStatus') log.debug('mythfillstatus = %s' % s) self.assertFalse(s is None) def test_getMythSetting_KeyOnly_NotFound(self): s = self.db.getMythSetting('blahblah') self.assertTrue(s is None) def test_getMythSetting_KeyWithHostname_Found(self): # TODO pass def test_getMythSetting_KeyWithHostname_NotFound(self): s = self.db.getMythSetting('blahblah', 'foobar') self.assertTrue(s is None) def test_getRecordingSchedules_All(self): schedules = self.db.getRecordingSchedules() for i, s in enumerate(schedules): log.debug('%d - %s' % (i + 1, s)) self.assertTrue(schedules) def test_getRecordingSchedules_By_Channel(self): # TODO pass def test_getRecordingSchedules_By_ScheduleId(self): # Setup schedules = self.db.getRecordingSchedules() if len(schedules) == 0: self.fail('Need schedules to run test') expectedSchedule = schedules.pop() # Test actualSchedules = self.db.getRecordingSchedules( scheduleId=expectedSchedule.getScheduleId()) # Verify self.assertEquals(1, len(actualSchedules)) self.assertEquals(expectedSchedule.getScheduleId(), actualSchedules.pop().getScheduleId()) def test_getJobs_All(self): when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() self.assertTrue(jobs is not None) for index, job in enumerate(jobs): log.debug('job %d = %s' % (index, job)) def test_getJobs_ForProgram(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[-1] # last job data = [''] * self.protocol.recordSize() data[4] = job.channelId data[11] = time.mktime(job.startTime.timetuple()) program = RecordedProgram(data=data, settings=Mock(), translator=Mock(), platform=Mock(), protocol=self.protocol, conn=Mock()) # Test jobs = self.db.getJobs(program=program) # Verify self.assertTrue(len(jobs) > 0) for index, actual in enumerate(jobs): log.debug('job %d = %s' % (index, actual)) self.assertEquals(job.channelId, actual.channelId) self.assertEquals(job.startTime, actual.startTime) def test_getJobs_ByJobType(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[0] # Test jobs = self.db.getJobs(jobType=job.jobType) # Verify self.assertTrue(len(jobs) > 0) for index, j2 in enumerate(jobs): log.debug('job %d = %s' % (index, j2)) self.assertEquals(job.jobType, j2.jobType) def test_getJobs_ForProgram_ByJobType(self): # Setup when(self.domainCache).getUserJobs().thenReturn(self.db.getUserJobs()) jobs = self.db.getJobs() if len(jobs) == 0: log.warn('No jobs in database to test with. Test skipped...') return job = jobs[-1] # last job data = [''] * self.protocol.recordSize() data[4] = job.channelId data[11] = time.mktime(job.startTime.timetuple()) program = RecordedProgram(data=data, settings=Mock(), translator=Mock(), platform=Mock(), protocol=self.protocol, conn=Mock()) # Test jobs = self.db.getJobs(program=program, jobType=job.jobType) # Verify self.assertTrue(len(jobs) > 0) for index, actual in enumerate(jobs): log.debug('job %d = %s' % (index, actual)) self.assertEquals(job.channelId, actual.channelId) self.assertEquals(job.startTime, actual.startTime) self.assertEquals(job.jobType, actual.jobType) def test_getUserJobs(self): userJobs = self.db.getUserJobs() for j in userJobs: log.debug(j) self.assertEqual(4, len(userJobs)) def test_getTVGuideDataFlattened(self): # TODO: Convert to mocks w/ assertions channels = self.db.getChannels()[:2] programs = self.db.getTVGuideDataFlattened( datetime.datetime.now(), datetime.datetime.now() + datetime.timedelta(hours=4), channels) for p in programs: log.debug(p) def test_getFramerate(self): from mythbox.mythtv.conn import Connection from mythbox.util import safe_str from mythbox.mythtv.enums import RecordingStatus conn = Connection(settings=self.settings, translator=Mock(), platform=Mock(), bus=Mock(), db=self.db) try: recordings = conn.getAllRecordings()[-10:] for r in recordings: if r.isCommFlagged() and r.getRecordingStatus( ) == RecordingStatus.RECORDED: fps = self.db.getFramerate(r) log.debug('%s - %s - %s %d' % (safe_str(r.title()), safe_str( r.subtitle()), fps, r.getRecordingStatus())) self.assertGreaterEqual(fps, 0.0, fps) finally: conn.close()
def test_verifyBoolean_AllValuesThatShouldNotRaiseException(self): MythSettings.verifyBoolean("True", "blah") MythSettings.verifyBoolean("False", "blah") MythSettings.verifyBoolean("1", "blah") MythSettings.verifyBoolean("0", "blah")
class DeleteOrphansTest(unittest.TestCase): def setUp(self): self.platform = getPlatform() self.translator = Mock() self.domainCache = Mock() self.settings = MythSettings(self.platform, self.translator) self.settings.put('streaming_enabled', 'False') privateConfig = OnDemandConfig() self.settings.put('mysql_host', privateConfig.get('mysql_host')) self.settings.put('mysql_port', privateConfig.get('mysql_port')) self.settings.setMySqlDatabase(privateConfig.get('mysql_database')) self.settings.setMySqlUser(privateConfig.get('mysql_user')) self.settings.put('mysql_password', privateConfig.get('mysql_password')) self.settings.put('paths_recordedprefix', privateConfig.get('paths_recordedprefix')) self.db = MythDatabase(self.settings, self.translator, self.domainCache) self.bus = EventBus() self.conn = Connection(self.settings, self.translator, self.platform, self.bus, self.db) def tearDown(self): self.conn.close() def test_delete_orphaned_recordings(self): recordings = self.conn.getAllRecordings() log.debug('Num Recordings = %s' % len(recordings)) for i,r in enumerate(recordings): print i,r.getBareFilename() dirs = ['/usr2/mythtv'] mpgs = [] for d in dirs: files = os.listdir(d) for f in files: if f.endswith('.mpg'): mpgs.append(f) print f print 'Recs total = ', len(recordings) print 'Files total = ', len(mpgs) print 'Extras = ', len(mpgs) - len(recordings) todelete = mpgs[:] for r in recordings: if r.getBareFilename() in mpgs: todelete.remove(r.getBareFilename()) print 'Todelete = ', len(todelete) bucket = [] import datetime for f in todelete: for d in dirs: path = os.path.join(d,f) if os.path.exists(path): bucket.append(path) print path, os.path.getsize(path) print 'Bucket = ', len(bucket) sorted(bucket) total = 0 for f in bucket: s = os.path.getsize(f) total += s print total/1000000000 import shutil for src in bucket: dest = '/usr2/mythtv/backup/' + os.path.basename(src) print src,' -> ', dest #shutil.move(src, dest) def test_recreate_lost_recordings(self): recordings = self.conn.getAllRecordings() log.debug('Num Recordings = %s' % len(recordings)) for i,r in enumerate(recordings): print i,r.getBareFilename() dirs = ['/usr2/mythtv'] mpgs = [] for d in dirs: files = os.listdir(d) for f in files: if f.endswith('.mpg'): mpgs.append(f) print f print 'Recs total = ', len(recordings) print 'Files total = ', len(mpgs) print 'Missing total = ', len(recordings) - len(mpgs) rec_names = [r.getBareFilename() for r in recordings] tocreate = rec_names[:] for m in mpgs: if m in rec_names: tocreate.remove(m) print 'Tocreate = ', len(tocreate) bucket = [] import datetime for f in tocreate: for d in dirs: path = os.path.join(d,f) if not os.path.exists(path): bucket.append(path) print path print 'Bucket = ', len(bucket) sorted(bucket) import shutil src = '/usr/copy/me.mpg' for dest in bucket: print src,' -> ', dest