Ejemplo n.º 1
0
 def test_forked_paths(self):
     # We have a fork in the road.  There is a full update, but two deltas
     # with different versions point to the same base.  This will give us
     # two upgrade paths, both of which include the full.
     index = get_index('candidates.index_07.json')
     candidates = get_candidates(index, 1200)
     self.assertEqual(len(candidates), 2)
     # We can sort the paths by length.
     paths = sorted(candidates, key=len)
     # The shortest path gets us to 1302 in two steps.
     self.assertEqual(len(paths[0]), 2)
     self.assertEqual([image.version for image in paths[0]], [1300, 1302])
     descriptions = []
     for image in paths[0]:
         # There's only one description per image so order doesn't matter.
         descriptions.extend(image.descriptions.values())
     self.assertEqual(descriptions, ['Full 1', 'Delta 2'])
     # The longer path gets us to 1302 in three steps.
     self.assertEqual(len(paths[1]), 3)
     self.assertEqual([image.version for image in paths[1]],
                      [1300, 1301, 1302])
     descriptions = []
     for image in paths[1]:
         # There's only one description per image so order doesn't matter.
         descriptions.extend(image.descriptions.values())
     self.assertEqual(descriptions, ['Full 1', 'Delta 1', 'Delta 3'])
Ejemplo n.º 2
0
 def test_candidates(self):
     # Path B will win; it has one full and two deltas.
     index = get_index('candidates.index_13.json')
     candidates = get_candidates(index, 0)
     self.assertEqual(len(candidates), 3)
     path0 = candidates[0]
     self.assertEqual(descriptions(path0),
                      ['Full A', 'Delta A.1', 'Delta A.2'])
     path1 = candidates[1]
     self.assertEqual(descriptions(path1),
                      ['Full B', 'Delta B.1', 'Delta B.2'])
     path2 = candidates[2]
     self.assertEqual(descriptions(path2), ['Full C', 'Delta C.1'])
     # The version numbers use the new regime.
     self.assertEqual(path0[0].version, 300)
     self.assertEqual(path0[1].base, 300)
     self.assertEqual(path0[1].version, 301)
     self.assertEqual(path0[2].base, 301)
     self.assertEqual(path0[2].version, 304)
     winner = WeightedScorer().choose(candidates, 'devel')
     self.assertEqual(descriptions(winner),
                      ['Full B', 'Delta B.1', 'Delta B.2'])
     self.assertEqual(winner[0].version, 200)
     self.assertEqual(winner[1].base, 200)
     self.assertEqual(winner[1].version, 201)
     self.assertEqual(winner[2].base, 201)
     self.assertEqual(winner[2].version, 304)
Ejemplo n.º 3
0
 def test_filter_for_fulls_with_just_delta_candidates(self):
     # A candidate path that contains only deltas will have no filtered
     # paths if all the images are delta updates.
     index = get_index('candidates.index_11.json')
     candidates = get_candidates(index, 100)
     self.assertEqual(len(candidates), 1)
     filtered = full_filter(candidates)
     self.assertEqual(len(filtered), 0)
Ejemplo n.º 4
0
 def test_filter_for_deltas(self):
     # Filter the candidates, where the only available path is a delta path.
     index = get_index('candidates.index_11.json')
     candidates = get_candidates(index, 100)
     self.assertEqual(len(candidates), 1)
     filtered = delta_filter(candidates)
     self.assertEqual(len(filtered), 1)
     self.assertEqual(candidates, filtered)
Ejemplo n.º 5
0
 def test_filter_for_deltas_none_available(self):
     # Run a filter over the candidates, such that the only ones left are
     # those that start with and contain only deltas.  Since none of the
     # paths do so, tere are no candidates left.
     index = get_index('candidates.index_08.json')
     candidates = get_candidates(index, 600)
     filtered = delta_filter(candidates)
     self.assertEqual(len(filtered), 0)
Ejemplo n.º 6
0
 def test_tied_candidates(self):
     # LP: #1206866 - TypeError when two candidate paths scored equal.
     #
     # index_04.json was captured from real data causing the traceback.
     index = get_index('scores.index_04.json')
     candidates = get_candidates(index, 1)
     path = self.scorer.choose(candidates, 'devel')
     self.assertEqual(len(path), 1)
     self.assertEqual(path[0].version, 1800)
Ejemplo n.º 7
0
 def test_filter_for_multiple_deltas(self):
     # The candidate path has multiple deltas.  All are preserved.
     index = get_index('candidates.index_12.json')
     candidates = get_candidates(index, 100)
     filtered = delta_filter(candidates)
     self.assertEqual(len(filtered), 1)
     path = filtered[0]
     self.assertEqual(len(path), 3)
     self.assertEqual(descriptions(path), ['Delta A', 'Delta B', 'Delta C'])
Ejemplo n.º 8
0
 def test_pulled_update_insanely_positive_randint(self):
     # When the final image on an update path has a phase percentage of
     # zero, then regardless of the device's percentage (even if randint
     # returned some insane value), the candidate path is not okay.  In this
     # case, the `Full B` has phase of 0%.
     index = get_index('scores.index_01.json')
     candidates = get_candidates(index, 100)
     with patch('systemimage.scores.phased_percentage', return_value=1000):
         winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(len(winner), 0)
Ejemplo n.º 9
0
 def test_pulled_update(self):
     # When the final image on an update path has a phase percentage of
     # zero, then regardless of the device's percentage, the candidate path
     # is not okay.  In this case, the `Full B` has phase of 0%.
     index = get_index('scores.index_01.json')
     candidates = get_candidates(index, 100)
     with patch('systemimage.scores.phased_percentage', return_value=0):
         winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(descriptions(winner),
                      ['Full A', 'Delta A.1', 'Delta A.2'])
Ejemplo n.º 10
0
 def test_equal_phase_gets_update(self):
     # When the final image on an update path has a phase percentage exactly
     # equal to the device percentage, the candidate path is okay.  In this
     # case, the `Full B` has phase of 50%.
     index = get_index('scores.index_05.json')
     candidates = get_candidates(index, 100)
     with patch('systemimage.scores.phased_percentage', return_value=50):
         winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(descriptions(winner),
                      ['Full B', 'Delta B.1', 'Delta B.2'])
Ejemplo n.º 11
0
 def test_one_path_with_full_and_deltas(self):
     # There's one path to upgrade from our version to the final version.
     # This one starts at a full and includes several deltas.
     index = get_index('candidates.index_06.json')
     candidates = get_candidates(index, 1000)
     self.assertEqual(len(candidates), 1)
     path = candidates[0]
     self.assertEqual(len(path), 3)
     self.assertEqual([image.version for image in path], [1300, 1301, 1302])
     self.assertEqual(descriptions(path), ['Full 1', 'Delta 1', 'Delta 2'])
Ejemplo n.º 12
0
 def test_outside_phase_gets_update(self):
     # When the final image on an update path has a phase percentage lower
     # than the device percentage, the scorer falls back to the next
     # candidate path.
     index = get_index('scores.index_05.json')
     candidates = get_candidates(index, 100)
     with patch('systemimage.scores.phased_percentage', return_value=66):
         winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(descriptions(winner),
                      ['Full A', 'Delta A.1', 'Delta A.2'])
Ejemplo n.º 13
0
 def test_one_delta_based_on_us(self):
     # There is one delta in the test data that is based on us.
     index = get_index('candidates.index_04.json')
     candidates = get_candidates(index, 500)
     self.assertEqual(len(candidates), 1)
     path = candidates[0]
     # The path has exactly one image.
     self.assertEqual(len(path), 1)
     image = path[0]
     self.assertEqual(list(image.descriptions.values()), ['Delta 2'])
Ejemplo n.º 14
0
 def test_one_path_with_deltas(self):
     # Similar to above, except that because we're upgrading from the
     # version of the full, the path is only two images long, i.e. the
     # deltas.
     index = get_index('candidates.index_06.json')
     candidates = get_candidates(index, 1300)
     self.assertEqual(len(candidates), 1)
     path = candidates[0]
     self.assertEqual(len(path), 2)
     self.assertEqual([image.version for image in path], [1301, 1302])
     self.assertEqual(descriptions(path), ['Delta 1', 'Delta 2'])
Ejemplo n.º 15
0
 def test_one_path(self):
     index = get_index('scores.index_02.json')
     candidates = get_candidates(index, 600)
     # There's only one path.
     scores = self.scorer.score(candidates)
     # The score is 200 for the two extra bootme flags.
     self.assertEqual(scores, [200])
     # And we upgrade to the only path available.
     winner = self.scorer.choose(candidates, 'devel')
     # There are two images in the winning path.
     self.assertEqual(len(winner), 2)
     self.assertEqual([image.version for image in winner], [1300, 1301])
Ejemplo n.º 16
0
 def test_inside_phase_gets_update(self):
     # When the final image on an update path has a phase percentage higher
     # than the device percentage, the candidate path is okay.  In this
     # case, the `Full B` has phase of 50%.
     index = get_index('scores.index_05.json')
     candidates = get_candidates(index, 100)
     with patch('systemimage.scores.phased_percentage', return_value=22):
         winner = self.scorer.choose(candidates, 'devel')
         descriptions = []
         for image in winner:
             descriptions.extend(image.descriptions.values())
     self.assertEqual(descriptions, ['Full B', 'Delta B.1', 'Delta B.2'])
Ejemplo n.º 17
0
 def test_one_higher_full(self):
     # Our device is between the minversions of the two available fulls, so
     # the older one can be upgraded too.
     index = get_index('candidates.index_02.json')
     candidates = get_candidates(index, 800)
     # There is exactly one upgrade path.
     self.assertEqual(len(candidates), 1)
     path = candidates[0]
     # The path has exactly one image.
     self.assertEqual(len(path), 1)
     image = path[0]
     self.assertEqual(list(image.descriptions.values()),
                      ['New full build 1'])
Ejemplo n.º 18
0
 def test_two_deltas_based_on_us(self):
     # There are two deltas that are based on us, so both are candidates.
     # They get us to different final versions.
     index = get_index('candidates.index_05.json')
     candidates = get_candidates(index, 1100)
     self.assertEqual(len(candidates), 2)
     # Both candidate paths have exactly one image in them.  We can't sort
     # these paths, so just test them both.
     path0, path1 = candidates
     self.assertEqual(len(path0), 1)
     self.assertEqual(len(path1), 1)
     # One path gets us to version 1300 and the other 1400.
     images = sorted([path0[0], path1[0]], key=attrgetter('version'))
     self.assertEqual(descriptions(images), ['Delta 2', 'Delta 1'])
Ejemplo n.º 19
0
 def test_no_version_detail(self):
     # The index.json file has three paths for updates, but only one is
     # selected.  The winning path lands on an image without a
     # version_detail key.
     index = get_index('scores.index_07.json')
     candidates = get_candidates(index, 600)
     scores = self.scorer.score(candidates)
     self.assertEqual(scores, [300, 200, 9401])
     winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(len(winner), 3)
     self.assertEqual([image.version for image in winner],
                      [1200, 1201, 1304])
     self.assertEqual(descriptions(winner),
                      ['Full B', 'Delta B.1', 'Delta B.2'])
     self.assertEqual(winner[-1].version_detail, '')
Ejemplo n.º 20
0
 def test_filter_for_fulls(self):
     # Run a filter over the candidates, such that the only ones left are
     # those that contain only full upgrades.  This can truncate any paths
     # that start with some fulls and then contain some deltas.
     index = get_index('candidates.index_08.json')
     candidates = get_candidates(index, 600)
     filtered = full_filter(candidates)
     # Since all images start with a full update, we're still left with
     # three candidates.
     self.assertEqual(len(filtered), 3)
     self.assertEqual([image.type for image in filtered[0]], ['full'])
     self.assertEqual([image.type for image in filtered[1]], ['full'])
     self.assertEqual([image.type for image in filtered[2]], ['full'])
     self.assertEqual(descriptions(filtered[0]), ['Full A'])
     self.assertEqual(descriptions(filtered[1]), ['Full B'])
     self.assertEqual(descriptions(filtered[2]), ['Full C'])
Ejemplo n.º 21
0
 def test_fulls_with_no_minversion(self):
     # Like the previous test, there are two full upgrades, but because
     # neither of them have minversions, both are candidates.
     index = get_index('candidates.index_03.json')
     candidates = get_candidates(index, 400)
     self.assertEqual(len(candidates), 2)
     # Both candidate paths have exactly one image in them.  We can't sort
     # these paths, so just test them both.
     path0, path1 = candidates
     self.assertEqual(len(path0), 1)
     self.assertEqual(len(path1), 1)
     # One path gets us to version 1300 and the other 1400.
     images = sorted([path0[0], path1[0]], key=attrgetter('version'))
     self.assertEqual(list(images[0].descriptions.values()),
                      ['New full build 1'])
     self.assertEqual(list(images[1].descriptions.values()),
                      ['New full build 2'])
Ejemplo n.º 22
0
 def _calculate_winner(self):
     """Given an index, calculate the paths and score a winner."""
     # If we were tracking a channel alias, and that channel alias has
     # changed, squash the build number to 0 before calculating the
     # winner.  Otherwise, trust the configured build number.
     channel = self.channels[config.channel]
     # channel_target is the channel we're on based on the alias mapping in
     # our config files.  channel_alias is the alias mapping in the
     # channel.json file, i.e. the channel an update will put us on.
     channel_target = getattr(config.service, 'channel_target', None)
     channel_alias = getattr(channel, 'alias', None)
     if (channel_alias is None or channel_target is None
             or channel_alias == channel_target):
         build_number = config.build_number
     else:
         # This is a channel switch caused by a new alias.  Unless the
         # build number has been explicitly overridden on the command line
         # via --build/-b, use build number 0 to force a full update.
         build_number = (config.build_number
                         if config.build_number_override else 0)
         self.channel_switch = (channel_target, channel_alias)
     candidates = get_candidates(self.index, build_number)
     log.debug('Candidates from build# {}: {}'.format(
         build_number, len(candidates)))
     if self.candidate_filter is not None:
         candidates = self.candidate_filter(candidates)
     self.winner = config.hooks.scorer().choose(
         candidates,
         (channel_target if channel_alias is None else channel_alias))
     if len(self.winner) == 0:
         log.info('Already up-to-date')
         return
     winning_path = [str(image.version) for image in self.winner]
     log.info('Upgrade path is {}'.format(COLON.join(winning_path)))
     # Now filter the winning path to cap the maximum version number.
     if (self.winner_filter is not None
             and self.winner_filter.maximum_version is not None):
         log.info('Upgrade path capped at version {}'.format(
             self.winner_filter.maximum_version))
         self.winner = self.winner_filter(self.winner)
         if len(self.winner) == 0:
             log.info('Capped upgrade leaves device up-to-date')
             return
     self._next.append(self._download_files)
Ejemplo n.º 23
0
 def test_get_downloads(self):
     # Path B will win; it has one full and two deltas, none of which have
     # a bootme flag.  Download all their files.
     index = get_index('candidates.index_08.json')
     candidates = get_candidates(index, 600)
     winner = WeightedScorer().choose(candidates, 'devel')
     descriptions = []
     for image in 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'])
     downloads = list(iter_path(winner))
     paths = set(filerec.path for (n, filerec) in downloads)
     self.assertEqual(
         paths,
         set([
             '/3/4/5.txt',
             '/4/5/6.txt',
             '/5/6/7.txt',
             '/6/7/8.txt',
             '/7/8/9.txt',
             '/8/9/a.txt',
             '/9/a/b.txt',
             '/e/d/c.txt',
             '/f/e/d.txt',
         ]))
     signatures = set(filerec.signature for (n, filerec) in downloads)
     self.assertEqual(
         signatures,
         set([
             '/3/4/5.txt.asc',
             '/4/5/6.txt.asc',
             '/5/6/7.txt.asc',
             '/6/7/8.txt.asc',
             '/7/8/9.txt.asc',
             '/8/9/a.txt.asc',
             '/9/a/b.txt.asc',
             '/e/d/c.txt.asc',
             '/f/e/d.txt.asc',
         ]))
Ejemplo n.º 24
0
 def test_get_downloads_with_bootme(self):
     # Path B will win; it has one full and two deltas.  The first delta
     # has a bootme flag so the second delta's files are not downloaded.
     index = get_index('candidates.index_09.json')
     candidates = get_candidates(index, 600)
     winner = WeightedScorer().choose(candidates, 'devel')
     descriptions = []
     for image in 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'])
     downloads = iter_path(winner)
     paths = set(filerec.path for (n, filerec) in downloads)
     self.assertEqual(
         paths,
         set([
             '/3/4/5.txt',
             '/4/5/6.txt',
             '/5/6/7.txt',
             '/6/7/8.txt',
             '/7/8/9.txt',
             '/8/9/a.txt',
         ]))
Ejemplo n.º 25
0
 def test_calculate_candidates(self):
     # Calculate the candidate paths.
     setup_keyrings()
     state = State()
     # Run the state machine until we get an index file.
     state.run_until('calculate_winner')
     candidates = get_candidates(state.index, 100)
     # There are three candidate upgrade paths.
     self.assertEqual(len(candidates), 3)
     descriptions = []
     for image in candidates[0]:
         # There's only one description per image so order doesn't matter.
         descriptions.extend(image.descriptions.values())
     self.assertEqual(descriptions, ['Full A', 'Delta A.1', 'Delta A.2'])
     descriptions = []
     for image in candidates[1]:
         # 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'])
     descriptions = []
     for image in candidates[2]:
         # There's only one description per image so order doesn't matter.
         descriptions.extend(image.descriptions.values())
     self.assertEqual(descriptions, ['Full C', 'Delta C.1'])
Ejemplo n.º 26
0
 def test_three_paths(self):
     # - Path A requires three extra reboots, is the smallest total
     #   download and leaves you at the highest available version.
     #   Score: 300
     #
     # - Path B requires one extra reboot, but is 100MiB bigger and leaves
     #   you at the highest available version.  Score: 200
     #
     # - Path C requires no extra reboots, but is 400MiB bigger and leaves
     #   you at 1303 instead of the highest 1304.  For that reason, it gets
     #   a huge score making it impossible to win.
     #
     # Path B wins.
     index = get_index('scores.index_03.json')
     candidates = get_candidates(index, 600)
     # There are three paths.  The scores are as above.
     scores = self.scorer.score(candidates)
     self.assertEqual(scores, [300, 200, 9401])
     winner = self.scorer.choose(candidates, 'devel')
     self.assertEqual(len(winner), 3)
     self.assertEqual([image.version for image in winner],
                      [1200, 1201, 1304])
     self.assertEqual(descriptions(winner),
                      ['Full B', 'Delta B.1', 'Delta B.2'])
Ejemplo n.º 27
0
 def test_no_deltas_based_on_us(self):
     # There are deltas in the test data, but no fulls.  None of the deltas
     # have a base equal to our build number.
     index = get_index('candidates.index_04.json')
     candidates = get_candidates(index, 100)
     self.assertEqual(candidates, [])
Ejemplo n.º 28
0
 def test_filter_for_deltas_one_candidate(self):
     # Filter for delta updates, but the only candidate is a full.
     index = get_index('candidates.index_10.json')
     candidates = get_candidates(index, 600)
     filtered = delta_filter(candidates)
     self.assertEqual(len(filtered), 0)
Ejemplo n.º 29
0
 def test_only_higher_fulls(self):
     # All the full images have a minversion greater than our version, so
     # we cannot upgrade to any of them.
     index = get_index('candidates.index_02.json')
     candidates = get_candidates(index, 100)
     self.assertEqual(candidates, [])
Ejemplo n.º 30
0
 def test_no_images(self):
     # If there are no images defined, there are no candidates.
     index = get_index('candidates.index_01.json')
     candidates = get_candidates(index, 1400)
     self.assertEqual(candidates, [])