Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / scripts / cros_portage_upgrade_unittest.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Unit tests for cros_portage_upgrade.py."""
7
8 from __future__ import print_function
9
10 import exceptions
11 import filecmp
12 import mox
13 import os
14 import re
15 import shutil
16 import sys
17 import tempfile
18 import unittest
19
20 sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
21                                 '..', '..'))
22 from chromite.lib import cros_build_lib
23 from chromite.lib import cros_test_lib
24 from chromite.lib import osutils
25 from chromite.lib import upgrade_table as utable
26 from chromite.scripts import cros_portage_upgrade as cpu
27 from chromite.scripts import parallel_emerge
28
29 from portage.package.ebuild import config as portcfg  # pylint: disable=F0401
30
31 # This no longer gets installed by portage.  Stub it as None to avoid
32 # `cros lint` errors.
33 #from portage.tests.resolver import ResolverPlayground as respgnd
34 respgnd = None
35
36 # Enable color invariably. Since we rely on color for error/warn message
37 # recognition, leaving this to be decided based on stdout being a tty
38 # will make the tests fail/succeed based on how they are run.
39 # pylint: disable=W0102,W0212,E1120,E1101
40 cpu.oper._color._enabled = True
41
42 DEFAULT_PORTDIR = '/usr/portage'
43
44 # Configuration for generating a temporary valid ebuild hierarchy.
45 # ResolverPlayground sets up a default profile with ARCH=x86, so
46 # other architectures are irrelevant for now.
47 DEFAULT_ARCH = 'x86'
48 EBUILDS = {
49   'dev-libs/A-1': {'RDEPEND': 'dev-libs/B'},
50   'dev-libs/A-2': {'RDEPEND': 'dev-libs/B'},
51   'dev-libs/B-1': {'RDEPEND': 'dev-libs/C'},
52   'dev-libs/B-2': {'RDEPEND': 'dev-libs/C'},
53   'dev-libs/C-1': {},
54   'dev-libs/C-2': {},
55   'dev-libs/D-1': {'RDEPEND': '!dev-libs/E'},
56   'dev-libs/D-2': {},
57   'dev-libs/D-3': {},
58   'dev-libs/E-2': {'RDEPEND': '!dev-libs/D'},
59   'dev-libs/E-3': {},
60
61   'dev-libs/F-1': {'SLOT': '1'},
62   'dev-libs/F-2': {'SLOT': '2'},
63   'dev-libs/F-2-r1': {'SLOT': '2',
64                       'KEYWORDS': '~amd64 ~x86 ~arm',
65                       },
66
67   'dev-apps/X-1': {
68     'EAPI': '3',
69     'SLOT': '0',
70     'KEYWORDS': 'amd64 arm x86',
71     'RDEPEND': '=dev-libs/C-1',
72     },
73   'dev-apps/Y-2': {
74     'EAPI': '3',
75     'SLOT': '0',
76     'KEYWORDS': 'amd64 arm x86',
77     'RDEPEND': '=dev-libs/C-2',
78     },
79
80   'chromeos-base/flimflam-0.0.1-r228': {
81     'EAPI': '2',
82     'SLOT': '0',
83     'KEYWORDS': 'amd64 x86 arm',
84     'RDEPEND': '>=dev-libs/D-2',
85     },
86   'chromeos-base/flimflam-0.0.2-r123': {
87     'EAPI': '2',
88     'SLOT': '0',
89     'KEYWORDS': '~amd64 ~x86 ~arm',
90     'RDEPEND': '>=dev-libs/D-3',
91     },
92   'chromeos-base/libchrome-57098-r4': {
93     'EAPI': '2',
94     'SLOT': '0',
95     'KEYWORDS': 'amd64 x86 arm',
96     'RDEPEND': '>=dev-libs/E-2',
97     },
98   'chromeos-base/libcros-1': {
99     'EAPI': '2',
100     'SLOT': '0',
101     'KEYWORDS': 'amd64 x86 arm',
102     'RDEPEND': 'dev-libs/B dev-libs/C chromeos-base/flimflam',
103     'DEPEND':
104     'dev-libs/B dev-libs/C chromeos-base/flimflam chromeos-base/libchrome',
105     },
106
107   'virtual/libusb-0'         : {
108     'EAPI': '2', 'SLOT': '0',
109     'RDEPEND':
110     '|| ( >=dev-libs/libusb-0.1.12-r1:0 dev-libs/libusb-compat ' +
111     '>=sys-freebsd/freebsd-lib-8.0[usb] )'},
112   'virtual/libusb-1'         : {
113     'EAPI':'2', 'SLOT': '1',
114     'RDEPEND': '>=dev-libs/libusb-1.0.4:1'},
115   'dev-libs/libusb-0.1.13'   : {},
116   'dev-libs/libusb-1.0.5'    : {'SLOT':'1'},
117   'dev-libs/libusb-compat-1' : {},
118   'sys-freebsd/freebsd-lib-8': {'IUSE': '+usb'},
119
120   'sys-fs/udev-164'          : {'EAPI': '1', 'RDEPEND': 'virtual/libusb:0'},
121
122   'virtual/jre-1.5.0'        : {
123     'SLOT': '1.5',
124     'RDEPEND': '|| ( =dev-java/sun-jre-bin-1.5.0* =virtual/jdk-1.5.0* )'},
125   'virtual/jre-1.5.0-r1'     : {
126     'SLOT': '1.5',
127     'RDEPEND': '|| ( =dev-java/sun-jre-bin-1.5.0* =virtual/jdk-1.5.0* )'},
128   'virtual/jre-1.6.0'        : {
129     'SLOT': '1.6',
130     'RDEPEND': '|| ( =dev-java/sun-jre-bin-1.6.0* =virtual/jdk-1.6.0* )'},
131   'virtual/jre-1.6.0-r1'     : {
132     'SLOT': '1.6',
133     'RDEPEND': '|| ( =dev-java/sun-jre-bin-1.6.0* =virtual/jdk-1.6.0* )'},
134   'virtual/jdk-1.5.0'        : {
135     'SLOT': '1.5',
136     'RDEPEND': '|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )'},
137   'virtual/jdk-1.5.0-r1'     : {
138     'SLOT' : '1.5',
139     'RDEPEND': '|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )'},
140   'virtual/jdk-1.6.0'        : {
141     'SLOT': '1.6',
142     'RDEPEND': '|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )'},
143   'virtual/jdk-1.6.0-r1'     : {
144     'SLOT': '1.6',
145     'RDEPEND': '|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )'},
146   'dev-java/gcj-jdk-4.5'     : {},
147   'dev-java/gcj-jdk-4.5-r1'  : {},
148   'dev-java/icedtea-6.1'     : {},
149   'dev-java/icedtea-6.1-r1'  : {},
150   'dev-java/sun-jdk-1.5'     : {'SLOT': '1.5'},
151   'dev-java/sun-jdk-1.6'     : {'SLOT': '1.6'},
152   'dev-java/sun-jre-bin-1.5' : {'SLOT': '1.5'},
153   'dev-java/sun-jre-bin-1.6' : {'SLOT': '1.6'},
154
155   'dev-java/ant-core-1.8'   : {'DEPEND' : '>=virtual/jdk-1.4'},
156   'dev-db/hsqldb-1.8'       : {'RDEPEND': '>=virtual/jre-1.6'},
157   }
158
159 WORLD = [
160   'dev-libs/A',
161   'dev-libs/D',
162   'virtual/jre',
163   ]
164
165 INSTALLED = {
166   'dev-libs/A-1': {},
167   'dev-libs/B-1': {},
168   'dev-libs/C-1': {},
169   'dev-libs/D-1': {},
170
171   'virtual/jre-1.5.0'       : {
172     'SLOT': '1.5',
173     'RDEPEND': '|| ( =virtual/jdk-1.5.0* =dev-java/sun-jre-bin-1.5.0* )'},
174   'virtual/jre-1.6.0'       : {
175     'SLOT': '1.6',
176     'RDEPEND': '|| ( =virtual/jdk-1.6.0* =dev-java/sun-jre-bin-1.6.0* )'},
177   'virtual/jdk-1.5.0'       : {
178     'SLOT': '1.5',
179     'RDEPEND': '|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )'},
180   'virtual/jdk-1.6.0'       : {
181     'SLOT': '1.6',
182     'RDEPEND': '|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )'},
183   'dev-java/gcj-jdk-4.5'    : {},
184   'dev-java/icedtea-6.1'    : {},
185
186   'virtual/libusb-0'        : {
187     'EAPI': '2', 'SLOT': '0',
188     'RDEPEND':
189     '|| ( >=dev-libs/libusb-0.1.12-r1:0 dev-libs/libusb-compat ' +
190     '>=sys-freebsd/freebsd-lib-8.0[usb] )'},
191   }
192
193 # For verifying dependency graph results
194 GOLDEN_DEP_GRAPHS = {
195   'dev-libs/A-2': { 'needs': { 'dev-libs/B-2': 'runtime' },
196                      'action': 'merge' },
197   'dev-libs/B-2': { 'needs': { 'dev-libs/C-2': 'runtime' } },
198   'dev-libs/C-2': { 'needs': { } },
199   'dev-libs/D-3': { 'needs': { } },
200   # TODO(mtennant): Bug in parallel_emerge deps graph makes blocker show up for
201   # E-3, rather than in just E-2 where it belongs. See crosbug.com/22190.
202   # To repeat bug, swap the commented status of next two lines.
203   #'dev-libs/E-3': { 'needs': { } },
204   'dev-libs/E-3': { 'needs': { 'dev-libs/D-3': 'blocker' } },
205   'chromeos-base/libcros-1': { 'needs': {
206     'dev-libs/B-2': 'runtime/buildtime',
207     'dev-libs/C-2': 'runtime/buildtime',
208     'chromeos-base/libchrome-57098-r4': 'buildtime',
209     'chromeos-base/flimflam-0.0.1-r228': 'runtime/buildtime'
210     } },
211   'chromeos-base/flimflam-0.0.1-r228': { 'needs': {
212     'dev-libs/D-3': 'runtime'
213     } },
214   'chromeos-base/libchrome-57098-r4': { 'needs': {
215     'dev-libs/E-3': 'runtime'
216     } },
217   }
218
219 # For verifying dependency set results
220 GOLDEN_DEP_SETS = {
221   'dev-libs/A': set(['dev-libs/A-2', 'dev-libs/B-2', 'dev-libs/C-2']),
222   'dev-libs/B': set(['dev-libs/B-2', 'dev-libs/C-2']),
223   'dev-libs/C': set(['dev-libs/C-2']),
224   'dev-libs/D': set(['dev-libs/D-3']),
225   'virtual/libusb': set(['virtual/libusb-1', 'dev-libs/libusb-1.0.5']),
226   'chromeos-base/libcros': set(['chromeos-base/libcros-1',
227                                 'dev-libs/B-2',
228                                 'chromeos-base/libchrome-57098-r4',
229                                 'dev-libs/E-3',
230                                 'chromeos-base/flimflam-0.0.1-r228',
231                                 'dev-libs/D-3',
232                                 'dev-libs/C-2',
233                                 ])
234   }
235
236
237 def _GetGoldenDepsSet(pkg):
238   """Retrieve the golden dependency set for |pkg| from GOLDEN_DEP_SETS."""
239   return GOLDEN_DEP_SETS.get(pkg, None)
240
241
242 def _VerifyDepsGraph(deps_graph, pkgs):
243   for pkg in pkgs:
244     if not _VerifyDepsGraphOnePkg(deps_graph, pkg):
245       return False
246
247   return True
248
249
250 def _VerifyDepsGraphOnePkg(deps_graph, pkg):
251   """Verfication function for Mox to validate deps graph for |pkg|."""
252
253   if deps_graph is None:
254     print('Error: no dependency graph passed into _GetPreOrderDepGraph')
255     return False
256
257   if type(deps_graph) != dict:
258     print('Error: dependency graph is expected to be a dict.  Instead:\n%r' %
259           deps_graph)
260     return False
261
262   validated = True
263
264   golden_deps_set = _GetGoldenDepsSet(pkg)
265   if golden_deps_set == None:
266     print('Error: golden dependency list not configured for %s package' % pkg)
267     validated = False
268
269   # Verify dependencies, by comparing them to GOLDEN_DEP_GRAPHS
270   for p in deps_graph:
271     golden_pkg_info = None
272     try:
273       golden_pkg_info = GOLDEN_DEP_GRAPHS[p]
274     except KeyError:
275       print('Error: golden dependency graph not configured for %s package' % p)
276       validated = False
277       continue
278
279     pkg_info = deps_graph[p]
280     for key in golden_pkg_info:
281       golden_value = golden_pkg_info[key]
282       value = pkg_info[key]
283       if not value == golden_value:
284         print('Error: while verifying "%s" value for %s package,'
285               ' expected:\n%r\nBut instead found:\n%r'
286               % (key, p, golden_value, value))
287         validated = False
288
289   if not validated:
290     print('Error: dependency graph for %s is not as expected.  Instead:\n%r' %
291           (pkg, deps_graph))
292
293   return validated
294
295
296 def _GenDepsGraphVerifier(pkgs):
297   """Generate a graph verification function for the given package."""
298   return lambda deps_graph: _VerifyDepsGraph(deps_graph, pkgs)
299
300
301 class ManifestLine(object):
302   """Class to represent a Manifest line."""
303
304   __slots__ = (
305       'type',    # DIST, EBUILD, etc.
306       'file',
307       'size',
308       'RMD160',
309       'SHA1',
310       'SHA256',
311       )
312
313   __attrlist__ = __slots__
314
315   def __init__(self, line=None, **kwargs):
316     """Parse |line| from manifest file."""
317     if line:
318       tokens = line.split()
319       self.type = tokens[0]
320       self.file = tokens[1]
321       self.size = tokens[2]
322       self.RMD160 = tokens[4]
323       self.SHA1 = tokens[6]
324       self.SHA256 = tokens[8]
325
326       assert tokens[3] == 'RMD160'
327       assert tokens[5] == 'SHA1'
328       assert tokens[7] == 'SHA256'
329
330     # Entries in kwargs are overwrites.
331     for attr in self.__attrlist__:
332       if attr in kwargs or not hasattr(self, attr):
333         setattr(self, attr, kwargs.get(attr))
334
335   def __str__(self):
336     return ('%s %s %s RMD160 %s SHA1 %s SHA256 %s' %
337             (self.type, self.file, self.size,
338             self.RMD160, self.SHA1, self.SHA256))
339
340   def __eq__(self, other):
341     """Equality support."""
342
343     if type(self) != type(other):
344       return False
345
346     no_attr = object()
347     for attr in self.__attrlist__:
348       if getattr(self, attr, no_attr) != getattr(other, attr, no_attr):
349         return False
350
351     return True
352
353   def __ne__(self, other):
354     """Inequality for completeness."""
355     return not self == other
356
357
358 class RunCommandResult(object):
359   """Class to simulate result of cros_build_lib.RunCommand."""
360   __slots__ = ['returncode', 'output']
361
362   def __init__(self, returncode, output):
363     self.returncode = returncode
364     self.output = output
365
366
367 class PInfoTest(cros_test_lib.OutputTestCase):
368   """Tests for the PInfo class."""
369
370   def testInit(self):
371     pinfo = cpu.PInfo(category='SomeCat', user_arg='SomeArg')
372
373     self.assertEquals('SomeCat', pinfo.category)
374     self.assertEquals('SomeArg', pinfo.user_arg)
375
376     self.assertEquals(None, pinfo.cpv)
377     self.assertEquals(None, pinfo.overlay)
378
379     self.assertRaises(AttributeError, getattr, pinfo, 'foobar')
380
381   def testEqAndNe(self):
382     pinfo1 = cpu.PInfo(category='SomeCat', user_arg='SomeArg')
383
384     self.assertEquals(pinfo1, pinfo1)
385     self.assertTrue(pinfo1 == pinfo1)
386     self.assertFalse(pinfo1 != pinfo1)
387
388     pinfo2 = cpu.PInfo(category='SomeCat', user_arg='SomeArg')
389
390     self.assertEquals(pinfo1, pinfo2)
391     self.assertTrue(pinfo1 == pinfo2)
392     self.assertFalse(pinfo1 != pinfo2)
393
394     pinfo3 = cpu.PInfo(category='SomeCat', user_arg='SomeOtherArg')
395
396     self.assertNotEquals(pinfo1, pinfo3)
397     self.assertFalse(pinfo1 == pinfo3)
398     self.assertTrue(pinfo1 != pinfo3)
399
400     pinfo4 = cpu.PInfo(category='SomeCat', slot='SomeSlot')
401
402     self.assertNotEquals(pinfo1, pinfo4)
403     self.assertFalse(pinfo1 == pinfo4)
404     self.assertTrue(pinfo1 != pinfo4)
405
406
407 class CpuTestBase(cros_test_lib.MoxOutputTestCase):
408   """Base class for all test classes in this file."""
409
410   __slots__ = [
411     'playground',
412     'playground_envvars',
413     ]
414
415   def setUp(self):
416     self.playground = None
417     self.playground_envvars = None
418
419   def tearDown(self):
420     self._TearDownPlayground()
421
422   def _SetUpPlayground(self, ebuilds=EBUILDS, installed=INSTALLED, world=WORLD,
423                        active=True):
424     """Prepare the temporary ebuild playground (ResolverPlayground).
425
426     This leverages test code in existing Portage modules to create an ebuild
427     hierarchy.  This can be a little slow.
428
429     Args:
430       ebuilds: A list of hashes representing ebuild files in a portdir.
431       installed: A list of hashes representing ebuilds files already installed.
432       world: A list of lines to simulate in the world file.
433       active: True means that os.environ variables should be set
434         to point to the created playground, such that Portage tools
435         (such as emerge) can be run now using the playground as the active
436         PORTDIR.  Also saves the playground as self._playground. If |active|
437         is False, then no os.environ variables are set and playground is
438         not saved (only returned).
439
440     Returns:
441       Tuple (playground, envvars).
442     """
443
444     # TODO(mtennant): Support multiple overlays?  This essentially
445     # creates just a default overlay.
446     # Also note that ResolverPlayground assumes ARCH=x86 for the
447     # default profile it creates.
448     playground = respgnd.ResolverPlayground(ebuilds=ebuilds,
449                                             installed=installed,
450                                             world=world)
451
452     # Set all envvars needed by parallel_emerge, since parallel_emerge
453     # normally does that when --board is given.
454     eroot = self._GetPlaygroundRoot(playground)
455     portdir = self._GetPlaygroundPortdir(playground)
456     envvars = {'PORTAGE_CONFIGROOT': eroot,
457                'ROOT': eroot,
458                'PORTDIR': portdir,
459                # See _GenPortageEnvvars for more info on this setting.
460                'PORTDIR_OVERLAY': portdir,
461                }
462
463     if active:
464       for envvar in envvars:
465         os.environ[envvar] = envvars[envvar]
466
467       self.playground = playground
468       self.playground_envvars = envvars
469
470     return (playground, envvars)
471
472   def _GetPlaygroundRoot(self, playground=None):
473     """Get the temp dir playground is using as ROOT."""
474     if playground is None:
475       playground = self.playground
476
477     eroot = playground.eroot
478     if eroot[-1:] == '/':
479       eroot = eroot[:-1]
480     return eroot
481
482   def _GetPlaygroundPortdir(self, playground=None):
483     """Get the temp portdir without playground."""
484     if playground is None:
485       playground = self.playground
486
487     eroot = self._GetPlaygroundRoot(playground)
488     portdir = '%s%s' % (eroot, DEFAULT_PORTDIR)
489     return portdir
490
491   def _TearDownPlayground(self):
492     """Delete the temporary ebuild playground files."""
493     if self.playground:
494       try:
495         self.playground.cleanup()
496       except OSError:
497         # The clever tmp cleanup code in osutils.TempDirDecorator
498         # will take care of the cleanup before this point if it
499         # is used in the current test.  Just move along.
500         pass
501
502       self.playground = None
503       self.playground_envvars = None
504
505   def _MockUpgrader(self, cmdargs=None, **kwargs):
506     """Set up a mocked Upgrader object with the given args."""
507     upgrader_slot_defaults = {
508       '_curr_arch':   DEFAULT_ARCH,
509       '_curr_board':  'some_board',
510       '_unstable_ok': False,
511       '_verbose':     False,
512     }
513
514     upgrader = self.mox.CreateMock(cpu.Upgrader)
515
516     # Initialize each attribute with default value.
517     for slot in cpu.Upgrader.__slots__:
518       value = upgrader_slot_defaults.get(slot, None)
519       upgrader.__setattr__(slot, value)
520
521     # Initialize with command line if given.
522     if cmdargs is not None:
523       parser = cpu._CreateParser()
524       options = parser.parse_args(cmdargs)
525       cpu.Upgrader.__init__(upgrader, options)
526
527     # Override Upgrader attributes if requested.
528     for slot in cpu.Upgrader.__slots__:
529       value = None
530       if slot in kwargs:
531         upgrader.__setattr__(slot, kwargs[slot])
532
533     return upgrader
534
535
536 @unittest.skip('relies on portage module not currently available')
537 class CopyUpstreamTest(CpuTestBase):
538   """Test Upgrader._CopyUpstreamPackage, _CopyUpstreamEclass, _CreateManifest"""
539
540   # This is a hack until crosbug.com/21965 is completed and upstreamed
541   # to Portage.  Insert eclass simulation into tree.
542   def _AddEclassToPlayground(self, eclass, lines=None,
543                              ebuilds=None, missing=False):
544     """Hack to insert an eclass into the playground source.
545
546     Args:
547       eclass: Name of eclass to create (without .eclass suffix).  Will be
548         created as an empty file unless |lines| is specified.
549       lines: Lines of text to put into created eclass, if given.
550       ebuilds: List of ebuilds to put inherit line into.  Should be path
551         to ebuild from playground portdir.
552       missing: If True, do not actually create the eclass file.  Only makes
553         sense if |ebuilds| is non-empty, presumably to test inherit failure.
554
555     Returns:
556       Full path to the eclass file, whether it was created or not.
557     """
558     portdir = self._GetPlaygroundPortdir()
559     eclass_path = os.path.join(portdir, 'eclass', '%s.eclass' % eclass)
560
561     # Create the eclass file
562     osutils.WriteFile(eclass_path, '\n'.join(lines if lines else []))
563
564     # Insert the inherit line into the ebuild file, if requested.
565     if ebuilds:
566       for ebuild in ebuilds:
567         ebuild_path = os.path.join(portdir, ebuild)
568
569         text = osutils.ReadFile(ebuild_path)
570
571         def repl(match):
572           return match.group(1) + '\ninherit ' + eclass
573         text = re.sub(r'(EAPI.*)', repl, text)
574
575         osutils.WriteFile(ebuild_path, text)
576
577         # Remove the Manifest file
578         os.remove(os.path.join(os.path.dirname(ebuild_path), 'Manifest'))
579
580         # Recreate the Manifests using the ebuild utility.
581         cmd = ['ebuild', ebuild_path, 'manifest']
582         cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True,
583                                   combine_stdout_stderr=True)
584
585     # If requested, remove the eclass.
586     if missing:
587       os.remove(eclass_path)
588
589     return eclass_path
590
591   #
592   # _IdentifyNeededEclass
593   #
594
595   def _TestIdentifyNeededEclass(self, cpv, ebuild, eclass, create_eclass):
596     """Test Upgrader._IdentifyNeededEclass"""
597
598     self._SetUpPlayground()
599     portdir = self._GetPlaygroundPortdir()
600     mocked_upgrader = self._MockUpgrader(cmdargs=[],
601                                          _stable_repo=portdir,
602                                          )
603     self._AddEclassToPlayground(eclass,
604                                 ebuilds=[ebuild],
605                                 missing=not create_eclass)
606
607     # Add test-specific mocks/stubs
608
609     # Replay script
610     envvars = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
611                                               mocked_upgrader._curr_arch,
612                                               unstable_ok=True)
613     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
614                                        unstable_ok=True,
615                                        ).AndReturn(envvars)
616     mocked_upgrader._GetBoardCmd('equery').AndReturn('equery')
617     self.mox.ReplayAll()
618
619     # Verify
620     with self.OutputCapturer():
621       result = cpu.Upgrader._IdentifyNeededEclass(mocked_upgrader, cpv)
622     self.mox.VerifyAll()
623
624     return result
625
626   def testIdentifyNeededEclassMissing(self):
627     result = self._TestIdentifyNeededEclass('dev-libs/A-2',
628                                             'dev-libs/A/A-2.ebuild',
629                                             'inheritme',
630                                             False)
631     self.assertEquals('inheritme.eclass', result)
632
633   def testIdentifyNeededEclassOK(self):
634     result = self._TestIdentifyNeededEclass('dev-libs/A-2',
635                                             'dev-libs/A/A-2.ebuild',
636                                             'inheritme',
637                                             True)
638     self.assertTrue(result is None)
639
640   #
641   # _CopyUpstreamEclass
642   #
643
644   @osutils.TempDirDecorator
645   def _TestCopyUpstreamEclass(self, eclass, do_copy,
646                               local_copy_identical=None, error=None):
647     """Test Upgrader._CopyUpstreamEclass"""
648
649     self._SetUpPlayground()
650     upstream_portdir = self._GetPlaygroundPortdir()
651     portage_stable = self.tempdir
652     mocked_upgrader = self._MockUpgrader(_curr_board=None,
653                                          _upstream=upstream_portdir,
654                                          _stable_repo=portage_stable,
655                                          )
656
657     eclass_subpath = os.path.join('eclass', eclass + '.eclass')
658     eclass_path = os.path.join(portage_stable, eclass_subpath)
659     upstream_eclass_path = None
660     if do_copy or local_copy_identical:
661       lines = ['#Dummy eclass', '#Hi']
662       upstream_eclass_path = self._AddEclassToPlayground(eclass,
663                                                          lines=lines)
664     if local_copy_identical:
665       # Make it look like identical eclass already exists in portage-stable.
666       os.makedirs(os.path.dirname(eclass_path))
667       shutil.copy2(upstream_eclass_path, eclass_path)
668     elif local_copy_identical is not None:
669       # Make local copy some other gibberish.
670       os.makedirs(os.path.dirname(eclass_path))
671       osutils.WriteFile(eclass_path, 'garblety gook')
672
673     # Add test-specific mocks/stubs
674
675     # Replay script
676     if do_copy:
677       mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
678                               ['add', eclass_subpath])
679     self.mox.ReplayAll()
680
681     # Verify
682     result = None
683     with self.OutputCapturer():
684       if error:
685         self.assertRaises(error, cpu.Upgrader._CopyUpstreamEclass,
686                           mocked_upgrader, eclass + '.eclass')
687       else:
688         result = cpu.Upgrader._CopyUpstreamEclass(mocked_upgrader,
689                                                   eclass + '.eclass')
690     self.mox.VerifyAll()
691
692     if do_copy:
693       self.assertTrue(result)
694       # Verify that eclass has been copied into portage-stable.
695       self.assertTrue(os.path.exists(eclass_path))
696       # Verify that eclass contents are correct.
697       self.assertTrue(filecmp.cmp(upstream_eclass_path, eclass_path))
698
699     else:
700       self.assertFalse(result)
701
702   def testCopyUpstreamEclassCopyBecauseMissing(self):
703     self._TestCopyUpstreamEclass('inheritme',
704                                  do_copy=True)
705
706   def testCopyUpstreamEclassCopyBecauseDifferent(self):
707     self._TestCopyUpstreamEclass('inheritme',
708                                  do_copy=True,
709                                  local_copy_identical=False)
710
711   def testCopyUpstreamEclassNoCopyBecauseIdentical(self):
712     self._TestCopyUpstreamEclass('inheritme',
713                                  do_copy=False,
714                                  local_copy_identical=True)
715
716   def testCopyUpstreamEclassNoCopyBecauseUpstreamMissing(self):
717     self._TestCopyUpstreamEclass('inheritme',
718                                  do_copy=False,
719                                  error=RuntimeError)
720
721   #
722   # _CopyUpstreamPackage
723   #
724
725   @osutils.TempDirDecorator
726   def _TestCopyUpstreamPackage(self, catpkg, verrev, success,
727                                existing_files, extra_upstream_files,
728                                error=None):
729     """Test Upgrader._CopyUpstreamPackage"""
730
731     upstream_cpv = '%s-%s' % (catpkg, verrev)
732     ebuild = '%s-%s.ebuild' % (catpkg.split('/')[-1], verrev)
733
734     self._SetUpPlayground()
735     upstream_portdir = self._GetPlaygroundPortdir()
736
737     # Simulate extra files in upsteam package dir.
738     if extra_upstream_files:
739       pkg_dir = os.path.join(upstream_portdir, catpkg)
740       if os.path.exists(pkg_dir):
741         for extra_file in extra_upstream_files:
742           open(os.path.join(pkg_dir, extra_file), 'w')
743
744     # Prepare dummy portage-stable dir, with extra previously
745     # existing files simulated if requested.
746     portage_stable = self.tempdir
747     if existing_files:
748       pkg_dir = os.path.join(portage_stable, catpkg)
749       os.makedirs(pkg_dir)
750       for existing_file in existing_files:
751         open(os.path.join(pkg_dir, existing_file), 'w')
752
753
754     mocked_upgrader = self._MockUpgrader(_curr_board=None,
755                                          _upstream=upstream_portdir,
756                                          _stable_repo=portage_stable,
757                                          )
758
759     # Replay script
760     if success:
761       def git_rm(*args, **_kwargs):
762         # Identify file that psuedo-git is to remove, then remove it.
763         # As with real "git rm", if the dir is then empty remove that.
764         # File to remove is last argument in git command (arg 1)
765         dirpath = args[0]
766         for f in args[1][2:]:
767           os.remove(os.path.join(dirpath, f))
768         try:
769           os.rmdir(os.path.dirname(dirpath))
770         except OSError:
771           pass
772
773       pkgdir = os.path.join(mocked_upgrader._stable_repo, catpkg)
774
775       if existing_files:
776         rm_list = [os.path.join(catpkg, f) for f in existing_files]
777
778         # Accept files to remove in any order.
779         def rm_cmd_verifier(cmd):
780           cmd_args = cmd[2:] # Peel off 'rm -rf'.
781           return sorted(cmd_args) == sorted(rm_list)
782
783         mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
784                                 mox.Func(rm_cmd_verifier),
785                                 redirect_stdout=True
786                                 ).WithSideEffects(git_rm)
787
788       mocked_upgrader._CreateManifest(os.path.join(upstream_portdir, catpkg),
789                                       pkgdir, ebuild)
790       mocked_upgrader._IdentifyNeededEclass(upstream_cpv).AndReturn(None)
791     self.mox.ReplayAll()
792
793     # Verify
794     result = None
795     with self.OutputCapturer():
796       if error:
797         self.assertRaises(error, cpu.Upgrader._CopyUpstreamPackage,
798                           mocked_upgrader, upstream_cpv)
799       else:
800         result = cpu.Upgrader._CopyUpstreamPackage(mocked_upgrader,
801                                                    upstream_cpv)
802     self.mox.VerifyAll()
803
804     if success:
805       self.assertEquals(result, upstream_cpv)
806
807       # Verify that ebuild has been copied into portage-stable.
808       ebuild_path = os.path.join(portage_stable, catpkg, ebuild)
809       self.assertTrue(os.path.exists(ebuild_path),
810                       msg='Missing expected ebuild after copy from upstream')
811
812       # Verify that any extra files upstream are also copied.
813       for extra_file in extra_upstream_files:
814         file_path = os.path.join(portage_stable, catpkg, extra_file)
815         msg = ('Missing expected extra file %s after copy from upstream' %
816                extra_file)
817         self.assertTrue(os.path.exists(file_path), msg=msg)
818     else:
819       self.assertTrue(result is None)
820
821   def testCopyUpstreamPackageEmptyStable(self):
822     existing_files = []
823     extra_upstream_files = []
824     self._TestCopyUpstreamPackage('dev-libs/D', '2', True,
825                                   existing_files,
826                                   extra_upstream_files)
827
828   def testCopyUpstreamPackageClutteredStable(self):
829     existing_files = ['foo', 'bar', 'foobar.ebuild', 'D-1.ebuild']
830     extra_upstream_files = []
831     self._TestCopyUpstreamPackage('dev-libs/D', '2', True,
832                                   existing_files,
833                                   extra_upstream_files)
834
835   def testCopyUpstreamPackageVersionNotAvailable(self):
836     """Should fail, dev-libs/D version 5 does not exist 'upstream'"""
837     existing_files = []
838     extra_upstream_files = []
839     self._TestCopyUpstreamPackage('dev-libs/D', '5', False,
840                                   existing_files,
841                                   extra_upstream_files,
842                                   error=RuntimeError)
843
844   def testCopyUpstreamPackagePackageNotAvailable(self):
845     """Should fail, a-b-c/D does not exist 'upstream' in any version"""
846     existing_files = []
847     extra_upstream_files = []
848     self._TestCopyUpstreamPackage('a-b-c/D', '5', False,
849                                   existing_files,
850                                   extra_upstream_files,
851                                   error=RuntimeError)
852
853   def testCopyUpstreamPackageExtraUpstreamFiles(self):
854     existing_files = ['foo', 'bar']
855     extra_upstream_files = ['keepme', 'andme']
856     self._TestCopyUpstreamPackage('dev-libs/F', '2-r1', True,
857                                   existing_files,
858                                   extra_upstream_files)
859
860
861   def _SetupManifestTest(self, ebuild,
862                          upstream_mlines, current_mlines):
863     upstream_dir = tempfile.mkdtemp(dir=self.tempdir)
864     current_dir = tempfile.mkdtemp(dir=self.tempdir)
865
866     upstream_manifest = os.path.join(upstream_dir, 'Manifest')
867     current_manifest = os.path.join(current_dir, 'Manifest')
868
869     if upstream_mlines:
870       osutils.WriteFile(upstream_manifest,
871                         '\n'.join(str(x) for x in upstream_mlines) + '\n')
872
873     if current_mlines:
874       osutils.WriteFile(current_manifest,
875                         '\n'.join(str(x) for x in current_mlines) + '\n')
876
877     ebuild_path = os.path.join(current_dir, ebuild)
878
879     # Add test-specific mocks/stubs
880     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
881
882     # Prepare test replay script.
883     run_result = RunCommandResult(returncode=0, output='')
884     cros_build_lib.RunCommand(['ebuild', ebuild_path, 'manifest'],
885                               error_code_ok=True, print_cmd=False,
886                               redirect_stdout=True, combine_stdout_stderr=True
887                               ).AndReturn(run_result)
888     self.mox.ReplayAll()
889
890     return (upstream_dir, current_dir)
891
892   def _AssertManifestContents(self, manifest_path, expected_manifest_lines):
893     manifest_lines = []
894     with open(manifest_path, 'r') as f:
895       for line in f:
896         manifest_lines.append(ManifestLine(line))
897
898     msg = ('Manifest contents not as expected.  Expected:\n%s\n'
899            '\nBut got:\n%s\n' %
900            ('\n'.join([str(ml) for ml in expected_manifest_lines]),
901             '\n'.join([str(ml) for ml in manifest_lines])))
902     self.assertTrue(manifest_lines == expected_manifest_lines, msg=msg)
903     self.assertFalse(manifest_lines != expected_manifest_lines, msg=msg)
904
905   @osutils.TempDirDecorator
906   def testCreateManifestNew(self):
907     """Test case with upstream but no current Manifest."""
908
909     mocked_upgrader = self._MockUpgrader()
910
911     ebuild = 'some-pkg.ebuild'
912     upst_mlines = [ManifestLine(type='DIST',
913                                 file='fileA',
914                                 size='100',
915                                 RMD160='abc',
916                                 SHA1='123',
917                                 SHA256='abc123'
918                                 ),
919                    ManifestLine(type='EBUILD',
920                                 file=ebuild,
921                                 size='254',
922                                 RMD160='def',
923                                 SHA1='456',
924                                 SHA256='def456'
925                                 ),
926                    ]
927     upstream_dir, current_dir = self._SetupManifestTest(ebuild,
928                                                         upst_mlines, None)
929
930     upstream_manifest = os.path.join(upstream_dir, 'Manifest')
931     current_manifest = os.path.join(current_dir, 'Manifest')
932
933     # Run test verification.
934     self.assertFalse(os.path.exists(current_manifest))
935     cpu.Upgrader._CreateManifest(mocked_upgrader,
936                                  upstream_dir, current_dir, ebuild)
937     self.mox.VerifyAll()
938     self.assertTrue(filecmp.cmp(upstream_manifest, current_manifest))
939
940   @osutils.TempDirDecorator
941   def testCreateManifestMerge(self):
942     """Test case with upstream but no current Manifest."""
943
944     mocked_upgrader = self._MockUpgrader()
945
946     ebuild = 'some-pkg.ebuild'
947     curr_mlines = [ManifestLine(type='DIST',
948                                 file='fileA',
949                                 size='101',
950                                 RMD160='abc',
951                                 SHA1='123',
952                                 SHA256='abc123'
953                                 ),
954                    ManifestLine(type='DIST',
955                                 file='fileC',
956                                 size='321',
957                                 RMD160='cde',
958                                 SHA1='345',
959                                 SHA256='cde345'
960                                 ),
961                    ManifestLine(type='EBUILD',
962                                 file=ebuild,
963                                 size='254',
964                                 RMD160='def',
965                                 SHA1='789',
966                                 SHA256='def789'
967                                 ),
968                    ]
969     upst_mlines = [ManifestLine(type='DIST',
970                                 file='fileA',
971                                 size='100',
972                                 RMD160='abc',
973                                 SHA1='123',
974                                 SHA256='abc123'
975                                 ),
976                    # This file is different from current manifest.
977                    # It should be picked up by _CreateManifest.
978                    ManifestLine(type='DIST',
979                                 file='fileB',
980                                 size='345',
981                                 RMD160='bcd',
982                                 SHA1='234',
983                                 SHA256='bcd234'
984                                 ),
985                    ManifestLine(type='EBUILD',
986                                 file=ebuild,
987                                 size='254',
988                                 RMD160='def',
989                                 SHA1='789',
990                                 SHA256='def789'
991                                 ),
992                    ]
993
994     upstream_dir, current_dir = self._SetupManifestTest(ebuild,
995                                                         upst_mlines,
996                                                         curr_mlines)
997
998     current_manifest = os.path.join(current_dir, 'Manifest')
999
1000     # Run test verification.
1001     self.assertTrue(os.path.exists(current_manifest))
1002     cpu.Upgrader._CreateManifest(mocked_upgrader,
1003                                  upstream_dir, current_dir, ebuild)
1004     self.mox.VerifyAll()
1005
1006     expected_mlines = curr_mlines + upst_mlines[1:2]
1007     self._AssertManifestContents(current_manifest, expected_mlines)
1008
1009
1010 class GetPackageUpgradeStateTest(CpuTestBase):
1011   """Test Upgrader._GetPackageUpgradeState"""
1012
1013   def _TestGetPackageUpgradeState(self, pinfo,
1014                                   exists_upstream,
1015                                   ):
1016
1017     cmdargs = []
1018     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
1019
1020     # Add test-specific mocks/stubs
1021
1022     # Replay script
1023     mocked_upgrader._FindUpstreamCPV(pinfo.cpv, unstable_ok=True,
1024                                      ).AndReturn(exists_upstream)
1025     self.mox.ReplayAll()
1026
1027     # Verify
1028     result = cpu.Upgrader._GetPackageUpgradeState(mocked_upgrader, pinfo)
1029     self.mox.VerifyAll()
1030
1031     return result
1032
1033   def testGetPackageUpgradeStateLocalOnly(self):
1034     pinfo = cpu.PInfo(cpv='foo/bar-2',
1035                       overlay='chromiumos-overlay',
1036                       cpv_cmp_upstream=None,
1037                       latest_upstream_cpv=None,
1038                       )
1039     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1040     self.assertEquals(result, utable.UpgradeTable.STATE_LOCAL_ONLY)
1041
1042   def testGetPackageUpgradeStateUnknown(self):
1043     pinfo = cpu.PInfo(cpv='foo/bar-2',
1044                       overlay='portage',
1045                       cpv_cmp_upstream=None,
1046                       latest_upstream_cpv=None,
1047                       )
1048     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1049     self.assertEquals(result, utable.UpgradeTable.STATE_UNKNOWN)
1050
1051   def testGetPackageUpgradeStateUpgradeAndDuplicated(self):
1052     pinfo = cpu.PInfo(cpv='foo/bar-2',
1053                       overlay='chromiumos-overlay',
1054                       cpv_cmp_upstream=1, # outdated
1055                       latest_upstream_cpv='not important',
1056                       )
1057     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=True)
1058     self.assertEquals(result,
1059                       utable.UpgradeTable.STATE_NEEDS_UPGRADE_AND_DUPLICATED)
1060
1061   def testGetPackageUpgradeStateUpgradeAndPatched(self):
1062     pinfo = cpu.PInfo(cpv='foo/bar-2',
1063                       overlay='chromiumos-overlay',
1064                       cpv_cmp_upstream=1, # outdated
1065                       latest_upstream_cpv='not important',
1066                       )
1067     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1068     self.assertEquals(result,
1069                       utable.UpgradeTable.STATE_NEEDS_UPGRADE_AND_PATCHED)
1070
1071   def testGetPackageUpgradeStateUpgrade(self):
1072     pinfo = cpu.PInfo(cpv='foo/bar-2',
1073                       overlay='portage-stable',
1074                       cpv_cmp_upstream=1, # outdated
1075                       latest_upstream_cpv='not important',
1076                       )
1077     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1078     self.assertEquals(result, utable.UpgradeTable.STATE_NEEDS_UPGRADE)
1079
1080   def testGetPackageUpgradeStateDuplicated(self):
1081     pinfo = cpu.PInfo(cpv='foo/bar-2',
1082                       overlay='chromiumos-overlay',
1083                       cpv_cmp_upstream=0, # current
1084                       latest_upstream_cpv='not important',
1085                       )
1086     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=True)
1087     self.assertEquals(result, utable.UpgradeTable.STATE_DUPLICATED)
1088
1089   def testGetPackageUpgradeStatePatched(self):
1090     pinfo = cpu.PInfo(cpv='foo/bar-2',
1091                       overlay='chromiumos-overlay',
1092                       cpv_cmp_upstream=0, # current
1093                       latest_upstream_cpv='not important',
1094                       )
1095     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1096     self.assertEquals(result, utable.UpgradeTable.STATE_PATCHED)
1097
1098   def testGetPackageUpgradeStateCurrent(self):
1099     pinfo = cpu.PInfo(cpv='foo/bar-2',
1100                       overlay='portage-stable',
1101                       cpv_cmp_upstream=0, # current
1102                       latest_upstream_cpv='not important',
1103                       )
1104     result = self._TestGetPackageUpgradeState(pinfo, exists_upstream=False)
1105     self.assertEquals(result, utable.UpgradeTable.STATE_CURRENT)
1106
1107
1108 @unittest.skip('relies on portage module not currently available')
1109 class EmergeableTest(CpuTestBase):
1110   """Test Upgrader._AreEmergeable."""
1111
1112   def _TestAreEmergeable(self, cpvlist, expect,
1113                          debug=False, world=WORLD):
1114     """Test the Upgrader._AreEmergeable method.
1115
1116     |cpvlist| is passed to _AreEmergeable.
1117     |expect| is boolean, expected return value of _AreEmergeable
1118     |debug| requests that emerge output in _AreEmergeable be shown.
1119     |world| is list of lines to override default world contents.
1120     """
1121
1122     cmdargs = ['--upgrade'] + cpvlist
1123     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
1124     self._SetUpPlayground(world=world)
1125
1126     # Add test-specific mocks/stubs
1127
1128     # Replay script
1129     envvars = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
1130                                               mocked_upgrader._curr_arch,
1131                                               unstable_ok=False)
1132     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
1133                                        unstable_ok=False).AndReturn(envvars)
1134     mocked_upgrader._GetBoardCmd('emerge').AndReturn('emerge')
1135     self.mox.ReplayAll()
1136
1137     # Verify
1138     result = cpu.Upgrader._AreEmergeable(mocked_upgrader, cpvlist)
1139     self.mox.VerifyAll()
1140
1141     (code, _cmd, output) = result
1142     if debug or code != expect:
1143       print('\nTest ended with success==%r (expected==%r)' % (code, expect))
1144       print('Emerge output:\n%s' % output)
1145
1146     self.assertEquals(code, expect)
1147
1148   def testAreEmergeableOnePkg(self):
1149     """Should pass, one cpv target."""
1150     cpvlist = ['dev-libs/A-1']
1151     return self._TestAreEmergeable(cpvlist, True)
1152
1153   def testAreEmergeableTwoPkgs(self):
1154     """Should pass, two cpv targets."""
1155     cpvlist = ['dev-libs/A-1', 'dev-libs/B-1']
1156     return self._TestAreEmergeable(cpvlist, True)
1157
1158   def testAreEmergeableOnePkgTwoVersions(self):
1159     """Should fail, targets two versions of same package."""
1160     cpvlist = ['dev-libs/A-1', 'dev-libs/A-2']
1161     return self._TestAreEmergeable(cpvlist, False)
1162
1163   def testAreEmergeableStableFlimFlam(self):
1164     """Should pass, target stable version of pkg."""
1165     cpvlist = ['chromeos-base/flimflam-0.0.1-r228']
1166     return self._TestAreEmergeable(cpvlist, True)
1167
1168   def testAreEmergeableUnstableFlimFlam(self):
1169     """Should fail, target unstable version of pkg."""
1170     cpvlist = ['chromeos-base/flimflam-0.0.2-r123']
1171     return self._TestAreEmergeable(cpvlist, False)
1172
1173   def testAreEmergeableBlockedPackages(self):
1174     """Should fail, targets have blocking deps on each other."""
1175     cpvlist = ['dev-libs/D-1', 'dev-libs/E-2']
1176     return self._TestAreEmergeable(cpvlist, False)
1177
1178   def testAreEmergeableBlockedByInstalledPkg(self):
1179     """Should fail because of installed D-1 pkg."""
1180     cpvlist = ['dev-libs/E-2']
1181     return self._TestAreEmergeable(cpvlist, False)
1182
1183   def testAreEmergeableNotBlockedByInstalledPkgNotInWorld(self):
1184     """Should pass because installed D-1 pkg not in world."""
1185     cpvlist = ['dev-libs/E-2']
1186     return self._TestAreEmergeable(cpvlist, True, world=[])
1187
1188   def testAreEmergeableSamePkgDiffSlots(self):
1189     """Should pass, same package but different slots."""
1190     cpvlist = ['dev-libs/F-1', 'dev-libs/F-2']
1191     return self._TestAreEmergeable(cpvlist, True)
1192
1193   def testAreEmergeableTwoPackagesIncompatibleDeps(self):
1194     """Should fail, targets depend on two versions of same pkg."""
1195     cpvlist = ['dev-apps/X-1', 'dev-apps/Y-2']
1196     return self._TestAreEmergeable(cpvlist, False)
1197
1198
1199 class CPVUtilTest(CpuTestBase):
1200   """Test various CPV utilities in Upgrader"""
1201
1202   def _TestCmpCpv(self, cpv1, cpv2):
1203     """Test Upgrader._CmpCpv"""
1204     # Add test-specific mocks/stubs
1205
1206     # Replay script
1207     self.mox.ReplayAll()
1208
1209     # Verify
1210     result = cpu.Upgrader._CmpCpv(cpv1, cpv2)
1211     self.mox.VerifyAll()
1212
1213     return result
1214
1215   def testCmpCpv(self):
1216     # cpvs to compare
1217     equal = [('foo/bar-1', 'foo/bar-1'),
1218              ('a-b-c/x-y-z-1.2.3-r1', 'a-b-c/x-y-z-1.2.3-r1'),
1219              ('foo/bar-1', 'foo/bar-1-r0'),
1220              (None, None),
1221              ]
1222     for (cpv1, cpv2) in equal:
1223       self.assertEqual(0, self._TestCmpCpv(cpv1, cpv2))
1224
1225     lessthan = [(None, 'foo/bar-1'),
1226                 ('foo/bar-1', 'foo/bar-2'),
1227                 ('foo/bar-1', 'foo/bar-1-r1'),
1228                 ('foo/bar-1-r1', 'foo/bar-1-r2'),
1229                 ('foo/bar-1.2.3', 'foo/bar-1.2.4'),
1230                 ('foo/bar-5a', 'foo/bar-5b'),
1231                 ]
1232     for (cpv1, cpv2) in lessthan:
1233       self.assertTrue(self._TestCmpCpv(cpv1, cpv2) < 0)
1234       self.assertTrue(self._TestCmpCpv(cpv2, cpv1) > 0)
1235
1236     not_comparable = [('foo/bar-1', 'bar/foo-1'),
1237                       ]
1238     for (cpv1, cpv2) in not_comparable:
1239       self.assertEquals(None, self._TestCmpCpv(cpv1, cpv2))
1240
1241   def _TestGetCatPkgFromCpv(self, cpv):
1242     """Test Upgrader._GetCatPkgFromCpv"""
1243     # Add test-specific mocks/stubs
1244
1245     # Replay script
1246     self.mox.ReplayAll()
1247
1248     # Verify
1249     result = cpu.Upgrader._GetCatPkgFromCpv(cpv)
1250     self.mox.VerifyAll()
1251
1252     return result
1253
1254   def testGetCatPkgFromCpv(self):
1255     # (input, output) tuples
1256     data = [('foo/bar-1', 'foo/bar'),
1257             ('a-b-c/x-y-z-1', 'a-b-c/x-y-z'),
1258             ('a-b-c/x-y-z-1.2.3-r3', 'a-b-c/x-y-z'),
1259             ('bar-1', 'bar'),
1260             ('bar', None),
1261             ]
1262
1263     for (cpv, catpn) in data:
1264       result = self._TestGetCatPkgFromCpv(cpv)
1265       self.assertEquals(catpn, result)
1266
1267   def _TestGetVerRevFromCpv(self, cpv):
1268     """Test Upgrader._GetVerRevFromCpv"""
1269     # Add test-specific mocks/stubs
1270
1271     # Replay script
1272     self.mox.ReplayAll()
1273
1274     # Verify
1275     result = cpu.Upgrader._GetVerRevFromCpv(cpv)
1276     self.mox.VerifyAll()
1277
1278     return result
1279
1280   def testGetVerRevFromCpv(self):
1281     # (input, output) tuples
1282     data = [('foo/bar-1', '1'),
1283             ('a-b-c/x-y-z-1', '1'),
1284             ('a-b-c/x-y-z-1.2.3-r3', '1.2.3-r3'),
1285             ('foo/bar-3.222-r0', '3.222'),
1286             ('bar-1', '1'),
1287             ('bar', None),
1288             ]
1289
1290     for (cpv, verrev) in data:
1291       result = self._TestGetVerRevFromCpv(cpv)
1292       self.assertEquals(verrev, result)
1293
1294   def _TestGetEbuildPathFromCpv(self, cpv):
1295     """Test Upgrader._GetEbuildPathFromCpv"""
1296     # Add test-specific mocks/stubs
1297
1298     # Replay script
1299     self.mox.ReplayAll()
1300
1301     # Verify
1302     result = cpu.Upgrader._GetEbuildPathFromCpv(cpv)
1303     self.mox.VerifyAll()
1304
1305     return result
1306
1307   def testGetEbuildPathFromCpv(self):
1308     # (input, output) tuples
1309     data = [('foo/bar-1', 'foo/bar/bar-1.ebuild'),
1310             ('a-b-c/x-y-z-1', 'a-b-c/x-y-z/x-y-z-1.ebuild'),
1311             ('a-b-c/x-y-z-1.2.3-r3', 'a-b-c/x-y-z/x-y-z-1.2.3-r3.ebuild'),
1312             ('foo/bar-3.222-r0', 'foo/bar/bar-3.222-r0.ebuild'),
1313             ]
1314
1315     for (cpv, verrev) in data:
1316       result = self._TestGetEbuildPathFromCpv(cpv)
1317       self.assertEquals(verrev, result)
1318
1319
1320 class PortageStableTest(CpuTestBase):
1321   """Test Upgrader methods _SaveStatusOnStableRepo, _CheckStableRepoOnBranch"""
1322
1323   STATUS_MIX = {'path1/file1': 'M',
1324                 'path1/path2/file2': 'A',
1325                 'a/b/.x/y~': 'D',
1326                 'foo/bar': 'C',
1327                 '/bar/foo': 'U',
1328                 'unknown/file': '??',
1329                 }
1330   STATUS_UNKNOWN = {'foo/bar': '??',
1331                     'a/b/c': '??',
1332                     }
1333   STATUS_EMPTY = {}
1334
1335   #
1336   # _CheckStableRepoOnBranch
1337   #
1338
1339   def _TestCheckStableRepoOnBranch(self, run_result, expect_err):
1340     """Test Upgrader._CheckStableRepoOnBranch"""
1341     cmdargs = []
1342     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
1343
1344     # Add test-specific mocks/stubs
1345
1346     # Replay script
1347     mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
1348                             ['branch'], redirect_stdout=True,
1349                             ).AndReturn(run_result)
1350     self.mox.ReplayAll()
1351
1352     # Verify
1353     try:
1354       cpu.Upgrader._CheckStableRepoOnBranch(mocked_upgrader)
1355       self.assertFalse(expect_err, 'Expected RuntimeError, but none raised.')
1356     except RuntimeError as ex:
1357       self.assertTrue(expect_err, 'Unexpected RuntimeError: %s' % str(ex))
1358     self.mox.VerifyAll()
1359
1360   def testCheckStableRepoOnBranchNoBranch(self):
1361     """Should fail due to 'git branch' saying 'no branch'"""
1362     output = '* (no branch)\n  somebranch\n  otherbranch\n'
1363     run_result = RunCommandResult(returncode=0, output=output)
1364     self._TestCheckStableRepoOnBranch(run_result, True)
1365
1366   def testCheckStableRepoOnBranchOK1(self):
1367     """Should pass as 'git branch' indicates a branch"""
1368     output = '* somebranch\n  otherbranch\n'
1369     run_result = RunCommandResult(returncode=0, output=output)
1370     self._TestCheckStableRepoOnBranch(run_result, False)
1371
1372   def testCheckStableRepoOnBranchOK2(self):
1373     """Should pass as 'git branch' indicates a branch"""
1374     output = '  somebranch\n* otherbranch\n'
1375     run_result = RunCommandResult(returncode=0, output=output)
1376     self._TestCheckStableRepoOnBranch(run_result, False)
1377
1378   def testCheckStableRepoOnBranchFail(self):
1379     """Should fail as 'git branch' failed"""
1380     output = 'does not matter'
1381     run_result = RunCommandResult(returncode=1, output=output)
1382     self._TestCheckStableRepoOnBranch(run_result, True)
1383
1384   #
1385   # _SaveStatusOnStableRepo
1386   #
1387
1388   def _TestSaveStatusOnStableRepo(self, run_result):
1389     """Test Upgrader._SaveStatusOnStableRepo"""
1390     cmdargs = []
1391     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
1392
1393     # Add test-specific mocks/stubs
1394
1395     # Replay script
1396     mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
1397                             ['status', '-s'], redirect_stdout=True,
1398                             ).AndReturn(run_result)
1399     self.mox.ReplayAll()
1400
1401     # Verify
1402     cpu.Upgrader._SaveStatusOnStableRepo(mocked_upgrader)
1403     self.mox.VerifyAll()
1404
1405     self.assertFalse(mocked_upgrader._stable_repo_stashed)
1406     return mocked_upgrader._stable_repo_status
1407
1408   def testSaveStatusOnStableRepoFailed(self):
1409     """Test case where 'git status -s' fails, should raise RuntimeError"""
1410     run_result = RunCommandResult(returncode=1,
1411                                   output=None)
1412
1413     self.assertRaises(RuntimeError,
1414                       self._TestSaveStatusOnStableRepo,
1415                       run_result)
1416
1417   def testSaveStatusOnStableRepoAllKinds(self):
1418     """Test where 'git status -s' returns all status kinds"""
1419     status_lines = ['%2s %s' % (v, k) for (k, v) in self.STATUS_MIX.items()]
1420     status_output = '\n'.join(status_lines)
1421     run_result = RunCommandResult(returncode=0,
1422                                   output=status_output)
1423     status = self._TestSaveStatusOnStableRepo(run_result)
1424     self.assertEqual(status, self.STATUS_MIX)
1425
1426   def testSaveStatusOnStableRepoRename(self):
1427     """Test where 'git status -s' shows a file rename"""
1428     old = 'path/foo-1'
1429     new = 'path/foo-2'
1430     status_lines = [' R %s --> %s' % (old, new)]
1431     status_output = '\n'.join(status_lines)
1432     run_result = RunCommandResult(returncode=0,
1433                                   output=status_output)
1434     status = self._TestSaveStatusOnStableRepo(run_result)
1435     self.assertEqual(status, {old: 'D', new: 'A'})
1436
1437   def testSaveStatusOnStableRepoEmpty(self):
1438     """Test empty response from 'git status -s'"""
1439     run_result = RunCommandResult(returncode=0,
1440                                   output='')
1441     status = self._TestSaveStatusOnStableRepo(run_result)
1442     self.assertEqual(status, {})
1443
1444   #
1445   # _AnyChangesStaged
1446   #
1447
1448   def _TestAnyChangesStaged(self, status_dict):
1449     """Test Upgrader._AnyChangesStaged"""
1450     mocked_upgrader = self._MockUpgrader(_stable_repo_status=status_dict)
1451
1452     # Add test-specific mocks/stubs
1453
1454     # Replay script
1455     self.mox.ReplayAll()
1456
1457     # Verify
1458     result = cpu.Upgrader._AnyChangesStaged(mocked_upgrader)
1459     self.mox.VerifyAll()
1460
1461     return result
1462
1463   def testAnyChangesStagedMix(self):
1464     """Should return True"""
1465     self.assertTrue(self._TestAnyChangesStaged(self.STATUS_MIX),
1466                     'Failed to notice files with changed status.')
1467
1468   def testAnyChangesStagedUnknown(self):
1469     """Should return False, only files with '??' status"""
1470     self.assertFalse(self._TestAnyChangesStaged(self.STATUS_UNKNOWN),
1471                     'Should not consider files with "??" status.')
1472
1473   def testAnyChangesStagedEmpty(self):
1474     """Should return False, no file statuses"""
1475     self.assertFalse(self._TestAnyChangesStaged(self.STATUS_EMPTY),
1476                     'No files should mean no changes staged.')
1477
1478   #
1479   # _StashChanges
1480   #
1481
1482   def testStashChanges(self):
1483     """Test Upgrader._StashChanges"""
1484     mocked_upgrader = self._MockUpgrader(cmdargs=[],
1485                                          _stable_repo_stashed=False)
1486     self.assertFalse(mocked_upgrader._stable_repo_stashed)
1487
1488     # Add test-specific mocks/stubs
1489
1490     # Replay script
1491     mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
1492                             ['stash', 'save'],
1493                             redirect_stdout=True,
1494                             combine_stdout_stderr=True)
1495     self.mox.ReplayAll()
1496
1497     # Verify
1498     cpu.Upgrader._StashChanges(mocked_upgrader)
1499     self.mox.VerifyAll()
1500
1501     self.assertTrue(mocked_upgrader._stable_repo_stashed)
1502
1503   #
1504   # _UnstashAnyChanges
1505   #
1506
1507   def _TestUnstashAnyChanges(self, stashed):
1508     """Test Upgrader._UnstashAnyChanges"""
1509     mocked_upgrader = self._MockUpgrader(cmdargs=[],
1510                                          _stable_repo_stashed=stashed)
1511     self.assertEqual(stashed, mocked_upgrader._stable_repo_stashed)
1512
1513     # Add test-specific mocks/stubs
1514
1515     # Replay script
1516     if stashed:
1517       mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
1518                               ['stash', 'pop', '--index'],
1519                               redirect_stdout=True,
1520                               combine_stdout_stderr=True)
1521     self.mox.ReplayAll()
1522
1523     # Verify
1524     cpu.Upgrader._UnstashAnyChanges(mocked_upgrader)
1525     self.mox.VerifyAll()
1526
1527     self.assertFalse(mocked_upgrader._stable_repo_stashed)
1528
1529   def testUnstashAnyChanges(self):
1530     self._TestUnstashAnyChanges(True)
1531     self._TestUnstashAnyChanges(False)
1532
1533   #
1534   # _DropAnyStashedChanges
1535   #
1536
1537   def _TestDropAnyStashedChanges(self, stashed):
1538     """Test Upgrader._DropAnyStashedChanges"""
1539     mocked_upgrader = self._MockUpgrader(cmdargs=[],
1540                                          _stable_repo_stashed=stashed)
1541     self.assertEqual(stashed, mocked_upgrader._stable_repo_stashed)
1542
1543     # Add test-specific mocks/stubs
1544
1545     # Replay script
1546     if stashed:
1547       mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
1548                               ['stash', 'drop'],
1549                               redirect_stdout=True,
1550                               combine_stdout_stderr=True)
1551     self.mox.ReplayAll()
1552
1553     # Verify
1554     cpu.Upgrader._DropAnyStashedChanges(mocked_upgrader)
1555     self.mox.VerifyAll()
1556
1557     self.assertFalse(mocked_upgrader._stable_repo_stashed)
1558
1559   def testDropAnyStashedChanges(self):
1560     self._TestDropAnyStashedChanges(True)
1561     self._TestDropAnyStashedChanges(False)
1562
1563
1564 class UtilityTest(CpuTestBase):
1565   """Test several Upgrader methods.
1566
1567   Test these Upgrader methods: _SplitEBuildPath, _GenPortageEnvvars
1568   """
1569
1570   #
1571   # _IsInUpgradeMode
1572   #
1573
1574   def _TestIsInUpgradeMode(self, cmdargs):
1575     """Test Upgrader._IsInUpgradeMode.  Pretty simple."""
1576     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
1577
1578     # Add test-specific mocks/stubs
1579
1580     # Replay script
1581     self.mox.ReplayAll()
1582
1583     # Verify
1584     result = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
1585     self.mox.VerifyAll()
1586
1587     return result
1588
1589   def testIsInUpgradeModeNoOpts(self):
1590     """Should not be in upgrade mode with no options."""
1591     result = self._TestIsInUpgradeMode([])
1592     self.assertFalse(result)
1593
1594   def testIsInUpgradeModeUpgrade(self):
1595     """Should be in upgrade mode with --upgrade."""
1596     result = self._TestIsInUpgradeMode(['--upgrade'])
1597     self.assertTrue(result)
1598
1599   def testIsInUpgradeModeUpgradeDeep(self):
1600     """Should be in upgrade mode with --upgrade-deep."""
1601     result = self._TestIsInUpgradeMode(['--upgrade-deep'])
1602     self.assertTrue(result)
1603
1604   #
1605   # _GetBoardCmd
1606   #
1607
1608   def _TestGetBoardCmd(self, cmd, board):
1609     """Test Upgrader._GetBoardCmd."""
1610     mocked_upgrader = self._MockUpgrader(_curr_board=board)
1611
1612     # Replay script
1613     self.mox.ReplayAll()
1614
1615     # Verify
1616     result = cpu.Upgrader._GetBoardCmd(mocked_upgrader, cmd)
1617     self.mox.VerifyAll()
1618
1619     return result
1620
1621   def testGetBoardCmdKnownCmds(self):
1622     board = 'x86-alex'
1623     for cmd in ['emerge', 'equery', 'portageq']:
1624       result = self._TestGetBoardCmd(cmd, cpu.Upgrader.HOST_BOARD)
1625       self.assertEquals(result, cmd)
1626       result = self._TestGetBoardCmd(cmd, board)
1627       self.assertEquals(result, '%s-%s' % (cmd, board))
1628
1629   def testGetBoardCmdUnknownCmd(self):
1630     board = 'x86-alex'
1631     cmd = 'foo'
1632     result = self._TestGetBoardCmd(cmd, cpu.Upgrader.HOST_BOARD)
1633     self.assertEquals(result, cmd)
1634     result = self._TestGetBoardCmd(cmd, board)
1635     self.assertEquals(result, cmd)
1636
1637   #
1638   # _GenPortageEnvvars testing
1639   #
1640
1641   def _TestGenPortageEnvvars(self, arch, unstable_ok,
1642                              portdir=None, portage_configroot=None):
1643     """Testing the behavior of the Upgrader._GenPortageEnvvars method."""
1644     mocked_upgrader = self._MockUpgrader()
1645
1646     # Replay script
1647     self.mox.ReplayAll()
1648
1649     # Verify
1650     result = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
1651                                              arch, unstable_ok,
1652                                              portdir, portage_configroot)
1653     self.mox.VerifyAll()
1654
1655     keyw = arch
1656     if unstable_ok:
1657       keyw = arch + ' ~' + arch
1658
1659     self.assertEquals(result['ACCEPT_KEYWORDS'], keyw)
1660     if portdir is None:
1661       self.assertFalse('PORTDIR' in result)
1662     else:
1663       self.assertEquals(result['PORTDIR'], portdir)
1664     if portage_configroot is None:
1665       self.assertFalse('PORTAGE_CONFIGROOT' in result)
1666     else:
1667       self.assertEquals(result['PORTAGE_CONFIGROOT'], portage_configroot)
1668
1669   def testGenPortageEnvvars1(self):
1670     self._TestGenPortageEnvvars('arm', False)
1671
1672   def testGenPortageEnvvars2(self):
1673     self._TestGenPortageEnvvars('x86', True)
1674
1675   def testGenPortageEnvvars3(self):
1676     self._TestGenPortageEnvvars('x86', True,
1677                                 portdir='/foo/bar',
1678                                 portage_configroot='/bar/foo')
1679
1680   #
1681   # _SplitEBuildPath testing
1682   #
1683
1684   def _TestSplitEBuildPath(self, ebuild_path, golden_result):
1685     """Test the behavior of the Upgrader._SplitEBuildPath method."""
1686     mocked_upgrader = self._MockUpgrader()
1687
1688     # Replay script
1689     self.mox.ReplayAll()
1690
1691     # Verify
1692     result = cpu.Upgrader._SplitEBuildPath(mocked_upgrader,
1693                                            ebuild_path)
1694     self.assertEquals(result, golden_result)
1695     self.mox.VerifyAll()
1696
1697   def testSplitEBuildPath1(self):
1698     self._TestSplitEBuildPath('/foo/bar/portage/dev-libs/A/A-2.ebuild',
1699                               ('portage', 'dev-libs', 'A', 'A-2'))
1700
1701   def testSplitEBuildPath2(self):
1702     self._TestSplitEBuildPath('/foo/ooo/ccc/ppp/ppp-1.2.3-r123.ebuild',
1703                               ('ooo', 'ccc', 'ppp', 'ppp-1.2.3-r123'))
1704
1705
1706 @unittest.skip('relies on portage module not currently available')
1707 class TreeInspectTest(CpuTestBase):
1708   """Test Upgrader methods: _FindCurrentCPV, _FindUpstreamCPV"""
1709
1710   def _GenerateTestInput(self, category, pkg_name, ver_rev,
1711                          path_prefix=DEFAULT_PORTDIR):
1712     """Return tuple (ebuild_path, cpv, cp)."""
1713     ebuild_path = None
1714     cpv = None
1715     if ver_rev:
1716       ebuild_path = '%s/%s/%s/%s-%s.ebuild' % (path_prefix,
1717                                                category, pkg_name,
1718                                                pkg_name, ver_rev)
1719       cpv = '%s/%s-%s' % (category, pkg_name, ver_rev)
1720     cp = '%s/%s' % (category, pkg_name)
1721     return (ebuild_path, cpv, cp)
1722
1723   #
1724   # _FindUpstreamCPV testing
1725   #
1726
1727   def _TestFindUpstreamCPV(self, pkg_arg, ebuild_expect, unstable_ok=False):
1728     """Test Upgrader._FindUpstreamCPV
1729
1730     This points _FindUpstreamCPV at the ResolverPlayground as if it is
1731     the upstream tree.
1732     """
1733
1734     self._SetUpPlayground()
1735     eroot = self._GetPlaygroundRoot()
1736     mocked_upgrader = self._MockUpgrader(_curr_board=None,
1737                                          _upstream=eroot,
1738                                          )
1739
1740     # Add test-specific mocks/stubs
1741
1742     # Replay script
1743     envvars = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
1744                                               mocked_upgrader._curr_arch,
1745                                               unstable_ok,
1746                                               portdir=eroot,
1747                                               portage_configroot=eroot)
1748     portage_configroot = mocked_upgrader._emptydir
1749     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
1750                                        unstable_ok,
1751                                        portdir=mocked_upgrader._upstream,
1752                                        portage_configroot=portage_configroot,
1753                                        ).AndReturn(envvars)
1754
1755     if ebuild_expect:
1756       ebuild_path = eroot + ebuild_expect
1757       split_path = cpu.Upgrader._SplitEBuildPath(mocked_upgrader, ebuild_path)
1758       mocked_upgrader._SplitEBuildPath(ebuild_path).AndReturn(split_path)
1759     self.mox.ReplayAll()
1760
1761     # Verify
1762     result = cpu.Upgrader._FindUpstreamCPV(mocked_upgrader, pkg_arg,
1763                                            unstable_ok)
1764     self.mox.VerifyAll()
1765     self.assertTrue(bool(ebuild_expect) == bool(result))
1766
1767     return result
1768
1769   def testFindUpstreamA2(self):
1770     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-libs',
1771                                                 pkg_name='A',
1772                                                 ver_rev='2')
1773     result = self._TestFindUpstreamCPV(cp, ebuild)
1774     self.assertEquals(result, cpv)
1775
1776   def testFindUpstreamAAA(self):
1777     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-apps',
1778                                                 pkg_name='AAA',
1779                                                 ver_rev=None)
1780     result = self._TestFindUpstreamCPV(cp, ebuild)
1781     self.assertEquals(result, cpv)
1782
1783   def testFindUpstreamF(self):
1784     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-libs',
1785                                                 pkg_name='F',
1786                                                 ver_rev='2')
1787     result = self._TestFindUpstreamCPV(cp, ebuild)
1788     self.assertEquals(result, cpv)
1789
1790   def testFindUpstreamFlimflam(self):
1791     """Should find 0.0.1-r228 because more recent flimflam unstable."""
1792     (ebuild, cpv, cp) = self._GenerateTestInput(category='chromeos-base',
1793                                                 pkg_name='flimflam',
1794                                                 ver_rev='0.0.1-r228')
1795     result = self._TestFindUpstreamCPV(cp, ebuild)
1796     self.assertEquals(result, cpv)
1797
1798   def testFindUpstreamFlimflamUnstable(self):
1799     """Should find 0.0.2-r123 because of unstable_ok."""
1800     (ebuild, cpv, cp) = self._GenerateTestInput(category='chromeos-base',
1801                                                 pkg_name='flimflam',
1802                                                 ver_rev='0.0.2-r123')
1803     result = self._TestFindUpstreamCPV(cp, ebuild, unstable_ok=True)
1804     self.assertEquals(result, cpv)
1805
1806   #
1807   # _FindCurrentCPV testing
1808   #
1809
1810   def _TestFindCurrentCPV(self, pkg_arg, ebuild_expect):
1811     """Test Upgrader._FindCurrentCPV
1812
1813     This test points Upgrader._FindCurrentCPV to the ResolverPlayground
1814     tree as if it is the local source.
1815     """
1816
1817     mocked_upgrader = self._MockUpgrader(_curr_board=None)
1818     self._SetUpPlayground()
1819     eroot = self._GetPlaygroundRoot()
1820
1821     # Add test-specific mocks/stubs
1822
1823     # Replay script
1824     envvars = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
1825                                               mocked_upgrader._curr_arch,
1826                                               unstable_ok=False)
1827     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
1828                                        unstable_ok=False).AndReturn(envvars)
1829     mocked_upgrader._GetBoardCmd('equery').AndReturn('equery')
1830
1831     if ebuild_expect:
1832       ebuild_path = eroot + ebuild_expect
1833       split_path = cpu.Upgrader._SplitEBuildPath(mocked_upgrader, ebuild_path)
1834       mocked_upgrader._SplitEBuildPath(ebuild_path).AndReturn(split_path)
1835
1836     self.mox.ReplayAll()
1837
1838     # Verify
1839     result = cpu.Upgrader._FindCurrentCPV(mocked_upgrader, pkg_arg)
1840     self.mox.VerifyAll()
1841
1842     return result
1843
1844   def testFindCurrentA(self):
1845     """Should find dev-libs/A-2."""
1846     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-libs',
1847                                                 pkg_name='A',
1848                                                 ver_rev='2')
1849     result = self._TestFindCurrentCPV(cp, ebuild)
1850     self.assertEquals(result, cpv)
1851
1852   def testFindCurrentAAA(self):
1853     """Should find None, because dev-libs/AAA does not exist in tree."""
1854     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-libs',
1855                                                 pkg_name='AAA',
1856                                                 ver_rev=None)
1857     result = self._TestFindCurrentCPV(cp, ebuild)
1858     self.assertEquals(result, cpv)
1859
1860   def testFindCurrentF(self):
1861     """Should find dev-libs/F-2."""
1862     (ebuild, cpv, cp) = self._GenerateTestInput(category='dev-libs',
1863                                                 pkg_name='F',
1864                                                 ver_rev='2')
1865     result = self._TestFindCurrentCPV(cp, ebuild)
1866     self.assertEquals(result, cpv)
1867
1868   def testFindCurrentFlimflam(self):
1869     """Should find 0.0.1-r228 because more recent flimflam unstable."""
1870     (ebuild, cpv, cp) = self._GenerateTestInput(category='chromeos-base',
1871                                                 pkg_name='flimflam',
1872                                                 ver_rev='0.0.1-r228')
1873     result = self._TestFindCurrentCPV(cp, ebuild)
1874     self.assertEquals(result, cpv)
1875
1876
1877 class RunBoardTest(CpuTestBase):
1878   """Test Upgrader.RunBoard,PrepareToRun,RunCompleted."""
1879
1880   def testRunCompletedSpecified(self):
1881     cmdargs = ['--upstream=/some/dir']
1882     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
1883                                          _emptydir='empty-dir',
1884                                          _curr_board=None)
1885
1886     # Add test-specific mocks/stubs
1887     self.mox.StubOutWithMock(osutils, 'RmDir')
1888
1889     # Replay script
1890     osutils.RmDir('empty-dir', ignore_missing=True)
1891     self.mox.ReplayAll()
1892
1893     # Verify
1894     with self.OutputCapturer():
1895       cpu.Upgrader.RunCompleted(mocked_upgrader)
1896     self.mox.VerifyAll()
1897
1898   def testRunCompletedRemoveCache(self):
1899     cmdargs = ['--no-upstream-cache']
1900     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
1901                                          _emptydir='empty-dir',
1902                                          _curr_board=None)
1903
1904     # Add test-specific mocks/stubs
1905     self.mox.StubOutWithMock(osutils, 'RmDir')
1906     self.mox.StubOutWithMock(osutils, 'SafeUnlink')
1907
1908     # Replay script
1909     osutils.RmDir(mocked_upgrader._upstream, ignore_missing=True)
1910     osutils.SafeUnlink('%s-README' % mocked_upgrader._upstream)
1911     osutils.RmDir('empty-dir', ignore_missing=True)
1912     self.mox.ReplayAll()
1913
1914     # Verify
1915     with self.OutputCapturer():
1916       cpu.Upgrader.RunCompleted(mocked_upgrader)
1917     self.mox.VerifyAll()
1918
1919   def testRunCompletedKeepCache(self):
1920     cmdargs = []
1921     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
1922                                          _emptydir='empty-dir',
1923                                          _curr_board=None)
1924
1925     # Add test-specific mocks/stubs
1926     self.mox.StubOutWithMock(osutils, 'RmDir')
1927
1928     # Replay script
1929     osutils.RmDir('empty-dir', ignore_missing=True)
1930     self.mox.ReplayAll()
1931
1932     # Verify
1933     with self.OutputCapturer():
1934       cpu.Upgrader.RunCompleted(mocked_upgrader)
1935     self.mox.VerifyAll()
1936
1937   def testPrepareToRunUpstreamRepoExists(self):
1938     cmdargs = []
1939     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
1940                                          _curr_board=None)
1941
1942     # Add test-specific mocks/stubs
1943     self.mox.StubOutWithMock(os.path, 'exists')
1944     self.mox.StubOutWithMock(osutils, 'RmDir')
1945
1946     # Replay script
1947     os.path.exists('/tmp/portage/.git/shallow').AndReturn(False)
1948     osutils.RmDir('/tmp/portage', ignore_missing=True)
1949     os.path.exists('/tmp/portage').AndReturn(True)
1950     mocked_upgrader._RunGit(
1951         '/tmp/portage', ['remote', 'set-url', 'origin',
1952                          cpu.Upgrader.PORTAGE_GIT_URL])
1953     mocked_upgrader._RunGit(
1954         '/tmp/portage', ['remote', 'update'])
1955     mocked_upgrader._RunGit(
1956         '/tmp/portage', ['checkout', 'origin/gentoo'],
1957         combine_stdout_stderr=True, redirect_stdout=True)
1958     self.mox.ReplayAll()
1959
1960     # Verify
1961     with self.OutputCapturer():
1962       cpu.Upgrader.PrepareToRun(mocked_upgrader)
1963     self.mox.VerifyAll()
1964
1965   @osutils.TempDirDecorator
1966   def testPrepareToRunUpstreamRepoNew(self):
1967     cmdargs = []
1968     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
1969                                          _upstream=self.tempdir,
1970                                          _curr_board=None)
1971
1972     # Add test-specific mocks/stubs
1973     self.mox.StubOutWithMock(os.path, 'dirname')
1974     self.mox.StubOutWithMock(os.path, 'basename')
1975     self.mox.StubOutWithMock(tempfile, 'mkdtemp')
1976
1977     # Replay script
1978     tempfile.mkdtemp()
1979     root = os.path.dirname(mocked_upgrader._upstream).AndReturn('root')
1980     name = os.path.basename(mocked_upgrader._upstream).AndReturn('name')
1981     os.path.basename('origin/gentoo').AndReturn('gentoo')
1982     mocked_upgrader._RunGit(root,
1983                             ['clone', '--branch', 'gentoo', '--depth', '1',
1984                              cpu.Upgrader.PORTAGE_GIT_URL, name])
1985     self.mox.ReplayAll()
1986
1987     # Verify
1988     try:
1989       with self.OutputCapturer():
1990         cpu.Upgrader.PrepareToRun(mocked_upgrader)
1991       self.mox.VerifyAll()
1992     finally:
1993       self.mox.UnsetStubs()
1994
1995     readme_path = self.tempdir + '-README'
1996     self.assertTrue(os.path.exists(readme_path))
1997     os.remove(readme_path)
1998
1999   def _TestRunBoard(self, pinfolist, upgrade=False, staged_changes=False):
2000     """Test Upgrader.RunBoard."""
2001
2002     targetlist = [pinfo.user_arg for pinfo in pinfolist]
2003     upstream_only_pinfolist = [pinfo for pinfo in pinfolist if not pinfo.cpv]
2004
2005     cmdargs = targetlist
2006     if upgrade:
2007       cmdargs = ['--upgrade'] + cmdargs
2008     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2009                                          _curr_board=None)
2010     board = 'runboard_testboard'
2011
2012     # Add test-specific mocks/stubs
2013     self.mox.StubOutWithMock(cpu.Upgrader, '_FindBoardArch')
2014
2015     # Replay script
2016     mocked_upgrader._SaveStatusOnStableRepo()
2017     mocked_upgrader._LoadStableRepoCategories()
2018     cpu.Upgrader._FindBoardArch(board).AndReturn('x86')
2019     upgrade_mode = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
2020     mocked_upgrader._IsInUpgradeMode().AndReturn(upgrade_mode)
2021     mocked_upgrader._AnyChangesStaged().AndReturn(staged_changes)
2022     if (staged_changes):
2023       mocked_upgrader._StashChanges()
2024
2025     mocked_upgrader._ResolveAndVerifyArgs(targetlist,
2026                                           upgrade_mode).AndReturn(pinfolist)
2027     if upgrade:
2028       mocked_upgrader._FinalizeUpstreamPInfolist(pinfolist).AndReturn([])
2029     else:
2030       mocked_upgrader._GetCurrentVersions(pinfolist).AndReturn(pinfolist)
2031       mocked_upgrader._FinalizeLocalPInfolist(pinfolist).AndReturn([])
2032
2033       if upgrade_mode:
2034         mocked_upgrader._FinalizeUpstreamPInfolist(
2035           upstream_only_pinfolist).AndReturn([])
2036
2037     mocked_upgrader._UnstashAnyChanges()
2038     mocked_upgrader._UpgradePackages([])
2039
2040     mocked_upgrader._DropAnyStashedChanges()
2041
2042     self.mox.ReplayAll()
2043
2044     # Verify
2045     with self.OutputCapturer():
2046       cpu.Upgrader.RunBoard(mocked_upgrader, board)
2047     self.mox.VerifyAll()
2048
2049   def testRunBoard1(self):
2050     target_pinfolist = [cpu.PInfo(user_arg='dev-libs/A',
2051                                   cpv='dev-libs/A-1',
2052                                   upstream_cpv='dev-libs/A-2',
2053                                   ),
2054                         ]
2055     return self._TestRunBoard(target_pinfolist)
2056
2057   def testRunBoard2(self):
2058     target_pinfolist = [cpu.PInfo(user_arg='dev-libs/A',
2059                                   cpv='dev-libs/A-1',
2060                                   upstream_cpv='dev-libs/A-2',
2061                                   ),
2062                         ]
2063     return self._TestRunBoard(target_pinfolist, upgrade=True)
2064
2065   def testRunBoard3(self):
2066     target_pinfolist = [cpu.PInfo(user_arg='dev-libs/A',
2067                                   cpv='dev-libs/A-1',
2068                                   upstream_cpv='dev-libs/A-2',
2069                                   ),
2070                         ]
2071     return self._TestRunBoard(target_pinfolist, upgrade=True,
2072                               staged_changes=True)
2073
2074   def testRunBoardUpstreamOnlyStatusMode(self):
2075     """Status mode with package that is only upstream should error."""
2076
2077     pinfolist = [cpu.PInfo(user_arg='dev-libs/M',
2078                            cpv=None,
2079                            upstream_cpv='dev-libs/M-2',
2080                            ),
2081                  ]
2082
2083     targetlist = [pinfo.user_arg for pinfo in pinfolist]
2084
2085     mocked_upgrader = self._MockUpgrader(cmdargs=['dev-libs/M'],
2086                                          _curr_board=None)
2087     board = 'runboard_testboard'
2088
2089     # Add test-specific mocks/stubs
2090     self.mox.StubOutWithMock(cpu.Upgrader, '_FindBoardArch')
2091
2092     # Replay script
2093     mocked_upgrader._SaveStatusOnStableRepo()
2094     mocked_upgrader._LoadStableRepoCategories()
2095     cpu.Upgrader._FindBoardArch(board).AndReturn('x86')
2096     upgrade_mode = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
2097     mocked_upgrader._IsInUpgradeMode().AndReturn(upgrade_mode)
2098     mocked_upgrader._AnyChangesStaged().AndReturn(False)
2099
2100     mocked_upgrader._ResolveAndVerifyArgs(targetlist,
2101                                           upgrade_mode).AndReturn(pinfolist)
2102     mocked_upgrader._DropAnyStashedChanges()
2103     self.mox.ReplayAll()
2104
2105     # Verify
2106     with self.OutputCapturer():
2107       self.assertRaises(RuntimeError,
2108                         cpu.Upgrader.RunBoard,
2109                         mocked_upgrader, board)
2110     self.mox.VerifyAll()
2111
2112
2113 class GiveEmergeResultsTest(CpuTestBase):
2114   """Test Upgrader._GiveEmergeResults"""
2115
2116   def _TestGiveEmergeResultsOK(self, pinfolist, ok, error=None):
2117     cmdargs = []
2118     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
2119
2120     # Add test-specific mocks/stubs
2121
2122     # Replay script
2123     mocked_upgrader._AreEmergeable(mox.IgnoreArg(),
2124                                    ).AndReturn((ok, None, None))
2125     self.mox.ReplayAll()
2126
2127     # Verify
2128     result = None
2129     with self.OutputCapturer():
2130       if error:
2131         self.assertRaises(error, cpu.Upgrader._GiveEmergeResults,
2132                           mocked_upgrader, pinfolist)
2133       else:
2134         result = cpu.Upgrader._GiveEmergeResults(mocked_upgrader, pinfolist)
2135     self.mox.VerifyAll()
2136
2137     return result
2138
2139   def testGiveEmergeResultsUnmaskedOK(self):
2140     pinfolist = [cpu.PInfo(upgraded_cpv='abc/def-4', upgraded_unmasked=True),
2141                  cpu.PInfo(upgraded_cpv='bcd/efg-8', upgraded_unmasked=True),
2142                  ]
2143     self._TestGiveEmergeResultsOK(pinfolist, True)
2144
2145   def testGiveEmergeResultsUnmaskedNotOK(self):
2146     pinfolist = [cpu.PInfo(upgraded_cpv='abc/def-4', upgraded_unmasked=True),
2147                  cpu.PInfo(upgraded_cpv='bcd/efg-8', upgraded_unmasked=True),
2148                  ]
2149     self._TestGiveEmergeResultsOK(pinfolist, False, error=RuntimeError)
2150
2151   def _TestGiveEmergeResultsMasked(self, pinfolist, ok, masked_cpvs,
2152                                    error=None):
2153     cmdargs = []
2154     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
2155
2156     # Add test-specific mocks/stubs
2157
2158     # Replay script
2159     emergeable_tuple = (ok, 'some-cmd', 'some-output')
2160     mocked_upgrader._AreEmergeable(mox.IgnoreArg(),
2161                                    ).AndReturn(emergeable_tuple)
2162     if not ok:
2163       for cpv in masked_cpvs:
2164         mocked_upgrader._GiveMaskedError(cpv, 'some-output').InAnyOrder()
2165     self.mox.ReplayAll()
2166
2167     # Verify
2168     result = None
2169     with self.OutputCapturer():
2170       if error:
2171         self.assertRaises(error, cpu.Upgrader._GiveEmergeResults,
2172                           mocked_upgrader, pinfolist)
2173       else:
2174         result = cpu.Upgrader._GiveEmergeResults(mocked_upgrader, pinfolist)
2175     self.mox.VerifyAll()
2176
2177     return result
2178
2179   def testGiveEmergeResultsMaskedOK(self):
2180     pinfolist = [cpu.PInfo(upgraded_cpv='abc/def-4', upgraded_unmasked=False),
2181                  cpu.PInfo(upgraded_cpv='bcd/efg-8', upgraded_unmasked=False),
2182                  ]
2183     masked_cpvs = ['abc/def-4', 'bcd/efg-8']
2184     self._TestGiveEmergeResultsMasked(pinfolist, True, masked_cpvs,
2185                                       error=RuntimeError)
2186
2187   def testGiveEmergeResultsMaskedNotOK(self):
2188     pinfolist = [cpu.PInfo(upgraded_cpv='abc/def-4', upgraded_unmasked=False),
2189                  cpu.PInfo(upgraded_cpv='bcd/efg-8', upgraded_unmasked=False),
2190                 ]
2191     masked_cpvs = ['abc/def-4', 'bcd/efg-8']
2192     self._TestGiveEmergeResultsMasked(pinfolist, False, masked_cpvs,
2193                                       error=RuntimeError)
2194
2195
2196 class CheckStagedUpgradesTest(CpuTestBase):
2197   """Test Upgrader._CheckStagedUpgrades"""
2198
2199   def testCheckStagedUpgradesTwoStaged(self):
2200     cmdargs = []
2201
2202     ebuild1 = 'a/b/foo/bar/bar-1.ebuild'
2203     ebuild2 = 'x/y/bar/foo/foo-3.ebuild'
2204     repo_status = {ebuild1: 'A',
2205                    'a/b/foo/garbage': 'A',
2206                    ebuild2: 'A',
2207                    }
2208
2209     pinfolist = [cpu.PInfo(package='foo/bar'),
2210                  cpu.PInfo(package='bar/foo'),
2211                 ]
2212
2213     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2214                                          _stable_repo_status=repo_status)
2215
2216     # Add test-specific mocks/stubs
2217
2218     # Replay script
2219     for ebuild in [ebuild1, ebuild2]:
2220       split = cpu.Upgrader._SplitEBuildPath(mocked_upgrader, ebuild)
2221       mocked_upgrader._SplitEBuildPath(ebuild).InAnyOrder().AndReturn(split)
2222
2223     self.mox.ReplayAll()
2224
2225     # Verify
2226     cpu.Upgrader._CheckStagedUpgrades(mocked_upgrader, pinfolist)
2227     self.mox.VerifyAll()
2228
2229   def testCheckStagedUpgradesTwoStagedOneUnexpected(self):
2230     cmdargs = []
2231
2232     ebuild1 = 'a/b/foo/bar/bar-1.ebuild'
2233     ebuild2 = 'x/y/bar/foo/foo-3.ebuild'
2234     repo_status = {ebuild1: 'A',
2235                    'a/b/foo/garbage': 'A',
2236                    ebuild2: 'A',
2237                    }
2238
2239     # Without foo/bar in the pinfolist it should complain about that
2240     # package having staged changes.
2241     pinfolist = [cpu.PInfo(package='bar/foo')]
2242
2243     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2244                                          _stable_repo_status=repo_status)
2245
2246     # Add test-specific mocks/stubs
2247
2248     # Replay script
2249     for ebuild in [ebuild1, ebuild2]:
2250       split = cpu.Upgrader._SplitEBuildPath(mocked_upgrader, ebuild)
2251       mocked_upgrader._SplitEBuildPath(ebuild).InAnyOrder().AndReturn(split)
2252
2253     self.mox.ReplayAll()
2254
2255     # Verify
2256     self.assertRaises(RuntimeError, cpu.Upgrader._CheckStagedUpgrades,
2257                       mocked_upgrader, pinfolist)
2258     self.mox.VerifyAll()
2259
2260   def testCheckStagedUpgradesNoneStaged(self):
2261     cmdargs = []
2262
2263     pinfolist = [cpu.PInfo(package='foo/bar-1'),
2264                  cpu.PInfo(package='bar/foo-3'),
2265                 ]
2266
2267     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2268                                          _stable_repo_status=None)
2269
2270     # Add test-specific mocks/stubs
2271
2272     # Replay script
2273     self.mox.ReplayAll()
2274
2275     # Verify
2276     cpu.Upgrader._CheckStagedUpgrades(mocked_upgrader, pinfolist)
2277     self.mox.VerifyAll()
2278
2279
2280 class UpgradePackagesTest(CpuTestBase):
2281   """Test Upgrader._UpgradePackages"""
2282
2283   def _TestUpgradePackages(self, pinfolist, upgrade):
2284     cmdargs = []
2285     if upgrade:
2286       cmdargs.append('--upgrade')
2287     table = utable.UpgradeTable('some-arch')
2288     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2289                                          _curr_table=table)
2290
2291     # Add test-specific mocks/stubs
2292
2293     # Replay script
2294     upgrades_this_run = False
2295     for pinfo in pinfolist:
2296       pkg_result = bool(pinfo.upgraded_cpv)
2297       mocked_upgrader._UpgradePackage(pinfo).InAnyOrder('up'
2298                                                         ).AndReturn(pkg_result)
2299       if pkg_result:
2300         upgrades_this_run = True
2301
2302     for pinfo in pinfolist:
2303       if pinfo.upgraded_cpv:
2304         mocked_upgrader._VerifyPackageUpgrade(pinfo).InAnyOrder('ver')
2305       mocked_upgrader._PackageReport(pinfo).InAnyOrder('ver')
2306
2307     if upgrades_this_run:
2308       mocked_upgrader._GiveEmergeResults(pinfolist)
2309
2310     upgrade_mode = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
2311     mocked_upgrader._IsInUpgradeMode().AndReturn(upgrade_mode)
2312     if upgrade_mode:
2313       mocked_upgrader._CheckStagedUpgrades(pinfolist)
2314     self.mox.ReplayAll()
2315
2316     # Verify
2317     cpu.Upgrader._UpgradePackages(mocked_upgrader, pinfolist)
2318     self.mox.VerifyAll()
2319
2320   def testUpgradePackagesUpgradeModeWithUpgrades(self):
2321     pinfolist = [cpu.PInfo(upgraded_cpv='abc/def-4'),
2322                  cpu.PInfo(upgraded_cpv='bcd/efg-8'),
2323                  cpu.PInfo(upgraded_cpv=None),
2324                  cpu.PInfo(upgraded_cpv=None)
2325                  ]
2326     self._TestUpgradePackages(pinfolist, True)
2327
2328   def testUpgradePackagesUpgradeModeNoUpgrades(self):
2329     pinfolist = [cpu.PInfo(upgraded_cpv=None),
2330                  cpu.PInfo(upgraded_cpv=None),
2331                  ]
2332     self._TestUpgradePackages(pinfolist, True)
2333
2334   def testUpgradePackagesStatusModeNoUpgrades(self):
2335     pinfolist = [cpu.PInfo(upgraded_cpv=None),
2336                  cpu.PInfo(upgraded_cpv=None),
2337                  ]
2338     self._TestUpgradePackages(pinfolist, False)
2339
2340
2341 class CategoriesRoundtripTest(cros_test_lib.MoxOutputTestCase):
2342   """Tests for full "round trip" runs."""
2343
2344   @osutils.TempDirDecorator
2345   def _TestCategoriesRoundtrip(self, categories):
2346     stable_repo = self.tempdir
2347     cat_file = cpu.Upgrader.CATEGORIES_FILE
2348     profiles_dir = os.path.join(stable_repo, os.path.dirname(cat_file))
2349
2350     self.mox.StubOutWithMock(cpu.Upgrader, '_RunGit')
2351
2352     # Prepare replay script.
2353     cpu.Upgrader._RunGit(stable_repo, ['add', cat_file])
2354     self.mox.ReplayAll()
2355
2356     options = cros_test_lib.EasyAttr(srcroot='foobar', upstream=None,
2357                                      packages='')
2358     upgrader = cpu.Upgrader(options=options)
2359     upgrader._stable_repo = stable_repo
2360     os.makedirs(profiles_dir)
2361
2362     # Verification phase.  Write then load categories.
2363     upgrader._stable_repo_categories = set(categories)
2364     upgrader._WriteStableRepoCategories()
2365     upgrader._stable_repo_categories = None
2366     upgrader._LoadStableRepoCategories()
2367     self.mox.VerifyAll()
2368     self.assertEquals(sorted(categories),
2369                       sorted(upgrader._stable_repo_categories))
2370
2371   def test1(self):
2372     categories = ['alpha-omega', 'omega-beta', 'beta-chi']
2373     self._TestCategoriesRoundtrip(categories)
2374
2375   def test2(self):
2376     categories = []
2377     self._TestCategoriesRoundtrip(categories)
2378
2379   def test3(self):
2380     categories = ['virtual', 'happy-days', 'virtually-there']
2381     self._TestCategoriesRoundtrip(categories)
2382
2383
2384 class UpgradePackageTest(CpuTestBase):
2385   """Test Upgrader._UpgradePackage"""
2386
2387   def _TestUpgradePackage(self, pinfo, upstream_cpv, upstream_cmp,
2388                           stable_up, latest_up,
2389                           upgrade_requested, upgrade_staged,
2390                           unstable_ok, force):
2391     cmdargs = []
2392     if unstable_ok:
2393       cmdargs.append('--unstable-ok')
2394     if force:
2395       cmdargs.append('--force')
2396     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
2397
2398     # Add test-specific mocks/stubs
2399     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
2400
2401     # Replay script
2402     mocked_upgrader._FindUpstreamCPV(pinfo.package).AndReturn(stable_up)
2403     mocked_upgrader._FindUpstreamCPV(pinfo.package,
2404                                      unstable_ok=True).AndReturn(latest_up)
2405     if upstream_cpv:
2406       mocked_upgrader._PkgUpgradeRequested(pinfo).AndReturn(upgrade_requested)
2407       if upgrade_requested:
2408         mocked_upgrader._PkgUpgradeStaged(upstream_cpv
2409                                           ).AndReturn(upgrade_staged)
2410         if (not upgrade_staged and
2411             (upstream_cmp > 0 or (upstream_cmp == 0 and force))):
2412           mocked_upgrader._CopyUpstreamPackage(upstream_cpv
2413                                                ).AndReturn(upstream_cpv)
2414           upgrade_staged = True
2415
2416
2417         if upgrade_staged:
2418           mocked_upgrader._SetUpgradedMaskBits(pinfo)
2419           ebuild_path = cpu.Upgrader._GetEbuildPathFromCpv(upstream_cpv)
2420           ebuild_path = os.path.join(mocked_upgrader._stable_repo,
2421                                      ebuild_path)
2422           mocked_upgrader._StabilizeEbuild(ebuild_path)
2423           mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
2424                                   ['add', pinfo.package])
2425           mocked_upgrader._UpdateCategories(pinfo)
2426           cache_files = 'metadata/md5-cache/%s-[0-9]*' % pinfo.package
2427           mocked_upgrader._RunGit(mocked_upgrader._stable_repo, ['rm',
2428                                   '--ignore-unmatch', '-q', '-f', cache_files])
2429           cmd = ['egencache', '--update', '--repo=portage-stable',
2430                  pinfo.package]
2431           run_result = RunCommandResult(returncode=0, output=None)
2432           cros_build_lib.RunCommand(cmd, print_cmd=False,
2433                                     redirect_stdout=True,
2434                                     combine_stdout_stderr=True).AndReturn(
2435                                         run_result)
2436           mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
2437                                   ['add', cache_files])
2438     self.mox.ReplayAll()
2439
2440     # Verify
2441     with self.OutputCapturer():
2442       result = cpu.Upgrader._UpgradePackage(mocked_upgrader, pinfo)
2443     self.mox.VerifyAll()
2444
2445     if upstream_cpv:
2446       self.assertEquals(upstream_cpv, pinfo.upstream_cpv)
2447
2448       if upgrade_requested and (upstream_cpv != pinfo.cpv or force):
2449         self.assertEquals(upstream_cpv, pinfo.upgraded_cpv)
2450       else:
2451         self.assertTrue(pinfo.upgraded_cpv is None)
2452     else:
2453       self.assertTrue(pinfo.upstream_cpv is None)
2454       self.assertTrue(pinfo.upgraded_cpv is None)
2455     self.assertEquals(stable_up, pinfo.stable_upstream_cpv)
2456     self.assertEquals(latest_up, pinfo.latest_upstream_cpv)
2457
2458     return result
2459
2460   # Dimensions to vary:
2461   # 1) Upgrade for this package requested or not
2462   # 2) Upgrade can be stable or not
2463   # 3) Specific version to upgrade to specified
2464   # 4) Upgrade already staged or not
2465   # 5) Upgrade needed or not (current)
2466
2467   def testUpgradePackageOutdatedRequestedStable(self):
2468     pinfo = cpu.PInfo(cpv='foo/bar-2',
2469                       package='foo/bar',
2470                       upstream_cpv=None,
2471                       )
2472     result = self._TestUpgradePackage(pinfo,
2473                                       upstream_cpv='foo/bar-3',
2474                                       upstream_cmp=1, # outdated
2475                                       stable_up='foo/bar-3',
2476                                       latest_up='foo/bar-5',
2477                                       upgrade_requested=True,
2478                                       upgrade_staged=False,
2479                                       unstable_ok=False,
2480                                       force=False,
2481                                       )
2482     self.assertTrue(result)
2483
2484   def testUpgradePackageOutdatedRequestedUnstable(self):
2485     pinfo = cpu.PInfo(cpv='foo/bar-2',
2486                       package='foo/bar',
2487                       upstream_cpv=None,
2488                       )
2489     result = self._TestUpgradePackage(pinfo,
2490                                       upstream_cpv='foo/bar-5',
2491                                       upstream_cmp=1, # outdated
2492                                       stable_up='foo/bar-3',
2493                                       latest_up='foo/bar-5',
2494                                       upgrade_requested=True,
2495                                       upgrade_staged=False,
2496                                       unstable_ok=True,
2497                                       force=False,
2498                                       )
2499     self.assertTrue(result)
2500
2501   def testUpgradePackageOutdatedRequestedStableSpecified(self):
2502     pinfo = cpu.PInfo(cpv='foo/bar-2',
2503                       package='foo/bar',
2504                       upstream_cpv='foo/bar-4',
2505                       )
2506     result = self._TestUpgradePackage(pinfo,
2507                                       upstream_cpv='foo/bar-4',
2508                                       upstream_cmp=1, # outdated
2509                                       stable_up='foo/bar-3',
2510                                       latest_up='foo/bar-5',
2511                                       upgrade_requested=True,
2512                                       upgrade_staged=False,
2513                                       unstable_ok=False, # not important
2514                                       force=False,
2515                                       )
2516     self.assertTrue(result)
2517
2518   def testUpgradePackageCurrentRequestedStable(self):
2519     pinfo = cpu.PInfo(cpv='foo/bar-3',
2520                       package='foo/bar',
2521                       upstream_cpv=None,
2522                       )
2523     result = self._TestUpgradePackage(pinfo,
2524                                       upstream_cpv='foo/bar-3',
2525                                       upstream_cmp=0, # current
2526                                       stable_up='foo/bar-3',
2527                                       latest_up='foo/bar-5',
2528                                       upgrade_requested=True,
2529                                       upgrade_staged=False,
2530                                       unstable_ok=False,
2531                                       force=False,
2532                                       )
2533     self.assertFalse(result)
2534
2535   def testUpgradePackageCurrentRequestedStableForce(self):
2536     pinfo = cpu.PInfo(cpv='foo/bar-3',
2537                       package='foo/bar',
2538                       upstream_cpv='foo/bar-3',
2539                       )
2540     result = self._TestUpgradePackage(pinfo,
2541                                       upstream_cpv='foo/bar-3',
2542                                       upstream_cmp=0, # current
2543                                       stable_up='foo/bar-3',
2544                                       latest_up='foo/bar-5',
2545                                       upgrade_requested=True,
2546                                       upgrade_staged=False,
2547                                       unstable_ok=False,
2548                                       force=True,
2549                                       )
2550     self.assertTrue(result)
2551
2552   def testUpgradePackageOutdatedStable(self):
2553     pinfo = cpu.PInfo(cpv='foo/bar-2',
2554                       package='foo/bar',
2555                       upstream_cpv=None,
2556                       )
2557     result = self._TestUpgradePackage(pinfo,
2558                                       upstream_cpv='foo/bar-3',
2559                                       upstream_cmp=1, # outdated
2560                                       stable_up='foo/bar-3',
2561                                       latest_up='foo/bar-5',
2562                                       upgrade_requested=False,
2563                                       upgrade_staged=False,
2564                                       unstable_ok=False,
2565                                       force=False,
2566                                       )
2567     self.assertFalse(result)
2568
2569   def testUpgradePackageOutdatedRequestedStableStaged(self):
2570     pinfo = cpu.PInfo(cpv='foo/bar-2',
2571                       package='foo/bar',
2572                       upstream_cpv=None,
2573                       )
2574     result = self._TestUpgradePackage(pinfo,
2575                                       upstream_cpv='foo/bar-3',
2576                                       upstream_cmp=1, # outdated
2577                                       stable_up='foo/bar-3',
2578                                       latest_up='foo/bar-5',
2579                                       upgrade_requested=True,
2580                                       upgrade_staged=True,
2581                                       unstable_ok=False,
2582                                       force=False,
2583                                       )
2584     self.assertTrue(result)
2585
2586   def testUpgradePackageOutdatedRequestedUnstableStaged(self):
2587     pinfo = cpu.PInfo(cpv='foo/bar-2',
2588                       package='foo/bar',
2589                       upstream_cpv='foo/bar-5',
2590                       )
2591     result = self._TestUpgradePackage(pinfo,
2592                                       upstream_cpv='foo/bar-5',
2593                                       upstream_cmp=1, # outdated
2594                                       stable_up='foo/bar-3',
2595                                       latest_up='foo/bar-5',
2596                                       upgrade_requested=True,
2597                                       upgrade_staged=True,
2598                                       unstable_ok=True,
2599                                       force=False,
2600                                       )
2601     self.assertTrue(result)
2602
2603
2604 class VerifyPackageTest(CpuTestBase):
2605   """Tests for _VerifyPackageUpgrade()."""
2606
2607   def _TestVerifyPackageUpgrade(self, pinfo):
2608     cmdargs = []
2609     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
2610     was_overwrite = pinfo.cpv_cmp_upstream == 0
2611
2612     # Add test-specific mocks/stubs
2613
2614     # Replay script
2615     mocked_upgrader._VerifyEbuildOverlay(pinfo.upgraded_cpv,
2616                                          'portage-stable',
2617                                          was_overwrite)
2618     self.mox.ReplayAll()
2619
2620     # Verify
2621     cpu.Upgrader._VerifyPackageUpgrade(mocked_upgrader, pinfo)
2622     self.mox.VerifyAll()
2623
2624   def testVerifyPackageUpgrade(self):
2625     pinfo = cpu.PInfo(upgraded_cpv='foo/bar-3')
2626
2627     for cpv_cmp_upstream in (0, 1):
2628       pinfo.cpv_cmp_upstream = cpv_cmp_upstream
2629       self._TestVerifyPackageUpgrade(pinfo)
2630
2631   def _TestVerifyEbuildOverlay(self, cpv, overlay, ebuild_path, was_overwrite):
2632     """Test Upgrader._VerifyEbuildOverlay"""
2633     cmdargs = []
2634     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2635                                          _curr_arch=DEFAULT_ARCH,
2636                                          )
2637
2638     # Add test-specific mocks/stubs
2639     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
2640
2641     # Replay script
2642     envvars = cpu.Upgrader._GenPortageEnvvars(mocked_upgrader,
2643                                               mocked_upgrader._curr_arch,
2644                                               unstable_ok=False)
2645     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
2646                                        unstable_ok=False).AndReturn(envvars)
2647     mocked_upgrader._GetBoardCmd('equery').AndReturn('equery')
2648     run_result = RunCommandResult(returncode=0,
2649                                   output=ebuild_path)
2650     cros_build_lib.RunCommand(['equery', '-C', 'which', '--include-masked',
2651                                cpv], error_code_ok=True,
2652                               extra_env=envvars, print_cmd=False,
2653                               redirect_stdout=True, combine_stdout_stderr=True,
2654                               ).AndReturn(run_result)
2655     split_ebuild = cpu.Upgrader._SplitEBuildPath(mocked_upgrader, ebuild_path)
2656     mocked_upgrader._SplitEBuildPath(ebuild_path).AndReturn(split_ebuild)
2657     self.mox.ReplayAll()
2658
2659     # Verify
2660     cpu.Upgrader._VerifyEbuildOverlay(mocked_upgrader, cpv,
2661                                       overlay, was_overwrite)
2662     self.mox.VerifyAll()
2663
2664   def testVerifyEbuildOverlayGood(self):
2665     cpv = 'foo/bar-2'
2666     overlay = 'some-overlay'
2667     good_path = '/some/path/%s/foo/bar/bar-2.ebuild' % overlay
2668
2669     self._TestVerifyEbuildOverlay(cpv, overlay, good_path, False)
2670
2671   def testVerifyEbuildOverlayEvilNonOverwrite(self):
2672     cpv = 'foo/bar-2'
2673     overlay = 'some-overlay'
2674     evil_path = '/some/path/spam/foo/bar/bar-2.ebuild'
2675
2676     self.assertRaises(RuntimeError,
2677                       self._TestVerifyEbuildOverlay,
2678                       cpv, overlay, evil_path, False)
2679
2680   def testVerifyEbuildOverlayEvilOverwrite(self):
2681     cpv = 'foo/bar-2'
2682     overlay = 'some-overlay'
2683     evil_path = '/some/path/spam/foo/bar/bar-2.ebuild'
2684
2685     self.assertRaises(RuntimeError,
2686                       self._TestVerifyEbuildOverlay,
2687                       cpv, overlay, evil_path, True)
2688
2689   def _TestSetUpgradedMaskBits(self, pinfo, output):
2690     cpv = pinfo.upgraded_cpv
2691     cmdargs = []
2692     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2693                                          _curr_arch=DEFAULT_ARCH,
2694                                          )
2695
2696     # Add test-specific mocks/stubs
2697     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
2698
2699     # Replay script
2700     mocked_upgrader._GenPortageEnvvars(mocked_upgrader._curr_arch,
2701                                        unstable_ok=False).AndReturn('envvars')
2702     mocked_upgrader._GetBoardCmd('equery').AndReturn('equery')
2703     run_result = RunCommandResult(returncode=0,
2704                                   output=output)
2705     cros_build_lib.RunCommand(['equery', '-qCN', 'list', '-F',
2706                                '$mask|$cpv:$slot', '-op', cpv],
2707                               error_code_ok=True,
2708                               extra_env='envvars', print_cmd=False,
2709                               redirect_stdout=True, combine_stdout_stderr=True,
2710                               ).AndReturn(run_result)
2711     self.mox.ReplayAll()
2712
2713     # Verify
2714     cpu.Upgrader._SetUpgradedMaskBits(mocked_upgrader, pinfo)
2715     self.mox.VerifyAll()
2716
2717   def testGetMaskBitsUnmaskedStable(self):
2718     output = '  |foo/bar-2.7.0:0'
2719     pinfo = cpu.PInfo(upgraded_cpv='foo/bar-2.7.0')
2720     self._TestSetUpgradedMaskBits(pinfo, output)
2721     self.assertTrue(pinfo.upgraded_unmasked)
2722
2723   def testGetMaskBitsUnmaskedUnstable(self):
2724     output = ' ~|foo/bar-2.7.3:0'
2725     pinfo = cpu.PInfo(upgraded_cpv='foo/bar-2.7.3')
2726     self._TestSetUpgradedMaskBits(pinfo, output)
2727     self.assertTrue(pinfo.upgraded_unmasked)
2728
2729   def testGetMaskBitsMaskedStable(self):
2730     output = 'M |foo/bar-2.7.4:0'
2731     pinfo = cpu.PInfo(upgraded_cpv='foo/bar-2.7.4')
2732     self._TestSetUpgradedMaskBits(pinfo, output)
2733     self.assertFalse(pinfo.upgraded_unmasked)
2734
2735   def testGetMaskBitsMaskedUnstable(self):
2736     output = 'M~|foo/bar-2.7.4-r1:0'
2737     pinfo = cpu.PInfo(upgraded_cpv='foo/bar-2.7.4-r1')
2738     self._TestSetUpgradedMaskBits(pinfo, output)
2739     self.assertFalse(pinfo.upgraded_unmasked)
2740
2741
2742 class CommitTest(CpuTestBase):
2743   """Test various commit-related Upgrader methods"""
2744
2745   #
2746   # _ExtractUpgradedPkgs
2747   #
2748
2749   def _TestExtractUpgradedPkgs(self, upgrade_lines):
2750     """Test Upgrader._ExtractUpgradedPkgs"""
2751     mocked_upgrader = self._MockUpgrader()
2752
2753     # Replay script
2754     self.mox.ReplayAll()
2755
2756     # Verify
2757     with self.OutputCapturer():
2758       result = cpu.Upgrader._ExtractUpgradedPkgs(mocked_upgrader, upgrade_lines)
2759     self.mox.VerifyAll()
2760
2761     return result
2762
2763   def testExtractUpgradedPkgs(self):
2764     upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2765                      'Upgraded xyz/uvw to version 1.2.3 on amd64',
2766                      'Upgraded xyz/uvw to version 3.2.1 on arm, x86',
2767                      'Upgraded mno/pqr to version 12345 on x86',
2768                      ]
2769     result = self._TestExtractUpgradedPkgs(upgrade_lines)
2770     self.assertEquals(result, ['efg', 'pqr', 'uvw'])
2771
2772   #
2773   # _AmendCommitMessage
2774   #
2775
2776   def _TestAmendCommitMessage(self, new_upgrade_lines,
2777                               old_upgrade_lines, remaining_lines,
2778                               git_show):
2779     """Test Upgrader._AmendCommitMessage"""
2780     mocked_upgrader = self._MockUpgrader()
2781
2782     gold_lines = new_upgrade_lines + old_upgrade_lines
2783     def all_lines_verifier(lines):
2784       return gold_lines == lines
2785
2786     # Add test-specific mocks/stubs
2787
2788     # Replay script
2789     git_result = RunCommandResult(returncode=0,
2790                                   output=git_show)
2791     mocked_upgrader._RunGit(mocked_upgrader._stable_repo,
2792                             mox.IgnoreArg(), redirect_stdout=True,
2793                             ).AndReturn(git_result)
2794     mocked_upgrader._CreateCommitMessage(mox.Func(all_lines_verifier),
2795                                          remaining_lines)
2796     self.mox.ReplayAll()
2797
2798     # Verify
2799     with self.OutputCapturer():
2800       cpu.Upgrader._AmendCommitMessage(mocked_upgrader,
2801                                        new_upgrade_lines)
2802     self.mox.VerifyAll()
2803
2804   def testOldAndNew(self):
2805     new_upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2806                          'Upgraded mno/pqr to version 4.5-r1 on x86',
2807                          ]
2808     old_upgrade_lines = ['Upgraded xyz/uvw to version 3.2.1 on arm, x86',
2809                          'Upgraded mno/pqr to version 12345 on x86',
2810                          ]
2811     remaining_lines = ['Extraneous extra comments in commit body.',
2812                        '',
2813                        'BUG=chromium-os:12345',
2814                        'TEST=test everything',
2815                        'again and again',
2816                        ]
2817     git_show_output = ('\n'.join(old_upgrade_lines) + '\n'
2818                        + '\n'
2819                        + '\n'.join(remaining_lines))
2820     self._TestAmendCommitMessage(new_upgrade_lines, old_upgrade_lines,
2821                                  remaining_lines, git_show_output)
2822
2823   def testOldOnly(self):
2824     old_upgrade_lines = ['Upgraded xyz/uvw to version 3.2.1 on arm, x86',
2825                          'Upgraded mno/pqr to version 12345 on x86',
2826                          ]
2827     git_show_output = ('\n'.join(old_upgrade_lines))
2828     self._TestAmendCommitMessage([], old_upgrade_lines, [], git_show_output)
2829
2830   def testNewOnly(self):
2831     new_upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2832                          'Upgraded mno/pqr to version 4.5-r1 on x86',
2833                          ]
2834     git_show_output = ''
2835     self._TestAmendCommitMessage(new_upgrade_lines, [], [], git_show_output)
2836
2837   def testOldEditedAndNew(self):
2838     new_upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2839                          'Upgraded mno/pqr to version 4.5-r1 on x86',
2840                          ]
2841     old_upgrade_lines = ['So I upgraded xyz/uvw to version 3.2.1 on arm, x86',
2842                          'Then I Upgraded mno/pqr to version 12345 on x86',
2843                          ]
2844     remaining_lines = ['Extraneous extra comments in commit body.',
2845                        '',
2846                        'BUG=chromium-os:12345',
2847                        'TEST=test everything',
2848                        'again and again',
2849                        ]
2850     git_show_output = ('\n'.join(old_upgrade_lines) + '\n'
2851                        + '\n'
2852                        + '\n'.join(remaining_lines))
2853
2854     # In this test, it should not recognize the existing old_upgrade_lines
2855     # as a previous commit message from this script.  So it should give a
2856     # warning and push those lines to the end (grouped with remaining_lines).
2857     remaining_lines = old_upgrade_lines + [''] + remaining_lines
2858     self._TestAmendCommitMessage(new_upgrade_lines, [],
2859                                  remaining_lines, git_show_output)
2860
2861   #
2862   # _CreateCommitMessage
2863   #
2864
2865   def _TestCreateCommitMessage(self, upgrade_lines):
2866     """Test Upgrader._CreateCommitMessage"""
2867     mocked_upgrader = self._MockUpgrader()
2868
2869     # Add test-specific mocks/stubs
2870
2871     # Replay script
2872     upgrade_pkgs = cpu.Upgrader._ExtractUpgradedPkgs(mocked_upgrader,
2873                                                      upgrade_lines)
2874     mocked_upgrader._ExtractUpgradedPkgs(upgrade_lines).AndReturn(upgrade_pkgs)
2875     self.mox.ReplayAll()
2876
2877     # Verify
2878     with self.OutputCapturer():
2879       result = cpu.Upgrader._CreateCommitMessage(mocked_upgrader, upgrade_lines)
2880     self.mox.VerifyAll()
2881
2882     self.assertTrue(': upgraded package' in result or
2883                     'Upgraded the following' in result)
2884     return result
2885
2886   def testCreateCommitMessageOnePkg(self):
2887     upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2888                      ]
2889     result = self._TestCreateCommitMessage(upgrade_lines)
2890
2891     # Commit message should have:
2892     # -- Summary that mentions 'efg' and ends in "package" (singular)
2893     # -- Body corresponding to upgrade_lines
2894     # -- BUG= line (with space after '=' to invalidate it)
2895     # -- TEST= line (with space after '=' to invalidate it)
2896     body = r'\n'.join([re.sub(r'\s+', r'\s', line) for line in upgrade_lines])
2897     regexp = re.compile(r'''^efg:\supgraded\spackage\sto\supstream\n # Summary
2898                             ^\s*\n                            # Blank line
2899                             %s\n                              # Body
2900                             ^\s*\n                            # Blank line
2901                             ^BUG=\s.+\n                       # BUG line
2902                             ^TEST=\s                          # TEST line
2903                             ''' % body,
2904                         re.VERBOSE | re.MULTILINE)
2905     self.assertTrue(regexp.search(result))
2906
2907   def testCreateCommitMessageThreePkgs(self):
2908     upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2909                      'Upgraded xyz/uvw to version 1.2.3 on amd64',
2910                      'Upgraded xyz/uvw to version 3.2.1 on arm, x86',
2911                      'Upgraded mno/pqr to version 12345 on x86',
2912                      ]
2913     result = self._TestCreateCommitMessage(upgrade_lines)
2914
2915     # Commit message should have:
2916     # -- Summary that mentions 'efg, pqr, uvw' and ends in "packages" (plural)
2917     # -- Body corresponding to upgrade_lines
2918     # -- BUG= line (with space after '=' to invalidate it)
2919     # -- TEST= line (with space after '=' to invalidate it)
2920     body = r'\n'.join([re.sub(r'\s+', r'\s', line) for line in upgrade_lines])
2921     regexp = re.compile(r'''^efg,\spqr,\suvw:\supgraded\spackages.*\n # Summary
2922                             ^\s*\n                            # Blank line
2923                             %s\n                              # Body
2924                             ^\s*\n                            # Blank line
2925                             ^BUG=\s.+\n                       # BUG line
2926                             ^TEST=\s                          # TEST line
2927                             ''' % body,
2928                         re.VERBOSE | re.MULTILINE)
2929     self.assertTrue(regexp.search(result))
2930
2931   def testCreateCommitMessageTenPkgs(self):
2932     upgrade_lines = ['Upgraded abc/efg to version 1.2.3 on amd64, arm, x86',
2933                      'Upgraded bcd/fgh to version 1.2.3 on amd64',
2934                      'Upgraded cde/ghi to version 3.2.1 on arm, x86',
2935                      'Upgraded def/hij to version 12345 on x86',
2936                      'Upgraded efg/ijk to version 1.2.3 on amd64',
2937                      'Upgraded fgh/jkl to version 3.2.1 on arm, x86',
2938                      'Upgraded ghi/klm to version 12345 on x86',
2939                      'Upgraded hij/lmn to version 1.2.3 on amd64',
2940                      'Upgraded ijk/mno to version 3.2.1 on arm, x86',
2941                      'Upgraded jkl/nop to version 12345 on x86',
2942                      ]
2943     result = self._TestCreateCommitMessage(upgrade_lines)
2944
2945     # Commit message should have:
2946     # -- Summary that mentions '10' and ends in "packages" (plural)
2947     # -- Body corresponding to upgrade_lines
2948     # -- BUG= line (with space after '=' to invalidate it)
2949     # -- TEST= line (with space after '=' to invalidate it)
2950     body = r'\n'.join([re.sub(r'\s+', r'\s', line) for line in upgrade_lines])
2951     regexp = re.compile(r'''^Upgraded\s.*10.*\spackages\n     # Summary
2952                             ^\s*\n                            # Blank line
2953                             %s\n                              # Body
2954                             ^\s*\n                            # Blank line
2955                             ^BUG=\s.+\n                       # BUG line
2956                             ^TEST=\s                          # TEST line
2957                             ''' % body,
2958                         re.VERBOSE | re.MULTILINE)
2959     self.assertTrue(regexp.search(result))
2960
2961
2962 @unittest.skip('relies on portage module not currently available')
2963 class GetCurrentVersionsTest(CpuTestBase):
2964   """Test Upgrader._GetCurrentVersions"""
2965
2966   def _TestGetCurrentVersionsLocalCpv(self, target_pinfolist):
2967     cmdargs = []
2968     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
2969                                          _curr_board=None)
2970     self._SetUpPlayground()
2971
2972     # Add test-specific mocks/stubs
2973     self.mox.StubOutWithMock(cpu.Upgrader, '_GetPreOrderDepGraph')
2974
2975     # Replay script
2976     packages = [pinfo.package for pinfo in target_pinfolist]
2977     targets = ['=' + pinfo.cpv for pinfo in target_pinfolist]
2978     pm_argv = cpu.Upgrader._GenParallelEmergeArgv(mocked_upgrader, targets)
2979     pm_argv.append('--root-deps')
2980     verifier = _GenDepsGraphVerifier(packages)
2981     mocked_upgrader._GenParallelEmergeArgv(targets).AndReturn(pm_argv)
2982     mocked_upgrader._SetPortTree(mox.IsA(portcfg.config), mox.IsA(dict))
2983     cpu.Upgrader._GetPreOrderDepGraph(mox.Func(verifier)).AndReturn([])
2984     self.mox.ReplayAll()
2985
2986     # Verify
2987     result = cpu.Upgrader._GetCurrentVersions(mocked_upgrader, target_pinfolist)
2988     self.mox.VerifyAll()
2989
2990     return result
2991
2992   def testGetCurrentVersionsTwoPkgs(self):
2993     target_pinfolist = [cpu.PInfo(package='dev-libs/A', cpv='dev-libs/A-2'),
2994                         cpu.PInfo(package='dev-libs/D', cpv='dev-libs/D-3'),
2995                         ]
2996     self._TestGetCurrentVersionsLocalCpv(target_pinfolist)
2997
2998   def testGetCurrentVersionsOnePkgB(self):
2999     target_pinfolist = [cpu.PInfo(package='dev-libs/B', cpv='dev-libs/B-2'),
3000                         ]
3001     self._TestGetCurrentVersionsLocalCpv(target_pinfolist)
3002
3003   def testGetCurrentVersionsOnePkgLibcros(self):
3004     target_pinfolist = [cpu.PInfo(package='chromeos-base/libcros',
3005                                   cpv='chromeos-base/libcros-1',
3006                                   ),
3007                         ]
3008     self._TestGetCurrentVersionsLocalCpv(target_pinfolist)
3009
3010   def _TestGetCurrentVersionsPackageOnly(self, target_pinfolist):
3011     cmdargs = []
3012     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
3013                                          _curr_board=None)
3014     self._SetUpPlayground()
3015
3016     # Add test-specific mocks/stubs
3017     self.mox.StubOutWithMock(cpu.Upgrader, '_GetPreOrderDepGraph')
3018
3019     # Replay script
3020     packages = [pinfo.package for pinfo in target_pinfolist]
3021     pm_argv = cpu.Upgrader._GenParallelEmergeArgv(mocked_upgrader, packages)
3022     pm_argv.append('--root-deps')
3023     mocked_upgrader._GenParallelEmergeArgv(packages).AndReturn(pm_argv)
3024     mocked_upgrader._SetPortTree(mox.IsA(portcfg.config), mox.IsA(dict))
3025     cpu.Upgrader._GetPreOrderDepGraph(mox.IgnoreArg()).AndReturn([])
3026     self.mox.ReplayAll()
3027
3028     # Verify
3029     result = cpu.Upgrader._GetCurrentVersions(mocked_upgrader, target_pinfolist)
3030     self.mox.VerifyAll()
3031
3032     return result
3033
3034   def testGetCurrentVersionsWorld(self):
3035     target_pinfolist = [cpu.PInfo(package='world', cpv='world'),
3036                         ]
3037     self._TestGetCurrentVersionsPackageOnly(target_pinfolist)
3038
3039   def testGetCurrentVersionsLocalOnlyB(self):
3040     target_pinfolist = [cpu.PInfo(package='dev-libs/B', cpv=None),
3041                         ]
3042     self._TestGetCurrentVersionsPackageOnly(target_pinfolist)
3043
3044
3045 class ResolveAndVerifyArgsTest(CpuTestBase):
3046   """Test Upgrader._ResolveAndVerifyArgs"""
3047
3048   def _TestResolveAndVerifyArgsWorld(self, upgrade_mode):
3049     args = ['world']
3050     cmdargs = []
3051     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
3052                                          _curr_board=None)
3053
3054     # Add test-specific mocks/stubs
3055
3056     # Replay script
3057     self.mox.ReplayAll()
3058
3059     # Verify
3060     with self.OutputCapturer():
3061       result = cpu.Upgrader._ResolveAndVerifyArgs(mocked_upgrader, args,
3062                                                   upgrade_mode=upgrade_mode)
3063     self.mox.VerifyAll()
3064
3065     self.assertEquals(result, [cpu.PInfo(user_arg='world',
3066                                          package='world',
3067                                          package_name='world',
3068                                          category=None,
3069                                          cpv='world',
3070                                          )])
3071
3072   def testResolveAndVerifyArgsWorldUpgradeMode(self):
3073     self._TestResolveAndVerifyArgsWorld(True)
3074
3075   def testResolveAndVerifyArgsWorldStatusMode(self):
3076     self._TestResolveAndVerifyArgsWorld(False)
3077
3078   def _TestResolveAndVerifyArgsNonWorld(self, pinfolist, cmdargs=[],
3079                                         error=None, error_checker=None):
3080     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
3081                                          _curr_board=None)
3082     upgrade_mode = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
3083
3084     # Add test-specific mocks/stubs
3085
3086     # Replay script
3087     args = []
3088     for pinfo in pinfolist:
3089       arg = pinfo.user_arg
3090       local_cpv = pinfo.cpv
3091       upstream_cpv = pinfo.upstream_cpv
3092       args.append(arg)
3093
3094       catpkg = cpu.Upgrader._GetCatPkgFromCpv(arg)
3095       local_arg = catpkg if catpkg else arg
3096
3097       mocked_upgrader._FindCurrentCPV(local_arg).AndReturn(local_cpv)
3098       mocked_upgrader._FindUpstreamCPV(arg, mocked_upgrader._unstable_ok,
3099                                        ).AndReturn(upstream_cpv)
3100
3101       if not upstream_cpv and upgrade_mode:
3102         # Real method raises an exception here.
3103         if not mocked_upgrader._unstable_ok:
3104           mocked_upgrader._FindUpstreamCPV(arg, True).AndReturn(arg)
3105         break
3106
3107       any_cpv = local_cpv if local_cpv else upstream_cpv
3108       if any_cpv:
3109         mocked_upgrader._FillPInfoFromCPV(mox.IsA(cpu.PInfo), any_cpv)
3110
3111     self.mox.ReplayAll()
3112
3113     # Verify
3114     result = None
3115     with self.OutputCapturer():
3116       if error:
3117         exc = self.AssertRaisesAndReturn(error,
3118                                          cpu.Upgrader._ResolveAndVerifyArgs,
3119                                          mocked_upgrader, args, upgrade_mode)
3120         if error_checker:
3121           check = error_checker(exc)
3122           self.assertTrue(check[0], msg=check[1])
3123       else:
3124         result = cpu.Upgrader._ResolveAndVerifyArgs(mocked_upgrader, args,
3125                                                     upgrade_mode)
3126     self.mox.VerifyAll()
3127
3128     return result
3129
3130   def testResolveAndVerifyArgsNonWorldUpgrade(self):
3131     pinfolist = [cpu.PInfo(user_arg='dev-libs/B',
3132                            cpv='dev-libs/B-1',
3133                            upstream_cpv='dev-libs/B-2',
3134                            ),
3135                  ]
3136     cmdargs = ['--upgrade', '--unstable-ok']
3137     result = self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs)
3138     self.assertEquals(result, pinfolist)
3139
3140   def testResolveAndVerifyArgsNonWorldUpgradeSpecificVer(self):
3141     pinfolist = [cpu.PInfo(user_arg='dev-libs/B-2',
3142                            cpv='dev-libs/B-1',
3143                            upstream_cpv='dev-libs/B-2',
3144                            ),
3145                  ]
3146     cmdargs = ['--upgrade', '--unstable-ok']
3147     result = self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs)
3148     self.assertEquals(result, pinfolist)
3149
3150   def testResolveAndVerifyArgsNonWorldUpgradeSpecificVerNotFoundStable(self):
3151     pinfolist = [cpu.PInfo(user_arg='dev-libs/B-2',
3152                            cpv='dev-libs/B-1',
3153                            ),
3154                  ]
3155     cmdargs = ['--upgrade']
3156
3157     def _error_checker(exception):
3158       # RuntimeError text should mention 'is unstable'.
3159       text = str(exception)
3160       phrase = 'is unstable'
3161       msg = 'No mention of "%s" in error message: %s' % (phrase, text)
3162       return (0 <= text.find(phrase), msg)
3163
3164     self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs,
3165                                            error=RuntimeError,
3166                                            error_checker=_error_checker)
3167
3168   def testResolveAndVerifyArgsNonWorldUpgradeSpecificVerNotFoundUnstable(self):
3169     pinfolist = [cpu.PInfo(user_arg='dev-libs/B-2',
3170                            cpv='dev-libs/B-1',
3171                            ),
3172                  ]
3173     cmdargs = ['--upgrade', '--unstable-ok']
3174
3175     def _error_checker(exception):
3176       # RuntimeError text should start with 'Unable to find'.
3177       text = str(exception)
3178       phrase = 'Unable to find'
3179       msg = 'Error message expected to start with "%s": %s' % (phrase, text)
3180       return (text.startswith(phrase), msg)
3181
3182     self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs,
3183                                            error=RuntimeError,
3184                                            error_checker=_error_checker)
3185
3186   def testResolveAndVerifyArgsNonWorldLocalOny(self):
3187     pinfolist = [cpu.PInfo(user_arg='dev-libs/B',
3188                            cpv='dev-libs/B-1',
3189                            ),
3190                  ]
3191     cmdargs = ['--upgrade', '--unstable-ok']
3192
3193     def _error_checker(exception):
3194       # RuntimeError text should start with 'Unable to find'.
3195       text = str(exception)
3196       phrase = 'Unable to find'
3197       msg = 'Error message expected to start with "%s": %s' % (phrase, text)
3198       return (text.startswith(phrase), msg)
3199
3200     self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs,
3201                                            error=RuntimeError,
3202                                            error_checker=_error_checker)
3203
3204   def testResolveAndVerifyArgsNonWorldUpstreamOnly(self):
3205     pinfolist = [cpu.PInfo(user_arg='dev-libs/B',
3206                            upstream_cpv='dev-libs/B-2',
3207                            ),
3208                  ]
3209     cmdargs = ['--upgrade', '--unstable-ok']
3210     result = self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs)
3211     self.assertEquals(result, pinfolist)
3212
3213   def testResolveAndVerifyArgsNonWorldNeither(self):
3214     pinfolist = [cpu.PInfo(user_arg='dev-libs/B'),
3215                  ]
3216     cmdargs = ['--upgrade', '--unstable-ok']
3217     self._TestResolveAndVerifyArgsNonWorld(pinfolist, cmdargs,
3218                                            error=RuntimeError)
3219
3220   def testResolveAndVerifyArgsNonWorldStatusSpecificVer(self):
3221     """Exception because specific cpv arg not allowed without --ugprade."""
3222     cmdargs = ['--unstable-ok']
3223     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
3224                                          _curr_board=None)
3225     upgrade_mode = cpu.Upgrader._IsInUpgradeMode(mocked_upgrader)
3226
3227     # Add test-specific mocks/stubs
3228
3229     # Replay script
3230     self.mox.ReplayAll()
3231
3232     # Verify
3233     self.assertRaises(RuntimeError,
3234                       cpu.Upgrader._ResolveAndVerifyArgs,
3235                       mocked_upgrader,
3236                       ['dev-libs/B-2'], upgrade_mode)
3237     self.mox.VerifyAll()
3238
3239
3240 class StabilizeEbuildTest(CpuTestBase):
3241   """Tests for _StabilizeEbuild()."""
3242
3243   PREFIX_LINES = ['Garbletygook nonsense unimportant',
3244                   'Some other nonsense with KEYWORDS mention',
3245                   ]
3246   POSTFIX_LINES = ['Some mention of KEYWORDS in a line',
3247                    'And other nonsense',
3248                    ]
3249
3250   def _TestStabilizeEbuild(self, ebuild_path, arch):
3251
3252     mocked_upgrader = self._MockUpgrader(cmdargs=[],
3253                                          _curr_arch=arch)
3254
3255     # These are the steps of the replay script.
3256     self.mox.ReplayAll()
3257
3258     # This is the verification phase.
3259     with self.OutputCapturer():
3260       cpu.Upgrader._StabilizeEbuild(mocked_upgrader, ebuild_path)
3261     self.mox.VerifyAll()
3262
3263   def _AssertEqualsExcludingComments(self, lines1, lines2):
3264     lines1 = [ln for ln in lines1 if not ln.startswith('#')]
3265     lines2 = [ln for ln in lines2 if not ln.startswith('#')]
3266
3267     self.assertEquals(lines1, lines2)
3268
3269   def _TestStabilizeEbuildWrapper(self, ebuild_path, arch,
3270                                   keyword_line, gold_keyword_line):
3271     if not isinstance(keyword_line, list):
3272       keyword_line = [keyword_line]
3273     if not isinstance(gold_keyword_line, list):
3274       gold_keyword_line = [gold_keyword_line]
3275
3276     input_content = self.PREFIX_LINES + keyword_line + self.POSTFIX_LINES
3277     gold_content = self.PREFIX_LINES + gold_keyword_line + self.POSTFIX_LINES
3278
3279     # Write contents to ebuild_path before test.
3280     osutils.WriteFile(ebuild_path, '\n'.join(input_content))
3281
3282     self._TestStabilizeEbuild(ebuild_path, arch)
3283
3284     # Read content back after test.
3285     content_lines = osutils.ReadFile(ebuild_path).splitlines()
3286
3287     self._AssertEqualsExcludingComments(gold_content, content_lines)
3288
3289   @osutils.TempFileDecorator
3290   def testNothingToDo(self):
3291     arch = 'arm'
3292     keyword_line = 'KEYWORDS="amd64 arm mips x86"'
3293     gold_keyword_line = 'KEYWORDS="*"'
3294     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3295                                      keyword_line, gold_keyword_line)
3296
3297   @osutils.TempFileDecorator
3298   def testNothingToDoFbsd(self):
3299     arch = 'x86'
3300     keyword_line = 'KEYWORDS="amd64 arm ~mips x86 ~x86-fbsd"'
3301     gold_keyword_line = 'KEYWORDS="*"'
3302     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3303                                      keyword_line, gold_keyword_line)
3304
3305   @osutils.TempFileDecorator
3306   def testSimpleMiddleOfLine(self):
3307     arch = 'arm'
3308     keyword_line = 'KEYWORDS="amd64 ~arm ~mips x86"'
3309     gold_keyword_line = 'KEYWORDS="*"'
3310     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3311                                      keyword_line, gold_keyword_line)
3312
3313   @osutils.TempFileDecorator
3314   def testSimpleMiddleOfLineSpacePrefix(self):
3315     arch = 'arm'
3316     keyword_line = '    KEYWORDS="amd64 ~arm ~mips x86"'
3317     gold_keyword_line = '    KEYWORDS="*"'
3318     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3319                                      keyword_line, gold_keyword_line)
3320
3321   @osutils.TempFileDecorator
3322   def testSimpleStartOfLine(self):
3323     arch = 'arm'
3324     keyword_line = 'KEYWORDS="~arm amd64 ~mips x86"'
3325     gold_keyword_line = 'KEYWORDS="*"'
3326     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3327                                      keyword_line, gold_keyword_line)
3328
3329   @osutils.TempFileDecorator
3330   def testSimpleEndOfLine(self):
3331     arch = 'arm'
3332     keyword_line = 'KEYWORDS="amd64 ~mips x86 ~arm"'
3333     gold_keyword_line = 'KEYWORDS="*"'
3334     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3335                                      keyword_line, gold_keyword_line)
3336
3337   @osutils.TempFileDecorator
3338   def testPreFbsd(self):
3339     arch = 'x86'
3340     keyword_line = 'KEYWORDS="amd64 ~arm ~mips ~x86 ~x86-fbsd"'
3341     gold_keyword_line = 'KEYWORDS="*"'
3342     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3343                                      keyword_line, gold_keyword_line)
3344
3345   @osutils.TempFileDecorator
3346   def testPostFbsd(self):
3347     arch = 'x86'
3348     keyword_line = 'KEYWORDS="amd64 ~arm ~mips ~x86-fbsd ~x86"'
3349     gold_keyword_line = 'KEYWORDS="*"'
3350     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3351                                      keyword_line, gold_keyword_line)
3352
3353   @osutils.TempFileDecorator
3354   def testMultilineKeywordsMiddle(self):
3355     arch = 'arm'
3356     keyword_lines = ['KEYWORDS="amd64',
3357                      '  ~arm',
3358                      '  ~mips',
3359                      '  x86"',
3360                      ]
3361     gold_keyword_lines = ['KEYWORDS="*"',]
3362     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3363                                      keyword_lines, gold_keyword_lines)
3364
3365   @osutils.TempFileDecorator
3366   def testMultilineKeywordsStart(self):
3367     arch = 'amd64'
3368     keyword_lines = ['KEYWORDS="~amd64',
3369                      '  arm',
3370                      '  ~mips',
3371                      '  x86"',
3372                      ]
3373     gold_keyword_lines = ['KEYWORDS="*"',]
3374     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3375                                      keyword_lines, gold_keyword_lines)
3376
3377   @osutils.TempFileDecorator
3378   def testMultilineKeywordsEnd(self):
3379     arch = 'x86'
3380     keyword_lines = ['KEYWORDS="amd64',
3381                      '  arm',
3382                      '  ~mips',
3383                      '  ~x86"',
3384                      ]
3385     gold_keyword_lines = ['KEYWORDS="*"',]
3386     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3387                                      keyword_lines, gold_keyword_lines)
3388
3389   @osutils.TempFileDecorator
3390   def testMultipleKeywordLinesOneChange(self):
3391     arch = 'arm'
3392     keyword_lines = ['KEYWORDS="amd64 arm mips x86"',
3393                      'KEYWORDS="~amd64 ~arm ~mips ~x86"',
3394                      ]
3395     gold_keyword_lines = ['KEYWORDS="*"',] * 2
3396     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3397                                      keyword_lines, gold_keyword_lines)
3398
3399   @osutils.TempFileDecorator
3400   def testMultipleKeywordLinesMultipleChanges(self):
3401     arch = 'arm'
3402     keyword_lines = ['KEYWORDS="amd64 ~arm mips x86"',
3403                      'KEYWORDS="~amd64 ~arm ~mips ~x86"',
3404                      ]
3405     gold_keyword_lines = ['KEYWORDS="*"',] * 2
3406     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3407                                      keyword_lines, gold_keyword_lines)
3408
3409   @osutils.TempFileDecorator
3410   def testMultipleKeywordLinesMultipleChangesSpacePrefix(self):
3411     arch = 'arm'
3412     keyword_lines = ['     KEYWORDS="amd64 ~arm mips x86"',
3413                      '     KEYWORDS="~amd64 ~arm ~mips ~x86"',
3414                      ]
3415     gold_keyword_lines = ['     KEYWORDS="*"',] * 2
3416     self._TestStabilizeEbuildWrapper(self.tempfile, arch,
3417                                      keyword_lines, gold_keyword_lines)
3418
3419
3420 @unittest.skip('relies on portage module not currently available')
3421 class GetPreOrderDepGraphTest(CpuTestBase):
3422   """Test the Upgrader class from cros_portage_upgrade."""
3423
3424   #
3425   # _GetPreOrderDepGraph testing (defunct - to be replaced)
3426   #
3427
3428   def _TestGetPreOrderDepGraph(self, pkg):
3429     """Test the behavior of the Upgrader._GetPreOrderDepGraph method."""
3430
3431     cmdargs = []
3432     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs,
3433                                          _curr_board=None)
3434     self._SetUpPlayground()
3435
3436     # Replay script
3437     self.mox.ReplayAll()
3438
3439     # Verify
3440     pm_argv = cpu.Upgrader._GenParallelEmergeArgv(mocked_upgrader, [pkg])
3441     pm_argv.append('--root-deps')
3442     deps = parallel_emerge.DepGraphGenerator()
3443     deps.Initialize(pm_argv)
3444     deps_tree, deps_info = deps.GenDependencyTree()
3445     deps_graph = deps.GenDependencyGraph(deps_tree, deps_info)
3446
3447     deps_list = cpu.Upgrader._GetPreOrderDepGraph(deps_graph)
3448     golden_deps_set = _GetGoldenDepsSet(pkg)
3449     self.assertEquals(set(deps_list), golden_deps_set)
3450     self.mox.VerifyAll()
3451
3452   def testGetPreOrderDepGraphDevLibsA(self):
3453     return self._TestGetPreOrderDepGraph('dev-libs/A')
3454
3455   def testGetPreOrderDepGraphDevLibsC(self):
3456     return self._TestGetPreOrderDepGraph('dev-libs/C')
3457
3458   def testGetPreOrderDepGraphVirtualLibusb(self):
3459     return self._TestGetPreOrderDepGraph('virtual/libusb')
3460
3461   def testGetPreOrderDepGraphCrosbaseLibcros(self):
3462     return self._TestGetPreOrderDepGraph('chromeos-base/libcros')
3463
3464
3465 class MainTest(CpuTestBase):
3466   """Test argument handling at the main method level."""
3467
3468   def _AssertCPUMain(self, args, expect_zero):
3469     """Run cpu.main() and assert exit value is expected.
3470
3471     If |expect_zero| is True, assert exit value = 0.  If False,
3472     assert exit value != 0.
3473     """
3474     try:
3475       cpu.main(args)
3476     except exceptions.SystemExit as e:
3477       if expect_zero:
3478         self.assertEquals(e.args[0], 0,
3479                           msg='expected call to main() to exit cleanly, '
3480                           'but it exited with code %d' % e.args[0])
3481       else:
3482         self.assertNotEquals(e.args[0], 0,
3483                              msg='expected call to main() to exit with '
3484                              'failure code, but exited with code 0 instead.')
3485
3486   def testHelp(self):
3487     """Test that --help is functioning"""
3488
3489     with self.OutputCapturer() as output:
3490       # Running with --help should exit with code==0
3491       try:
3492         cpu.main(['--help'])
3493       except exceptions.SystemExit as e:
3494         self.assertEquals(e.args[0], 0)
3495
3496     # Verify that a message beginning with "Usage: " was printed
3497     stdout = output.GetStdout()
3498     self.assertTrue(stdout.startswith('usage: '))
3499
3500   def testMissingBoard(self):
3501     """Test that running without --board exits with an error."""
3502     with self.OutputCapturer():
3503       # Running without --board should exit with code!=0
3504       try:
3505         cpu.main([])
3506       except exceptions.SystemExit as e:
3507         self.assertNotEquals(e.args[0], 0)
3508
3509     # Verify that an error message was printed.
3510     self.AssertOutputEndsInError()
3511
3512   def testBoardWithoutPackage(self):
3513     """Test that running without a package argument exits with an error."""
3514     with self.OutputCapturer():
3515       # Running without a package should exit with code!=0
3516       self._AssertCPUMain(['--board=any-board'], expect_zero=False)
3517
3518     # Verify that an error message was printed.
3519     self.AssertOutputEndsInError()
3520
3521   def testHostWithoutPackage(self):
3522     """Test that running without a package argument exits with an error."""
3523     with self.OutputCapturer():
3524       # Running without a package should exit with code!=0
3525       self._AssertCPUMain(['--host'], expect_zero=False)
3526
3527     # Verify that an error message was printed.
3528     self.AssertOutputEndsInError()
3529
3530   def testUpgradeAndUpgradeDeep(self):
3531     """Running with --upgrade and --upgrade-deep exits with an error."""
3532     with self.OutputCapturer():
3533       # Expect exit with code!=0
3534       self._AssertCPUMain(['--host', '--upgrade', '--upgrade-deep',
3535                           'any-package'], expect_zero=False)
3536
3537     # Verify that an error message was printed.
3538     self.AssertOutputEndsInError()
3539
3540   def testForceWithoutUpgrade(self):
3541     """Running with --force requires --upgrade or --upgrade-deep."""
3542     with self.OutputCapturer():
3543       # Expect exit with code!=0
3544       self._AssertCPUMain(['--host', '--force', 'any-package'],
3545                           expect_zero=False)
3546
3547     # Verify that an error message was printed.
3548     self.AssertOutputEndsInError()
3549
3550   def testFlowStatusReportOneBoard(self):
3551     """Test main flow for basic one-board status report."""
3552
3553     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3554     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3555     self.mox.StubOutWithMock(cpu.Upgrader, 'PrepareToRun')
3556     self.mox.StubOutWithMock(cpu.Upgrader, 'RunBoard')
3557     self.mox.StubOutWithMock(cpu.Upgrader, 'RunCompleted')
3558     self.mox.StubOutWithMock(cpu.Upgrader, 'WriteTableFiles')
3559
3560     cpu.Upgrader.PreRunChecks()
3561     cpu._BoardIsSetUp('any-board').AndReturn(True)
3562     cpu.Upgrader.PrepareToRun()
3563     cpu.Upgrader.RunBoard('any-board')
3564     cpu.Upgrader.RunCompleted()
3565     cpu.Upgrader.WriteTableFiles(csv='/dev/null')
3566     self.mox.ReplayAll()
3567
3568     with self.OutputCapturer():
3569       self._AssertCPUMain(['--board=any-board', '--to-csv=/dev/null',
3570                           'any-package'], expect_zero=True)
3571     self.mox.VerifyAll()
3572
3573   def testFlowStatusReportOneBoardNotSetUp(self):
3574     """Test main flow for basic one-board status report."""
3575     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3576     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3577
3578     cpu.Upgrader.PreRunChecks()
3579     cpu._BoardIsSetUp('any-board').AndReturn(False)
3580     self.mox.ReplayAll()
3581
3582     # Running with a package not set up should exit with code!=0
3583     with self.OutputCapturer():
3584       self._AssertCPUMain(['--board=any-board', '--to-csv=/dev/null',
3585                           'any-package'], expect_zero=False)
3586     self.mox.VerifyAll()
3587
3588     # Verify that an error message was printed.
3589     self.AssertOutputEndsInError()
3590
3591   def testFlowStatusReportTwoBoards(self):
3592     """Test main flow for two-board status report."""
3593     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3594     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3595     self.mox.StubOutWithMock(cpu.Upgrader, 'PrepareToRun')
3596     self.mox.StubOutWithMock(cpu.Upgrader, 'RunBoard')
3597     self.mox.StubOutWithMock(cpu.Upgrader, 'RunCompleted')
3598     self.mox.StubOutWithMock(cpu.Upgrader, 'WriteTableFiles')
3599
3600     cpu.Upgrader.PreRunChecks()
3601     cpu._BoardIsSetUp('board1').AndReturn(True)
3602     cpu._BoardIsSetUp('board2').AndReturn(True)
3603     cpu.Upgrader.PrepareToRun()
3604     cpu.Upgrader.RunBoard('board1')
3605     cpu.Upgrader.RunBoard('board2')
3606     cpu.Upgrader.RunCompleted()
3607     cpu.Upgrader.WriteTableFiles(csv=None)
3608     self.mox.ReplayAll()
3609
3610     with self.OutputCapturer():
3611       self._AssertCPUMain(['--board=board1:board2', 'any-package'],
3612                           expect_zero=True)
3613     self.mox.VerifyAll()
3614
3615   def testFlowUpgradeOneBoard(self):
3616     """Test main flow for basic one-board upgrade."""
3617     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3618     self.mox.StubOutWithMock(cpu.Upgrader, 'CheckBoardList')
3619     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3620     self.mox.StubOutWithMock(cpu.Upgrader, 'PrepareToRun')
3621     self.mox.StubOutWithMock(cpu.Upgrader, 'RunBoard')
3622     self.mox.StubOutWithMock(cpu.Upgrader, 'RunCompleted')
3623     self.mox.StubOutWithMock(cpu.Upgrader, 'WriteTableFiles')
3624
3625     cpu.Upgrader.PreRunChecks()
3626     cpu.Upgrader.CheckBoardList(['any-board'])
3627     cpu._BoardIsSetUp('any-board').AndReturn(True)
3628     cpu.Upgrader.PrepareToRun()
3629     cpu.Upgrader.RunBoard('any-board')
3630     cpu.Upgrader.RunCompleted()
3631     cpu.Upgrader.WriteTableFiles(csv=None)
3632     self.mox.ReplayAll()
3633
3634     with self.OutputCapturer():
3635       self._AssertCPUMain(['--upgrade', '--board=any-board', 'any-package'],
3636                           expect_zero=True)
3637     self.mox.VerifyAll()
3638
3639   def testFlowUpgradeTwoBoards(self):
3640     """Test main flow for two-board upgrade."""
3641     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3642     self.mox.StubOutWithMock(cpu.Upgrader, 'CheckBoardList')
3643     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3644     self.mox.StubOutWithMock(cpu.Upgrader, 'PrepareToRun')
3645     self.mox.StubOutWithMock(cpu.Upgrader, 'RunBoard')
3646     self.mox.StubOutWithMock(cpu.Upgrader, 'RunCompleted')
3647     self.mox.StubOutWithMock(cpu.Upgrader, 'WriteTableFiles')
3648
3649     cpu.Upgrader.PreRunChecks()
3650     cpu.Upgrader.CheckBoardList(['board1', 'board2'])
3651     cpu._BoardIsSetUp('board1').AndReturn(True)
3652     cpu._BoardIsSetUp('board2').AndReturn(True)
3653     cpu.Upgrader.PrepareToRun()
3654     cpu.Upgrader.RunBoard('board1')
3655     cpu.Upgrader.RunBoard('board2')
3656     cpu.Upgrader.RunCompleted()
3657     cpu.Upgrader.WriteTableFiles(csv='/dev/null')
3658     self.mox.ReplayAll()
3659
3660     with self.OutputCapturer():
3661       self._AssertCPUMain(['--upgrade', '--board=board1:board2',
3662                           '--to-csv=/dev/null', 'any-package'],
3663                           expect_zero=True)
3664     self.mox.VerifyAll()
3665
3666   def testFlowUpgradeTwoBoardsAndHost(self):
3667     """Test main flow for two-board and host upgrade."""
3668     self.mox.StubOutWithMock(cpu.Upgrader, 'PreRunChecks')
3669     self.mox.StubOutWithMock(cpu.Upgrader, 'CheckBoardList')
3670     self.mox.StubOutWithMock(cpu, '_BoardIsSetUp')
3671     self.mox.StubOutWithMock(cpu.Upgrader, 'PrepareToRun')
3672     self.mox.StubOutWithMock(cpu.Upgrader, 'RunBoard')
3673     self.mox.StubOutWithMock(cpu.Upgrader, 'RunCompleted')
3674     self.mox.StubOutWithMock(cpu.Upgrader, 'WriteTableFiles')
3675
3676     cpu.Upgrader.PreRunChecks()
3677     cpu.Upgrader.CheckBoardList(['board1', 'board2'])
3678     cpu._BoardIsSetUp('board1').AndReturn(True)
3679     cpu._BoardIsSetUp('board2').AndReturn(True)
3680     cpu.Upgrader.PrepareToRun()
3681     cpu.Upgrader.RunBoard(cpu.Upgrader.HOST_BOARD)
3682     cpu.Upgrader.RunBoard('board1')
3683     cpu.Upgrader.RunBoard('board2')
3684     cpu.Upgrader.RunCompleted()
3685     cpu.Upgrader.WriteTableFiles(csv='/dev/null')
3686     self.mox.ReplayAll()
3687
3688     with self.OutputCapturer():
3689       self._AssertCPUMain(['--upgrade', '--host', '--board=board1:host:board2',
3690                         '--to-csv=/dev/null', 'any-package'], expect_zero=True)
3691     self.mox.VerifyAll()
3692
3693 if __name__ == '__main__':
3694   cros_test_lib.main()