def test_no_update_available_version(self): # No update is available, so the target version number is zero. self._setup_server_keyrings() touch_build(1600) update = Mediator().check_for_update() self.assertFalse(update.is_available) self.assertEqual(update.version, '')
def test_no_update_available_newer(self): # Because our build number is higher than the latest available in the # index file, there is no update available. self._setup_server_keyrings() touch_build(1700) update = Mediator().check_for_update() self.assertFalse(update.is_available)
def test_download_winners_signed_by_wrong_key(self): # There is a device key, but the image files are signed by the image # signing key, which according to the spec means the files are not # signed correctly. setup_keyrings() # To set up the device signing key, we need to load this channels.json # file and copy the device keyring to the server. copy('winner.channels_02.json', self._serverdir, 'channels.json') sign(os.path.join(self._serverdir, 'channels.json'), 'image-signing.gpg') setup_keyring_txz( 'device-signing.gpg', 'image-signing.gpg', dict(type='device-signing'), os.path.join(self._serverdir, 'stable', 'nexus7', 'device.tar.xz')) sign(os.path.join(self._serverdir, self._indexpath), 'device-signing.gpg') # All the downloadable files are now signed with a bogus key. setup_index('winner.index_02.json', self._serverdir, 'spare.gpg') touch_build(100) # Run the state machine until just before we download the files. state = State() state.run_until('download_files') # The next state transition will fail because of the missing signature. self.assertRaises(SignatureError, next, state) # There are no downloaded files. txtfiles = set(filename for filename in os.listdir(config.tempdir) if os.path.splitext(filename)[1] == '.txt') self.assertEqual(len(txtfiles), 0)
def test_download_winners_overwrite(self): # Check that all the winning path's files are downloaded, even if # those files already exist in their destination paths. setup_keyrings() state = State() touch_build(100) # Run the state machine until we download the files. for basename in '56789abcd': base = os.path.join(config.updater.cache_partition, basename) path = base + '.txt' with open(path, 'w', encoding='utf-8') as fp: print('stale', file=fp) state.run_thru('download_files') # The B path files contain their checksums. def assert_file_contains(filename, contents): path = os.path.join(config.updater.cache_partition, filename) with open(path, encoding='utf-8') as fp: self.assertEqual(fp.read(), contents) assert_file_contains('5.txt', '345') assert_file_contains('6.txt', '456') assert_file_contains('7.txt', '567') # Delta B.1 files. assert_file_contains('8.txt', '678') assert_file_contains('9.txt', '789') assert_file_contains('a.txt', '89a') # Delta B.2 files. assert_file_contains('b.txt', '9ab') assert_file_contains('d.txt', 'fed') assert_file_contains('c.txt', 'edc')
def test_download_winners(self): # Check that all the winning path's files are downloaded. setup_keyrings() state = State() touch_build(100) # Run the state machine until we download the files. state.run_thru('download_files') # The B path files contain their checksums. def assert_file_contains(filename, contents): path = os.path.join(config.updater.cache_partition, filename) with open(path, encoding='utf-8') as fp: self.assertEqual(fp.read(), contents) assert_file_contains('5.txt', '345') assert_file_contains('6.txt', '456') assert_file_contains('7.txt', '567') # Delta B.1 files. assert_file_contains('8.txt', '678') assert_file_contains('9.txt', '789') assert_file_contains('a.txt', '89a') # Delta B.2 files. assert_file_contains('b.txt', '9ab') assert_file_contains('d.txt', 'fed') assert_file_contains('c.txt', 'edc')
def test_calculate_winner(self): # Calculate the winning upgrade path. setup_keyrings() state = State() touch_build(100) # Run the state machine long enough to get the candidates and winner. state.run_thru('calculate_winner') # There are three candidate upgrade paths. descriptions = [] for image in state.winner: # There's only one description per image so order doesn't matter. descriptions.extend(image.descriptions.values()) self.assertEqual(descriptions, ['Full B', 'Delta B.1', 'Delta B.2'])
def test_no_download_winners_with_bad_signature(self): # If one of the download files has a bad a signature, none of the # downloaded files are available. setup_keyrings() state = State() touch_build(100) # Break a signature sign(os.path.join(self._serverdir, '6', '7', '8.txt'), 'spare.gpg') # Run the state machine to calculate the winning path. state.run_until('download_files') # The next state transition will fail because of the missing signature. self.assertRaises(SignatureError, next, state) # There are no downloaded files. txtfiles = set(filename for filename in os.listdir(config.tempdir) if os.path.splitext(filename)[1] == '.txt') self.assertEqual(len(txtfiles), 0)
def test_no_download_winners_with_missing_signature(self): # If one of the download files is missing a signature, none of the # files get downloaded and get_files() fails. setup_keyrings() state = State() touch_build(100) # Remove a signature. os.remove(os.path.join(self._serverdir, '6/7/8.txt.asc')) # Run the state machine to calculate the winning path. state.run_until('download_files') # The next state transition will fail because of the missing signature. self.assertRaises(FileNotFoundError, next, state) # There are no downloaded files. txtfiles = set(filename for filename in os.listdir(config.tempdir) if os.path.splitext(filename)[1] == '.txt') self.assertEqual(len(txtfiles), 0, txtfiles)
def test_download_winners_bad_checksums(self): # Similar to the various good paths, except because the checksums are # wrong in this index.json file, we'll get a error when downloading. copy('winner.index_01.json', self._serverdir, self._indexpath) sign(os.path.join(self._serverdir, self._indexpath), 'image-signing.gpg') setup_index('winner.index_01.json', self._serverdir, 'image-signing.gpg') setup_keyrings() state = State() touch_build(100) # Run the state machine until we're prepped to download state.run_until('download_files') # Now try to download the files and get the error. with self.assertRaises(FileNotFoundError) as cm: next(state) self.assertIn('HASH ERROR', str(cm.exception))
def test_download_winners_signed_by_device_key(self): # Check that all the winning path's files are downloaded, even when # they are signed by the device key instead of the image signing # master. setup_keyrings() # To set up the device signing key, we need to load channels_03.json # and copy the device keyring to the server. copy('winner.channels_02.json', self._serverdir, 'channels.json') sign(os.path.join(self._serverdir, 'channels.json'), 'image-signing.gpg') setup_keyring_txz( 'device-signing.gpg', 'image-signing.gpg', dict(type='device-signing'), os.path.join(self._serverdir, 'stable', 'nexus7', 'device.tar.xz')) # The index.json file and all the downloadable files must now be # signed with the device key. sign(os.path.join(self._serverdir, self._indexpath), 'device-signing.gpg') setup_index('winner.index_02.json', self._serverdir, 'device-signing.gpg') touch_build(100) # Run the state machine until we download the files. state = State() state.run_thru('download_files') # The B path files contain their checksums. def assert_file_contains(filename, contents): path = os.path.join(config.updater.cache_partition, filename) with open(path, encoding='utf-8') as fp: self.assertEqual(fp.read(), contents) assert_file_contains('5.txt', '345') assert_file_contains('6.txt', '456') assert_file_contains('7.txt', '567') # Delta B.1 files. assert_file_contains('8.txt', '678') assert_file_contains('9.txt', '789') assert_file_contains('a.txt', '89a') # Delta B.2 files. assert_file_contains('b.txt', '9ab') assert_file_contains('d.txt', 'fed') assert_file_contains('c.txt', 'edc')
def test_last_date_no_permission(self, config): # LP: #1365761 reports a problem where stat'ing /userdata/.last_update # results in a PermissionError. In that case it should fall back to # using the mtimes of the config.d ini files. timestamp_1 = int(datetime(2022, 1, 2, 3, 4, 5).timestamp()) touch_build(2, timestamp_1) # Now create an unstat'able /userdata/.last_update file. with ExitStack() as stack: tmpdir = stack.enter_context(temporary_directory()) userdata_path = Path(tmpdir) / '.last_update' stack.enter_context( patch('systemimage.helpers.LAST_UPDATE_FILE', str(userdata_path))) timestamp = int(datetime(2012, 11, 10, 9, 8, 7).timestamp()) # Make the file unreadable. userdata_path.touch() os.utime(str(userdata_path), (timestamp, timestamp)) stack.callback(os.chmod, tmpdir, 0o777) os.chmod(tmpdir, 0o000) config.reload() # The last update date will be the date of the 99_build.ini file. self.assertEqual(last_update_date(), '2022-01-02 03:04:05')
def test_get_build_number_after_reload(self, config): # After a reload, the build number gets updated. self.assertEqual(config.build_number, 0) touch_build(801) config.reload() self.assertEqual(config.build_number, 801)
def test_get_build_number(self, config): # The current build number is stored in a file specified in the # configuration file. touch_build(1500) config.reload() self.assertEqual(config.build_number, 1500)