def testBadFile(self): with update_check.UpdateCheckData() as checker: self.assertEqual(0, checker.LastUpdateCheckTime()) checker._data.last_update_check_time = 5 self.assertEqual(5, checker.LastUpdateCheckTime()) with open(config.Paths().update_check_cache_path, 'w') as f: f.write('junk') with update_check.UpdateCheckData() as checker: # Make sure there was no error and the file just gets reset. self.assertEqual(0, checker.LastUpdateCheckTime())
def testUpdatesAvailableNoCheckComponents(self): with update_check.UpdateCheckData() as checker: # Everything starts as empty because the cache doesn't exist. self.assertFalse(checker.UpdatesAvailable()) snapshot = self.CreateSnapshotFromComponents( 20000101000000, [], None, notifications=[{ 'id': 'test', 'condition': { 'check_components': False } }]) checker.SetFromSnapshot(snapshot, True) self.assertEqual(1, len(checker._data.notifications)) self.assertFalse(checker.UpdatesAvailable()) snapshot = self.CreateSnapshotFromComponents( 20000101000001, [], None, notifications=[{ 'id': 'test', 'condition': { 'check_components': True } }]) checker.SetFromSnapshot(snapshot, True) self.assertEqual(1, len(checker._data.notifications)) self.assertTrue(checker.UpdatesAvailable())
def testBasicUpdateData(self): time_mock = self.StartObjectPatch(time, 'time', return_value=1) with update_check.UpdateCheckData() as checker: # Everything starts as empty because the cache doesn't exist. self.assertEqual(0, checker.LastUpdateCheckTime()) self.assertEqual(0, checker.LastUpdateCheckRevision()) self.assertFalse(checker.UpdatesAvailable()) self.assertEqual(checker.SecondsSinceLastUpdateCheck(), 1) self.assertFalse(checker.ShouldDoUpdateCheck()) # Time elapses, should report that we should do an update check. check_plus_one = ( update_check.UpdateCheckData.UPDATE_CHECK_FREQUENCY_IN_SECONDS + 1) time_mock.return_value = check_plus_one self.assertEqual(checker.SecondsSinceLastUpdateCheck(), check_plus_one) self.assertTrue(checker.ShouldDoUpdateCheck()) # Set the current state from this snapshot. snapshot = self.CreateSnapshotFromComponents( 20000101000000, [], None, notifications=[{ 'id': 'basic', 'trigger': { 'frequency': 2 }, 'notification': { 'custom_message': 'custom' } }]) checker.SetFromSnapshot(snapshot, True) # Check that the update was done, and all attributes cached correctly. self.assertEqual(check_plus_one, checker.LastUpdateCheckTime()) self.assertEqual(20000101000000, checker.LastUpdateCheckRevision()) self.assertTrue(checker.UpdatesAvailable()) self.assertEqual(checker.SecondsSinceLastUpdateCheck(), 0) self.assertFalse(checker.ShouldDoUpdateCheck()) # Notify that an update is available because we haven't before. self.StartObjectPatch(log._ConsoleWriter, 'isatty').return_value = True checker.Notify(command_path=None) self.AssertErrContains('custom') self.assertEqual(check_plus_one, checker._data.last_nag_times.get('basic')) self.ClearErr() # Time advances, but not enough to nag again. time_mock.return_value = check_plus_one + 1 checker.Notify(command_path=None) self.AssertErrNotContains('custom') self.assertEqual(check_plus_one, checker._data.last_nag_times.get('basic')) # Time advances enough to nag again. Check that nag time is updated. time_mock.return_value = check_plus_one + 2 checker.Notify(command_path=None) self.AssertErrContains('custom') self.assertEqual(check_plus_one + 2, checker._data.last_nag_times.get('basic')) # Reload the cache and make sure everything was saved correctly. with update_check.UpdateCheckData() as checker: self.assertEqual(check_plus_one, checker.LastUpdateCheckTime()) self.assertEqual(20000101000000, checker.LastUpdateCheckRevision()) self.assertTrue(checker.UpdatesAvailable()) self.assertEqual(checker.SecondsSinceLastUpdateCheck(), 2) self.assertFalse(checker.ShouldDoUpdateCheck()) self.assertEqual(check_plus_one + 2, checker._data.last_nag_times.get('basic'))
def testNags(self): def CheckOutput(basic, another): self.AssertErrContains('basic', success=basic) self.AssertErrContains('another', success=another) self.AssertErrNotContains('not_activated') self.ClearErr() time_mock = self.StartObjectPatch(time, 'time', return_value=0) out_mock = self.StartObjectPatch(log._ConsoleWriter, 'isatty') out_mock.return_value = True snapshot = self.CreateSnapshotFromComponents(20000101000000, [], None, notifications=[{ 'id': 'basic', 'trigger': { 'frequency': 2, 'command_regex': r'gcloud\..+' }, 'notification': { 'custom_message': 'basic' } }, { 'id': 'another', 'trigger': { 'frequency': 3 }, 'notification': { 'custom_message': 'another' } }, { 'id': 'not_activated', 'condition': { 'version_regex': 'xxxxxxx' }, 'trigger': { 'frequency': 1 }, 'notification': { 'custom_message': 'not_activated' } }]) with update_check.UpdateCheckData() as checker: checker.SetFromSnapshot(snapshot, True) # Ensure 'not_activated' did not get picked up. self.assertEqual(['basic', 'another'], [n.id for n in checker._data.notifications]) # Time 0, nothing to notify checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Time 1, nothing to notify time_mock.return_value = 1 checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Time 2, turn not in a terminal, don't notify time_mock.return_value = 2 out_mock.return_value = False checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Time 2, notify 'basic' out_mock.return_value = True # Command is not correct for notification. checker.Notify(command_path='asdf') CheckOutput(False, False) # Matching command should notify. checker.Notify(command_path='gcloud.foo') CheckOutput(True, False) # Second time won't notify because time has not expired checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Time 4, both are eligible, 'basic' goes first because it comes first # in the list. time_mock.return_value = 4 checker.Notify(command_path='gcloud.foo') CheckOutput(True, False) # On second command, 'basic' has already been notified so now 'another' # goes. checker.Notify(command_path='gcloud.foo') CheckOutput(False, True) # Time 5, nothing to notify time_mock.return_value = 5 checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Time 6, notify 'basic' time_mock.return_value = 6 checker.Notify(command_path='gcloud.foo') CheckOutput(True, False) checker.Notify(command_path='gcloud.foo') CheckOutput(False, False) # Make sure the last nag times are correctly recorded. self.assertEqual(6, checker._data.last_nag_times.get('basic')) self.assertEqual(4, checker._data.last_nag_times.get('another')) # Remove a notification and make sure the last nag time gets cleaned up # and the other is not cleared. del snapshot.sdk_definition.notifications[0] checker.SetFromSnapshot(snapshot, True, force=True) self.assertNotIn('basic', checker._data.last_nag_times) self.assertEqual(4, checker._data.last_nag_times.get('another')) # Set from incompat schema. Make sure we get a single notification for # that and remove others. checker.SetFromIncompatibleSchema() self.assertEqual(['incompatible'], [n.id for n in checker._data.notifications]) self.assertEqual({}, checker._data.last_nag_times) # Hasn't been enough time to notify checker.Notify(command_path='gcloud.foo') self.AssertErrNotContains('gcloud components update') self.ClearErr() # Now there is enough time to notify. time_mock.return_value = 604801 checker.Notify(command_path='gcloud.foo') self.AssertErrContains('gcloud components update') self.ClearErr() # Make sure last nag is recorded per usual. self.assertEqual(604801, checker._data.last_nag_times.get('incompatible')) checker.SetFromIncompatibleSchema() # Make sure last nag was not cleared. self.assertEqual(604801, checker._data.last_nag_times.get('incompatible'))
def testConditionMatching(self): freq = update_check.UpdateCheckData.UPDATE_CHECK_FREQUENCY_IN_SECONDS time_mock = self.StartObjectPatch(time, 'time') time_mock.return_value = freq self.StartPatch( 'googlecloudsdk.core.config.INSTALLATION_CONFIG.version', new='1.2.3') self.StartPatch( 'googlecloudsdk.core.config.INSTALLATION_CONFIG.revision', new=20000101000000) with update_check.UpdateCheckData() as checker: self.assertEqual(checker.SecondsSinceLastUpdateCheck(), freq) self.assertTrue(checker.ShouldDoUpdateCheck()) # Set the current state from this snapshot. snapshot = self.CreateSnapshotFromComponents( 20000101000005, [], None, notifications=[ { 'id': 'basic', 'trigger': { 'frequency': 2 }, 'notification': { 'custom_message': 'custom' } }, ]) # Doesn't match start version snapshot.sdk_definition.notifications[ 0].condition = schemas.Condition(start_version='2.0.0', end_version=None, version_regex=None, age=None, check_components=True) checker.SetFromSnapshot(snapshot, True, force=True) self.assertFalse(checker.UpdatesAvailable()) # Doesn't match end version snapshot.sdk_definition.notifications[ 0].condition = schemas.Condition(start_version=None, end_version='0.0.0', version_regex=None, age=None, check_components=True) checker.SetFromSnapshot(snapshot, True, force=True) self.assertFalse(checker.UpdatesAvailable()) # Doesn't match age snapshot.sdk_definition.notifications[ 0].condition = schemas.Condition(start_version=None, end_version=None, version_regex=None, age=100, check_components=True) checker.SetFromSnapshot(snapshot, True, force=True) self.assertFalse(checker.UpdatesAvailable()) # Doesn't match check_components. snapshot.sdk_definition.notifications[ 0].condition = schemas.Condition(start_version=None, end_version=None, version_regex=None, age=None, check_components=True) checker.SetFromSnapshot(snapshot, False, force=True) self.assertFalse(checker.UpdatesAvailable()) # Matches. snapshot.sdk_definition.notifications[ 0].condition = schemas.Condition(None, None, None, None, True) checker.SetFromSnapshot(snapshot, True, force=True) self.assertTrue(checker.UpdatesAvailable()) # Add in another notification, check that they both get stored. snapshot.sdk_definition.notifications.append( schemas.NotificationSpec.FromDictionary({'id': 'default'})) checker.SetFromSnapshot(snapshot, True, force=True) self.assertEqual(['basic', 'default'], [n.id for n in checker._data.notifications]) # Remove that notification, ensure it gets removed. del snapshot.sdk_definition.notifications[1] checker.SetFromSnapshot(snapshot, True, force=True) self.assertEqual(['basic'], [n.id for n in checker._data.notifications])