def test_check_threads_state(self): """ Test almost all pathways of check_threads_state. """ alarm_mgr = AlarmManager() self.create_alarms(alarm_mgr) check_result = alarm_mgr.check_threads_state() self.assertTrue(check_result) # Now that everything is working correctly, sneak around AlarmManager # and edit a running thread by editing an AlarmItem using the # AlarmThread internal reference to the AlarmItem instance (which does # not do the extra checks for tracking like AlarmManager does). # Also edit the database entry for that alarm bypassing AlarmManager. alarm_bypass = \ alarm_mgr._AlarmManager__alarm_threads[0]._AlarmThread__alarm alarm_bypass.enabled = False alarm_id = alarm_bypass.id_ AlarmDb().edit_alarm(alarm_id, enabled=False) check_result = alarm_mgr.check_threads_state() self.assertFalse(check_result) # Executing check_threads_state should have return false as there was # an issue, but if fixed correctly the second time should return true check_result = alarm_mgr.check_threads_state() self.assertTrue(check_result) # Now the thread for alarm 'alarm_bypass' with ID 'alarm_id' has been # stopped, we can bypass AlarmManager again to activate it and check # if check_threads_state recovers again. alarm_bypass.enabled = True AlarmDb().edit_alarm(alarm_bypass.id_, enabled=True) check_result = alarm_mgr.check_threads_state() self.assertFalse(check_result) check_result = alarm_mgr.check_threads_state() self.assertTrue(check_result) # Now that everything is working correctly once more, add extra thread alarm_test = AlarmItem(self.hour, 20, enabled=True, alarm_id=96, days=(True, True, True, True, True, True, True)) launch_success = alarm_mgr._AlarmManager__set_alarm_thread(alarm_test) self.assertTrue(launch_success) check_result = alarm_mgr.check_threads_state() self.assertFalse(check_result) check_result = alarm_mgr.check_threads_state() self.assertTrue(check_result) # Now we stop a running thread bypassing AlarmManager public methods alarm_mgr._AlarmManager__alarm_threads[0].stop() while alarm_mgr._AlarmManager__alarm_threads[0].isAlive(): time.sleep(0.1) check_result = alarm_mgr.check_threads_state() self.assertFalse(check_result) check_result = alarm_mgr.check_threads_state() self.assertTrue(check_result)
def set_snooze_time(snooze_time): """ Static method, sets the current snooze time interval. :param snooze_time: Integer, new snooze time in minutes. :return: Boolean indicating the operation success. """ return AlarmDb().set_snooze_time(snooze_time)
def get_offset_alert_time(): """ Static method, gets the offset alert time (the time difference before or after the alarm alert is triggered), used to set some action. :return: Integer, the offset alert time in minutes. """ return AlarmDb().get_offset_alert_time()
def edit_alarm(self, alarm_id, hour=None, minute=None, days=None, enabled=None, label=None): """ Edits an alarm from the database with the input data. A new timestamp is set by the AlarmDb class if the edit is successful. :param alarm_id: Integer to indicate the ID of the alarm to be edited. :param hour: Integer to indicate the alarm hour. :param minute: Integer to indicate the alarm minute. :param days: 7-item list of booleans to indicate repeat weekdays. :param enabled: Boolean to indicate alarm enabled state. :param label: Strong to contain the alarm label. :return: Boolean indicating the success of the 'edit' operation. """ db = AlarmDb() # As the default values for AlarmDb.edit_alarm are all None as well we # can send all through as is. success = db.edit_alarm(alarm_id, hour=hour, minute=minute, days=days, enabled=enabled, label=label) # If a successful edit was carried, then make sure the alarm is launched if success is True: self.__set_alarm_thread(AlarmManager.get_alarm(alarm_id)) return success
def add_alarm(self, hour, minute, days=(False, False, False, False, False, False, False), enabled=True, label='', timestamp=None): """ Adds an alarm to the database with the input values. If saved successfully it is sent to __set_alarm_thread to see if it should be launched as an enabled alarm thread. :param hour: Integer to indicate the alarm hour. :param minute: Integer to indicate the alarm minute. :param days: 7-item list of booleans to indicate repeat weekdays. :param enabled: Boolean to indicate the alarm enabled state. :param label: Strong to contain the alarm label. :param timestamp: Time, in seconds since 1970, that this alarm was last modified. This value can be added in order to be able to synchronise alarms between different systems. :return: Integer indicating the newly created alarm ID, or None if fail. """ alarm = AlarmItem(hour, minute, days=days, enabled=enabled, label=label, timestamp=timestamp) if alarm is not None: alarm.id_ = AlarmDb().add_alarm(alarm) if alarm.id_ is not None: self.__set_alarm_thread(alarm) return alarm.id_ return None
def test_get_wrong_entry(self): """ Loads 5 alarms and then tries to access an invalid alarm. """ adh = AlarmDb(self.db_name) self.only_five_entries(adh) # ID 7 does not exists alarm = adh.get_alarm(7) self.assertIsNone(alarm)
def get_all_disabled_alarms(): """ Gets all the disabled alarms from the database. :return: List of AlarmItems containing all enabled alarms. Returns an empty list if there aren't any. """ return AlarmDb().get_all_disabled_alarms()
def __init__(self, alert_callback=None, offset_alert_callback=None): """ On initialization we connect to the database and check if there are any alarms to load. If not, load a couple of dummy alarms. It also registers any alarms present in the database. :param alert_callback: Optional argument to register a callback function to be executed on an alarm alert. :param offset_alert_callback: Optional argument to register a callback function to be executed on an offset time of the alarm. """ # Save the alarm callback functions as a private member variable self.__alert_callback = alert_callback self.__offset_alert_callback = offset_alert_callback # Create a private member list for the alarm threads self.__alarm_threads = [] # Set dummy alarms if database empty if AlarmDb().get_number_of_alarms() == 0: self.load_dummy_alarms() # Register and launch any active (enabled with repeat days) alarms # from the database alarms = AlarmManager.get_all_active_alarms() for alarm in alarms: self.__set_alarm_thread(alarm)
def get_all_alarms(): """ Static method, gets all the alarms from the database. :return: List of AlarmItems containing all alarms. Returns an empty list if there aren't any. """ return AlarmDb().get_all_alarms()
def test_entry(self, mock_time): """ Adds an entry to the database and deletes it. """ hour = 13 minute = 35 mock_timestamp = 12341234 mock_time.return_value = mock_timestamp adh = AlarmDb(self.db_name) # Test an entry with the minimum amount of arguments and check for # default values test_alarm = AlarmItem(hour, minute) test_alarm.id_ = adh.add_alarm(test_alarm) # Test that the alarm object inserted has its member variable edited # with the new timestamp self.assertEqual(mock_timestamp, test_alarm.timestamp) # Check variables with a new alarm with data retrieved directly from db retrieved_alarm = adh.get_alarm(test_alarm.id_) self.assertEqual(hour, retrieved_alarm.hour) self.assertEqual(minute, retrieved_alarm.minute) self.assertEqual(test_alarm.monday, retrieved_alarm.monday) self.assertEqual(test_alarm.tuesday, retrieved_alarm.tuesday) self.assertEqual(test_alarm.wednesday, retrieved_alarm.wednesday) self.assertEqual(test_alarm.thursday, retrieved_alarm.thursday) self.assertEqual(test_alarm.friday, retrieved_alarm.friday) self.assertEqual(test_alarm.saturday, retrieved_alarm.saturday) self.assertEqual(test_alarm.sunday, retrieved_alarm.sunday) self.assertEqual(test_alarm.enabled, retrieved_alarm.enabled) self.assertEqual(test_alarm.label, retrieved_alarm.label) self.assertEqual(mock_timestamp, retrieved_alarm.timestamp) # Test with all possible arguments days = (False, False, True, False, False, True, False) enabled = False label = 'Test alarm label' timestamp = 98765432 test_alarm = AlarmItem(hour, minute, days=days, enabled=enabled, label=label, timestamp=timestamp) test_alarm.id_ = adh.add_alarm(test_alarm) # Check that the timestamp value from the alarm instance was not # modified with the present (in this case the mocked) timestamp self.assertEqual(timestamp, test_alarm.timestamp) # Check variables with a new alarm with data retrieved directly from db retrieved_alarm = adh.get_alarm(test_alarm.id_) self.assertEqual(hour, retrieved_alarm.hour) self.assertEqual(minute, retrieved_alarm.minute) self.assertEqual(days[0], retrieved_alarm.monday) self.assertEqual(days[1], retrieved_alarm.tuesday) self.assertEqual(days[2], retrieved_alarm.wednesday) self.assertEqual(days[3], retrieved_alarm.thursday) self.assertEqual(days[4], retrieved_alarm.friday) self.assertEqual(days[5], retrieved_alarm.saturday) self.assertEqual(days[6], retrieved_alarm.sunday) self.assertEqual(enabled, retrieved_alarm.enabled) self.assertEqual(label, retrieved_alarm.label) self.assertEqual(timestamp, retrieved_alarm.timestamp)
def test_edit_alarm_single(self): """ Adds an alarm, edits a single value and checks all the others remain the same. """ adh = AlarmDb(self.db_name) alarm_test = AlarmItem(13, 35, enabled=True, label='yes', days=(True, False, True, False, True, False, True)) # Check the timestamp changes on add_alarm original_timestamp = alarm_test.timestamp alarm_test.id_ = adh.add_alarm(alarm_test) self.assertNotEqual(alarm_test.timestamp, original_timestamp) # Edit alarm, check new data and different timestamp original_timestamp = alarm_test.timestamp time.sleep(1) edit_success = adh.edit_alarm(alarm_test.id_, minute=0) self.assertTrue(edit_success) edited_alarm = adh.get_alarm(alarm_test.id_) self.assertGreater(edited_alarm.timestamp, original_timestamp) self.assertEqual(edited_alarm.hour, 13) self.assertEqual(edited_alarm.minute, 0) self.assertTrue(edited_alarm.monday) self.assertFalse(edited_alarm.tuesday) self.assertTrue(edited_alarm.wednesday) self.assertFalse(edited_alarm.thursday) self.assertTrue(edited_alarm.friday) self.assertFalse(edited_alarm.saturday) self.assertTrue(edited_alarm.sunday) self.assertTrue(edited_alarm.enabled) self.assertEqual(edited_alarm.label, 'yes') # Test with opposite initial values alarm_test = AlarmItem(10, 20, enabled=False, label='no', days=(False, True, False, True, False, True, False)) alarm_test.id_ = adh.add_alarm(alarm_test) edit_success = adh.edit_alarm(alarm_test.id_, hour=0) self.assertTrue(edit_success) edited_alarm = adh.get_alarm(alarm_test.id_) self.assertEqual(edited_alarm.hour, 0) self.assertEqual(edited_alarm.minute, 20) self.assertFalse(edited_alarm.monday) self.assertTrue(edited_alarm.tuesday) self.assertFalse(edited_alarm.wednesday) self.assertTrue(edited_alarm.thursday) self.assertFalse(edited_alarm.friday) self.assertTrue(edited_alarm.saturday) self.assertFalse(edited_alarm.sunday) self.assertFalse(edited_alarm.enabled) self.assertEqual(edited_alarm.label, 'no')
def test_empty_table_zero_alarms(self): """ Check that an empty table returns a 0 length list of items """ adh = AlarmDb(self.db_name) adh.delete_all_alarms() number_of_alarms = adh.get_number_of_alarms() all_alarms = adh.get_all_alarms() self.assertEqual(number_of_alarms, 0) self.assertEqual(len(all_alarms), 0)
def get_alarm(alarm_id): """ Get the alarm with the given ID from the database. :param alarm_id: Integer to indicate the primary key of the Alarm to get. :return: AlarmItem with the alarm data, or None if id could not be found. """ return AlarmDb().get_alarm(alarm_id)
def set__offset_alert_time(offset_alert_time): """ Static method, sets the offset alert time (the time before or after the alarm alert is triggered), used to set some additional action to the alarm alert. :param offset_alert_time: Integer, offset alert time in minutes. :return: Boolean indicating the operation success. """ return AlarmDb().set_offset_alert_time(offset_alert_time)
def delete_alarm(self, alarm_id): """ Remove the alarm with the given ID from the database and remove its alarm thread. :param alarm_id: Integer to indicate the primary key of the Alarm to be removed. :return: Boolean indicating the success of the 'delete alarm' operation. """ # First we need to ensure it there is no alarm thread running for it self.__stop_alarm_thread(alarm_id) # Remove it from the database return AlarmDb().delete_alarm(alarm_id)
def update_alarm(alarm): """ Updates the alarm in the database with an AlarmItem input data. This method also updates the timestamp stored into the instance passed as an argument. :param alarm: AlarmItem instance with data to update the database. :return: Boolean indicating the success of the 'update' operation. """ if isinstance(alarm, AlarmItem): success = AlarmDb().update_alarm(alarm) else: success = False return success
def test_create_instance(self): """ Simply creates an instance with an input file and checks the database file has been created. """ db_file = '%s.db' % self.db_name # Ensure the file is not there if os.path.isfile(db_file): os.remove(db_file) self.assertFalse(os.path.isfile(db_file)) adh = AlarmDb(self.db_name) adh._AlarmDb__connect_alarms() self.assertTrue(os.path.isfile(db_file))
def test_reset_settings(self): """ Test reset settings. """ adh = AlarmDb(self.db_name) success = adh.set_snooze_time(321) self.assertTrue(success) success = adh.set_offset_alert_time(123) self.assertTrue(success) self.assertEquals(adh.get_snooze_time(), 321) self.assertEquals(adh.get_offset_alert_time(), 123) success = adh.reset_settings() self.assertTrue(success) self.assertNotEquals(adh.get_snooze_time(), 321) self.assertNotEquals(adh.get_offset_alert_time(), 123)
def delete_all_alarms(self): """ Removes all alarm threads and alarms from the database. :return: Boolean indicating the success of the 'delete all' operation. """ # Ensure there are no alarm threads running anymore thread_success = self.__stop_all_alarm_threads() # Remove from database db_success = AlarmDb().delete_all_alarms() if thread_success is True and db_success is True: return True else: return False
def test_get_alarm_and_delete(self): """ Adds 5 alarms into the database, then it removes one, and then all the rest. """ adh = AlarmDb(self.db_name) self.only_five_entries(adh) retrieved_alarm = adh.get_alarm(3) # AlarmItem(15, 37) id=3 self.assertEqual(retrieved_alarm.hour, 15) self.assertEqual(retrieved_alarm.minute, 37) delete_success = adh.delete_alarm(3) self.assertTrue(delete_success) retrieved_alarm = adh.get_alarm(3) # AlarmItem(15, 37) id=3 self.assertIsNone(retrieved_alarm) delete_success = adh.delete_all_alarms() self.assertTrue(delete_success)
def test_update_alarm(self): """ Creates an alarm and update it. """ adh = AlarmDb(self.db_name) adh.delete_all_alarms() alarm_test = AlarmItem(13, 35, days=(False, False, False, False, False, False, False), enabled=True, label='') original_timestamp = alarm_test.timestamp # Add the alarm to the database and check the timestamp has been set alarm_test.id_ = adh.add_alarm(alarm_test) self.assertNotEqual(alarm_test.timestamp, original_timestamp) original_timestamp = alarm_test.timestamp # Create a new AlarmItem with the same id and timestamp to update the db alarm_updated = AlarmItem(21, 12, days=(True, True, True, True, True, True, True), enabled=False, label='new label', alarm_id=alarm_test.id_, timestamp=original_timestamp) time.sleep(1) update_success = adh.update_alarm(alarm_updated) self.assertEqual(update_success, True) self.assertNotEqual(alarm_updated.timestamp, original_timestamp) # Check the new data has replaced the old, retrieved_alarm = adh.get_alarm(alarm_test.id_) self.assertEqual(retrieved_alarm.hour, 21) self.assertEqual(retrieved_alarm.minute, 12) self.assertTrue(retrieved_alarm.monday) self.assertTrue(retrieved_alarm.tuesday) self.assertTrue(retrieved_alarm.wednesday) self.assertTrue(retrieved_alarm.thursday) self.assertTrue(retrieved_alarm.friday) self.assertTrue(retrieved_alarm.saturday) self.assertTrue(retrieved_alarm.sunday) self.assertFalse(retrieved_alarm.enabled) self.assertEqual(retrieved_alarm.label, 'new label') self.assertEqual(retrieved_alarm.timestamp, alarm_updated.timestamp) self.assertGreater(retrieved_alarm.timestamp, original_timestamp)
def test_get_all_alarms(self): """ Adds 5 alarms to the db, then checks all are retrieved. Also test the get_number_of_alarms method. """ adh = AlarmDb(self.db_name) self.only_five_entries(adh) number_of_alarms = adh.get_number_of_alarms() all_alarms = adh.get_all_alarms() self.assertEqual(number_of_alarms, 5) self.assertEqual(number_of_alarms, len(all_alarms)) hour = 13 minute = 35 for alarm in all_alarms: self.assertEqual(hour, alarm.hour) self.assertEqual(minute, alarm.minute) hour += 1 minute += 1
def test_snooze_time(self): """ Test the accessor for the db snooze time setting. """ adh = AlarmDb(self.db_name) # Valid data success = adh.set_snooze_time(5) self.assertTrue(success) self.assertEquals(adh.get_snooze_time(), 5) # Invalid data should maintain old value success = adh.set_snooze_time(-1) self.assertFalse(success) self.assertEquals(adh.get_snooze_time(), 5) success = adh.set_snooze_time(2.5) self.assertFalse(success) self.assertEquals(adh.get_snooze_time(), 5) success = adh.set_snooze_time('3') self.assertFalse(success) self.assertEquals(adh.get_snooze_time(), 5)
def test_get_all_enable_alarms(self): """ Adds 5 alarms into the database, 3 enabled and 2 disabled. Checks the enabled and disabled getters are working. """ adh = AlarmDb(self.db_name) adh.delete_all_alarms() adh.add_alarm(AlarmItem(13, 35, days=self.random_days, enabled=True)) # id 1 adh.add_alarm(AlarmItem(14, 36, days=self.random_days, enabled=False)) # id 2 adh.add_alarm(AlarmItem(15, 37, days=self.random_days, enabled=True)) # id 3 adh.add_alarm(AlarmItem(16, 38, days=self.random_days, enabled=False)) # id 4 adh.add_alarm(AlarmItem(17, 39, days=self.random_days, enabled=True)) # id 5 enabled_alarms = adh.get_all_enabled_alarms() disabled_alarms = adh.get_all_disabled_alarms() self.assertEqual(len(enabled_alarms), 3) self.assertEqual(len(disabled_alarms), 2)
def test_edit_alarm(self): """ Creates an alarm and edits it. """ adh = AlarmDb(self.db_name) adh.delete_all_alarms() alarm_test = AlarmItem(13, 35, days=(False, False, False, False, False, False, False), enabled=True, label='') # Check the timestamp changes on add_alarm original_timestamp = alarm_test.timestamp alarm_test.id_ = adh.add_alarm(alarm_test) self.assertNotEqual(alarm_test.timestamp, original_timestamp) # Edit alarm, check new data and different timestamp original_timestamp = alarm_test.timestamp time.sleep(1) edit_success = adh.edit_alarm(alarm_test.id_, 11, 22, enabled=False, label='New label', days=(True, True, True, True, True, True, True)) self.assertEqual(edit_success, True) edited_alarm = adh.get_alarm(alarm_test.id_) self.assertGreater(edited_alarm.timestamp, original_timestamp) self.assertEqual(edited_alarm.hour, 11) self.assertEqual(edited_alarm.minute, 22) self.assertTrue(edited_alarm.monday) self.assertTrue(edited_alarm.tuesday) self.assertTrue(edited_alarm.wednesday) self.assertTrue(edited_alarm.thursday) self.assertTrue(edited_alarm.friday) self.assertTrue(edited_alarm.saturday) self.assertTrue(edited_alarm.sunday) self.assertFalse(edited_alarm.enabled) self.assertEqual(edited_alarm.label, 'New label')
def test_offset_alert_time(self): """ Test the accessor for the db offset_alert time setting. """ adh = AlarmDb(self.db_name) # Valid negative data success = adh.set_offset_alert_time(-1) self.assertTrue(success) self.assertEquals(adh.get_offset_alert_time(), -1) # Valid positive data success = adh.set_offset_alert_time(5) self.assertTrue(success) self.assertEquals(adh.get_offset_alert_time(), 5) # Invalid data should maintain old value success = adh.set_offset_alert_time(2.5) self.assertFalse(success) self.assertEquals(adh.get_offset_alert_time(), 5) success = adh.set_offset_alert_time('3') self.assertFalse(success) self.assertEquals(adh.get_offset_alert_time(), 5)
def test_export_alarms_json(self): """ Tests that the test_export_alarms_json creates a correct json string for all the 5 alarms inputted into the database. """ adh = AlarmDb(self.db_name) self.only_five_entries(adh) json_str = adh.export_alarms_json() alarms_parsed = json.loads(json_str) def test_alarm(test, alarm, hour, minute, monday, tuesday, wednesday, thursday, friday, saturday, sunday, enabled, label): test.assertEqual(alarm.hour, hour) test.assertEqual(alarm.minute, minute) test.assertEqual(alarm.monday, monday) test.assertEqual(alarm.tuesday, tuesday) test.assertEqual(alarm.wednesday, wednesday) test.assertEqual(alarm.thursday, thursday) test.assertEqual(alarm.friday, friday) test.assertEqual(alarm.saturday, saturday) test.assertEqual(alarm.sunday, sunday) test.assertEqual(alarm.enabled, enabled) test.assertEqual(alarm.label, label) for i in range(0, 5): test_alarm(self, adh.get_alarm(i + 1), alarms_parsed['alarms'][i]['hour'], alarms_parsed['alarms'][i]['minute'], alarms_parsed['alarms'][i]['monday'], alarms_parsed['alarms'][i]['tuesday'], alarms_parsed['alarms'][i]['wednesday'], alarms_parsed['alarms'][i]['thursday'], alarms_parsed['alarms'][i]['friday'], alarms_parsed['alarms'][i]['saturday'], alarms_parsed['alarms'][i]['sunday'], alarms_parsed['alarms'][i]['enabled'], alarms_parsed['alarms'][i]['label'])
def get_number_of_alarms(): """ Gets the number of alarms stored in the database. :return: Integer indicating the number of alarms in the db. """ return AlarmDb().get_number_of_alarms()
def test_entry_error(self): """ Tries to add an entry with an incorrect number of arguments. """ adh = AlarmDb(self.db_name) self.assertRaises(TypeError, adh.add_alarm, AlarmItem(0, 0), 0) self.assertRaises(TypeError, adh.add_alarm)
def get_snooze_time(): """ Static method, gets the current set snooze time interval. :return: Integer with the snooze time interval in minutes. """ return AlarmDb().get_snooze_time()