Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / lib / portage_util_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 portage_util.py."""
7
8 from __future__ import print_function
9
10 import fileinput
11 import mox
12 import os
13 import sys
14 import unittest
15
16 sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
17                                 '..', '..'))
18 from chromite.cbuildbot import constants
19 from chromite.lib import cros_build_lib
20 from chromite.lib import cros_test_lib
21 from chromite.lib import git
22 from chromite.lib import osutils
23 from chromite.lib import portage_util
24
25 # pylint: disable=W0212
26 MANIFEST = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
27
28 class _Package(object):
29   """Package helper class."""
30   def __init__(self, package):
31     self.package = package
32
33
34 class _DummyCommandResult(object):
35   """Create mock RunCommand results."""
36   def __init__(self, output):
37     # Members other than 'output' are expected to be unused, so
38     # we omit them here.
39     #
40     # All shell output will be newline terminated; we add the
41     # newline here for convenience.
42     self.output = output + '\n'
43
44
45 class EBuildTest(cros_test_lib.MoxTestCase):
46   """Ebuild related tests."""
47
48   def _makeFakeEbuild(self, fake_ebuild_path, fake_ebuild_content=''):
49     self.mox.StubOutWithMock(fileinput, 'input')
50     fileinput.input(fake_ebuild_path).AndReturn(fake_ebuild_content)
51     self.mox.ReplayAll()
52     fake_ebuild = portage_util.EBuild(fake_ebuild_path)
53     self.mox.VerifyAll()
54     return fake_ebuild
55
56   def testParseEBuildPath(self):
57     # Test with ebuild with revision number.
58     fake_ebuild_path = '/path/to/test_package/test_package-0.0.1-r1.ebuild'
59     fake_ebuild = self._makeFakeEbuild(fake_ebuild_path)
60
61     self.assertEquals(fake_ebuild._category, 'to')
62     self.assertEquals(fake_ebuild._pkgname, 'test_package')
63     self.assertEquals(fake_ebuild.version_no_rev, '0.0.1')
64     self.assertEquals(fake_ebuild.current_revision, 1)
65     self.assertEquals(fake_ebuild.version, '0.0.1-r1')
66     self.assertEquals(fake_ebuild.package, 'to/test_package')
67     self.assertEquals(fake_ebuild._ebuild_path_no_version,
68                       '/path/to/test_package/test_package')
69     self.assertEquals(fake_ebuild.ebuild_path_no_revision,
70                       '/path/to/test_package/test_package-0.0.1')
71     self.assertEquals(fake_ebuild._unstable_ebuild_path,
72                       '/path/to/test_package/test_package-9999.ebuild')
73     self.assertEquals(fake_ebuild.ebuild_path, fake_ebuild_path)
74
75   def testParseEBuildPathNoRevisionNumber(self):
76     # Test with ebuild without revision number.
77     fake_ebuild_path = '/path/to/test_package/test_package-9999.ebuild'
78     fake_ebuild = self._makeFakeEbuild(fake_ebuild_path)
79
80     self.assertEquals(fake_ebuild._category, 'to')
81     self.assertEquals(fake_ebuild._pkgname, 'test_package')
82     self.assertEquals(fake_ebuild.version_no_rev, '9999')
83     self.assertEquals(fake_ebuild.current_revision, 0)
84     self.assertEquals(fake_ebuild.version, '9999')
85     self.assertEquals(fake_ebuild.package, 'to/test_package')
86     self.assertEquals(fake_ebuild._ebuild_path_no_version,
87                       '/path/to/test_package/test_package')
88     self.assertEquals(fake_ebuild.ebuild_path_no_revision,
89                       '/path/to/test_package/test_package-9999')
90     self.assertEquals(fake_ebuild._unstable_ebuild_path,
91                       '/path/to/test_package/test_package-9999.ebuild')
92     self.assertEquals(fake_ebuild.ebuild_path, fake_ebuild_path)
93
94   def testGetCommitId(self):
95     fake_sources = '/path/to/sources'
96     fake_hash = '24ab3c9f6d6b5c744382dba2ca8fb444b9808e9f'
97     fake_ebuild_path = '/path/to/test_package/test_package-9999.ebuild'
98     fake_ebuild = self._makeFakeEbuild(fake_ebuild_path)
99
100     # git rev-parse HEAD
101     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
102     result = _DummyCommandResult(fake_hash)
103     cros_build_lib.RunCommand(
104         mox.IgnoreArg(),
105         cwd=mox.IgnoreArg(),
106         print_cmd=portage_util.EBuild.VERBOSE,
107         capture_output=True).AndReturn(result)
108
109     self.mox.ReplayAll()
110     test_hash = fake_ebuild.GetCommitId(fake_sources)
111     self.mox.VerifyAll()
112     self.assertEquals(test_hash, fake_hash)
113
114   def testEBuildStable(self):
115     """Test ebuild w/keyword variations"""
116     fake_ebuild_path = '/path/to/test_package/test_package-9999.ebuild'
117
118     datasets = (
119         ('~amd64', False),
120         ('amd64', True),
121         ('~amd64 ~arm ~x86', False),
122         ('~amd64 arm ~x86', True),
123         ('-* ~arm', False),
124         ('-* x86', True),
125     )
126     for keywords, stable in datasets:
127       fake_ebuild = self._makeFakeEbuild(
128           fake_ebuild_path, fake_ebuild_content=['KEYWORDS="%s"\n' % keywords])
129       self.assertEquals(fake_ebuild.is_stable, stable)
130       self.mox.UnsetStubs()
131
132   def testEBuildBlacklisted(self):
133     """Test blacklisted ebuild"""
134     fake_ebuild_path = '/path/to/test_package/test_package-9999.ebuild'
135
136     fake_ebuild = self._makeFakeEbuild(fake_ebuild_path)
137     self.assertEquals(fake_ebuild.is_blacklisted, False)
138     self.mox.UnsetStubs()
139
140     fake_ebuild = self._makeFakeEbuild(
141         fake_ebuild_path, fake_ebuild_content=['CROS_WORKON_BLACKLIST="1"\n'])
142     self.assertEquals(fake_ebuild.is_blacklisted, True)
143
144
145 class ProjectAndPathTest(cros_test_lib.MoxTempDirTestCase):
146   """Project and Path related tests."""
147
148   def _MockParseWorkonVariables(self, fake_projects, _fake_localname,
149                                 _fake_subdir, fake_ebuild_contents):
150     """Mock the necessary calls, start Replay mode, call GetSourcePath()."""
151     # pylint: disable=E1120
152     self.mox.StubOutWithMock(os.path, 'isdir')
153     self.mox.StubOutWithMock(MANIFEST, 'FindCheckoutFromPath')
154
155     # We need 'chromeos-base' here because it controls default _SUBDIR values.
156     ebuild_path = os.path.join(self.tempdir, 'chromeos-base', 'package',
157                                'package-9999.ebuild')
158     osutils.WriteFile(ebuild_path, fake_ebuild_contents, makedirs=True)
159     for p in fake_projects:
160       os.path.isdir(mox.IgnoreArg()).AndReturn(False)
161     for p in fake_projects:
162       os.path.isdir(mox.IgnoreArg()).AndReturn(True)
163       MANIFEST.FindCheckoutFromPath(mox.IgnoreArg()).AndReturn({ 'name': p })
164     self.mox.ReplayAll()
165
166     ebuild = portage_util.EBuild(ebuild_path)
167     result = ebuild.GetSourcePath(self.tempdir, MANIFEST)
168     self.mox.VerifyAll()
169     return result
170
171   def testParseLegacyWorkonVariables(self):
172     """Tests if ebuilds in a single item format are correctly parsed."""
173     fake_project = 'my_project1'
174     fake_localname = 'foo'
175     fake_subdir = 'bar'
176     fake_ebuild_contents = """
177 CROS_WORKON_PROJECT=%s
178 CROS_WORKON_LOCALNAME=%s
179 CROS_WORKON_SUBDIR=%s
180     """ % (fake_project, fake_localname, fake_subdir)
181     project, subdir = self._MockParseWorkonVariables(
182         [fake_project], [fake_localname], [fake_subdir], fake_ebuild_contents)
183     self.assertEquals(project, [fake_project])
184     self.assertEquals(subdir, [os.path.join(
185         self.tempdir, 'platform', '%s/%s' % (fake_localname, fake_subdir))])
186
187   def testParseArrayWorkonVariables(self):
188     """Tests if ebuilds in an array format are correctly parsed."""
189     fake_projects = ['my_project1', 'my_project2', 'my_project3']
190     fake_localname = ['foo', 'bar', 'bas']
191     fake_subdir = ['sub1', 'sub2', 'sub3']
192     # The test content is formatted using the same function that
193     # formats ebuild output, ensuring that we can parse our own
194     # products.
195     fake_ebuild_contents = """
196 CROS_WORKON_PROJECT=%s
197 CROS_WORKON_LOCALNAME=%s
198 CROS_WORKON_SUBDIR=%s
199     """ % (portage_util.EBuild.FormatBashArray(fake_projects),
200            portage_util.EBuild.FormatBashArray(fake_localname),
201            portage_util.EBuild.FormatBashArray(fake_subdir))
202     project, subdir = self._MockParseWorkonVariables(
203         fake_projects, fake_localname, fake_subdir, fake_ebuild_contents)
204     self.assertEquals(project, fake_projects)
205     fake_path = ['%s/%s' % (fake_localname[i], fake_subdir[i])
206                  for i in range(0, len(fake_projects))]
207     fake_path = map(lambda x: os.path.realpath(
208         os.path.join(self.tempdir, 'platform', x)), fake_path)
209     self.assertEquals(subdir, fake_path)
210
211
212 class StubEBuild(portage_util.EBuild):
213   """Test helper to StubEBuild."""
214   def __init__(self, path):
215     super(StubEBuild, self).__init__(path)
216     self.is_workon = True
217     self.is_stable = True
218
219   def _ReadEBuild(self, path):
220     pass
221
222   def GetCommitId(self, srcpath):
223     id_map = {
224       'p1_path' : 'my_id',
225       'p1_path1' : 'my_id1',
226       'p1_path2' : 'my_id2'
227     }
228     if srcpath in id_map:
229       return id_map[srcpath]
230     else:
231       return 'you_lose'
232
233
234 class EBuildRevWorkonTest(cros_test_lib.MoxTempDirTestCase):
235   """Tests for EBuildRevWorkon."""
236   # Lines that we will feed as fake ebuild contents to
237   # EBuild.MarAsStable().  This is the minimum content needed
238   # to test the various branches in the function's main processing
239   # loop.
240   _mock_ebuild = ['EAPI=2\n',
241                   'CROS_WORKON_COMMIT=old_id\n',
242                   'KEYWORDS=\"~x86 ~arm ~amd64\"\n',
243                   'src_unpack(){}\n']
244   _mock_ebuild_multi = ['EAPI=2\n',
245                         'CROS_WORKON_COMMIT=("old_id1","old_id2")\n',
246                         'KEYWORDS=\"~x86 ~arm ~amd64\"\n',
247                         'src_unpack(){}\n']
248
249   def setUp(self):
250     self.overlay = '/sources/overlay'
251     package_name = os.path.join(self.overlay,
252                                 'category/test_package/test_package-0.0.1')
253     ebuild_path = package_name + '-r1.ebuild'
254     self.m_ebuild = StubEBuild(ebuild_path)
255     self.revved_ebuild_path = package_name + '-r2.ebuild'
256
257   def createRevWorkOnMocks(self, ebuild_content, rev, multi=False):
258     # pylint: disable=E1120
259     self.mox.StubOutWithMock(os.path, 'exists')
260     self.mox.StubOutWithMock(cros_build_lib, 'Die')
261     self.mox.StubOutWithMock(portage_util.shutil, 'copyfile')
262     self.mox.StubOutWithMock(os, 'unlink')
263     self.mox.StubOutWithMock(portage_util.EBuild, '_RunGit')
264     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
265     self.mox.StubOutWithMock(portage_util.filecmp, 'cmp')
266     self.mox.StubOutWithMock(portage_util.fileinput, 'input')
267     self.mox.StubOutWithMock(portage_util.EBuild, 'GetVersion')
268     self.mox.StubOutWithMock(portage_util.EBuild, 'GetSourcePath')
269     self.mox.StubOutWithMock(portage_util.EBuild, 'GetTreeId')
270
271     if multi:
272       portage_util.EBuild.GetSourcePath('/sources', MANIFEST).AndReturn(
273           (['fake_project1','fake_project2'], ['p1_path1','p1_path2']))
274     else:
275       portage_util.EBuild.GetSourcePath('/sources', MANIFEST).AndReturn(
276           (['fake_project1'], ['p1_path']))
277     portage_util.EBuild.GetVersion('/sources', MANIFEST, '0.0.1').AndReturn(
278         '0.0.1')
279     if multi:
280       portage_util.EBuild.GetTreeId('p1_path1').AndReturn('treehash1')
281       portage_util.EBuild.GetTreeId('p1_path2').AndReturn('treehash2')
282     else:
283       portage_util.EBuild.GetTreeId('p1_path').AndReturn('treehash')
284
285     ebuild_9999 = self.m_ebuild._unstable_ebuild_path
286     os.path.exists(ebuild_9999).AndReturn(True)
287
288     # These calls come from MarkAsStable()
289     portage_util.shutil.copyfile(ebuild_9999, self.revved_ebuild_path)
290
291     m_file = self.mox.CreateMock(file)
292     portage_util.fileinput.input(self.revved_ebuild_path,
293                                  inplace=1).AndReturn(ebuild_content)
294     m_file.write('EAPI=2\n')
295
296     if multi:
297       m_file.write('CROS_WORKON_COMMIT=("my_id1" "my_id2")\n')
298       m_file.write('CROS_WORKON_TREE=("treehash1" "treehash2")\n')
299     else:
300       m_file.write('CROS_WORKON_COMMIT="my_id"\n')
301       m_file.write('CROS_WORKON_TREE="treehash"\n')
302
303     m_file.write('KEYWORDS=\"x86 arm amd64\"\n')
304     m_file.write('src_unpack(){}\n')
305     # MarkAsStable() returns here
306
307     portage_util.filecmp.cmp(self.m_ebuild.ebuild_path,
308                              self.revved_ebuild_path,
309                              shallow=False).AndReturn(not rev)
310     if rev:
311       cmd = ['add', self.revved_ebuild_path]
312       portage_util.EBuild._RunGit(self.overlay, cmd)
313       if self.m_ebuild.is_stable:
314         cmd = ['rm', self.m_ebuild.ebuild_path]
315         portage_util.EBuild._RunGit(self.overlay, cmd)
316     else:
317       os.unlink(self.revved_ebuild_path)
318
319     return m_file
320
321   def testRevWorkOnEBuild(self):
322     """Test Uprev of a single project ebuild."""
323     m_file = self.createRevWorkOnMocks(self._mock_ebuild, rev=True)
324     self.mox.ReplayAll()
325     result = self.m_ebuild.RevWorkOnEBuild('/sources', MANIFEST,
326                                            redirect_file=m_file)
327     self.mox.VerifyAll()
328     self.assertEqual(result, 'category/test_package-0.0.1-r2')
329
330   def testRevWorkOnMultiEBuild(self):
331     """Test Uprev of a multi-project (array) ebuild."""
332     m_file = self.createRevWorkOnMocks(self._mock_ebuild_multi, rev=True,
333                                        multi=True)
334     self.mox.ReplayAll()
335     result = self.m_ebuild.RevWorkOnEBuild('/sources', MANIFEST,
336                                            redirect_file=m_file)
337     self.mox.VerifyAll()
338     self.assertEqual(result, 'category/test_package-0.0.1-r2')
339
340   def testRevUnchangedEBuild(self):
341     m_file = self.createRevWorkOnMocks(self._mock_ebuild, rev=False)
342
343     self.mox.ReplayAll()
344     result = self.m_ebuild.RevWorkOnEBuild('/sources', MANIFEST,
345                                            redirect_file=m_file)
346     self.mox.VerifyAll()
347     self.assertEqual(result, None)
348
349   def testRevMissingEBuild(self):
350     self.revved_ebuild_path = self.m_ebuild.ebuild_path
351     self.m_ebuild.ebuild_path = self.m_ebuild._unstable_ebuild_path
352     self.m_ebuild.current_revision = 0
353     self.m_ebuild.is_stable = False
354
355     m_file = self.createRevWorkOnMocks(
356       self._mock_ebuild[0:1] + self._mock_ebuild[2:], rev=True)
357
358     self.mox.ReplayAll()
359     result = self.m_ebuild.RevWorkOnEBuild('/sources', MANIFEST,
360                                            redirect_file=m_file)
361     self.mox.VerifyAll()
362     self.assertEqual(result, 'category/test_package-0.0.1-r1')
363
364   def testCommitChange(self):
365     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
366     mock_message = 'Commitme'
367     git.RunGit('.', ['commit', '-a', '-m', mock_message])
368     self.mox.ReplayAll()
369     self.m_ebuild.CommitChange(mock_message, '.')
370     self.mox.VerifyAll()
371
372   def testUpdateCommitHashesForChanges(self):
373     """Tests that we can update the commit hashes for changes correctly."""
374     cls = portage_util.EBuild
375     ebuild1 = self.mox.CreateMock(cls)
376     ebuild1.ebuild_path = 'public_overlay/ebuild.ebuild'
377     ebuild1.package = 'test/project'
378
379     self.mox.StubOutWithMock(portage_util, 'FindOverlays')
380     self.mox.StubOutWithMock(cls, '_GetEBuildPaths')
381     self.mox.StubOutWithMock(cls, '_GetSHA1ForPath')
382     self.mox.StubOutWithMock(cls, 'UpdateEBuild')
383     self.mox.StubOutWithMock(cls, 'CommitChange')
384     self.mox.StubOutWithMock(cls, 'GitRepoHasChanges')
385
386     build_root = 'fakebuildroot'
387     overlays = ['public_overlay']
388     changes = ['fake change']
389     paths = ['fake_path1', 'fake_path2']
390     path_ebuilds = {ebuild1: paths}
391     portage_util.FindOverlays(
392         constants.BOTH_OVERLAYS, buildroot=build_root).AndReturn(overlays)
393     cls._GetEBuildPaths(build_root, mox.IgnoreArg(), overlays,
394                         changes).AndReturn(path_ebuilds)
395     for i, p in enumerate(paths):
396       cls._GetSHA1ForPath(mox.IgnoreArg(), p).InAnyOrder().AndReturn(str(i))
397     cls.UpdateEBuild(ebuild1.ebuild_path, dict(CROS_WORKON_COMMIT='("0" "1")'))
398     cls.GitRepoHasChanges('public_overlay').AndReturn(True)
399     cls.CommitChange(mox.IgnoreArg(), overlay='public_overlay')
400     self.mox.ReplayAll()
401     cls.UpdateCommitHashesForChanges(changes, build_root, MANIFEST)
402     self.mox.VerifyAll()
403
404   def testGitRepoHasChanges(self):
405     """Tests that GitRepoHasChanges works correctly."""
406     url = 'file://' + os.path.join(constants.SOURCE_ROOT, 'chromite')
407     git.RunGit(self.tempdir, ['clone', '--depth=1', url, self.tempdir])
408     # No changes yet as we just cloned the repo.
409     self.assertFalse(portage_util.EBuild.GitRepoHasChanges(self.tempdir))
410     # Update metadata but no real changes.
411     osutils.Touch(os.path.join(self.tempdir, 'LICENSE'))
412     self.assertFalse(portage_util.EBuild.GitRepoHasChanges(self.tempdir))
413     # A real change.
414     osutils.WriteFile(os.path.join(self.tempdir, 'LICENSE'), 'hi')
415     self.assertTrue(portage_util.EBuild.GitRepoHasChanges(self.tempdir))
416
417
418 class FindOverlaysTest(cros_test_lib.MockTestCase):
419   """Tests related to finding overlays."""
420
421   FAKE, MARIO = 'fake-board', 'x86-mario'
422   PRIVATE = constants.PRIVATE_OVERLAYS
423   PUBLIC = constants.PUBLIC_OVERLAYS
424   BOTH = constants.BOTH_OVERLAYS
425
426   def setUp(self):
427     """Fetch all overlays."""
428     self.overlays = {}
429     for b in (None, self.FAKE, self.MARIO):
430       self.overlays[b] = d = {}
431       for o in (self.PRIVATE, self.PUBLIC, self.BOTH, None):
432         d[o] = portage_util.FindOverlays(o, b, constants.SOURCE_ROOT)
433     self._no_overlays = not bool(any(d.values()))
434
435   def _MaybeSkip(self):
436     """Skip the test if no overlays are available."""
437     # TODO: Should create a local buildroot to test against instead ...
438     if self._no_overlays:
439       raise unittest.SkipTest('no overlays found in src/overlays/')
440
441   def testMissingPrimaryOverlay(self):
442     """Test what happens when a primary overlay is missing.
443
444     If the overlay doesn't exist, FindOverlays should throw a
445     MissingOverlayException.
446     """
447     self.assertRaises(portage_util.MissingOverlayException,
448                       portage_util.FindPrimaryOverlay, self.BOTH,
449                       self.FAKE, constants.SOURCE_ROOT)
450
451   def testDuplicates(self):
452     """Verify that no duplicate overlays are returned."""
453     for d in self.overlays.itervalues():
454       for overlays in d.itervalues():
455         self.assertEqual(len(overlays), len(set(overlays)))
456
457   def testOverlaysExist(self):
458     """Verify that all overlays returned actually exist on disk."""
459     for d in self.overlays.itervalues():
460       for overlays in d.itervalues():
461         self.assertTrue(all(os.path.isdir(x) for x in overlays))
462
463   def testPrivatePublicOverlayTypes(self):
464     """Verify public/private filtering.
465
466     If we ask for results from 'both overlays', we should
467     find all public and all private overlays.
468
469     There should always be at least one public overlay. (Note:
470     there may not be any private overlays, e.g. if the user has
471     a public checkout.)
472     """
473     self._MaybeSkip()
474
475     for d in self.overlays.itervalues():
476       self.assertGreaterEqual(set(d[self.BOTH]), set(d[self.PUBLIC]))
477       self.assertGreater(set(d[self.BOTH]), set(d[self.PRIVATE]))
478       self.assertTrue(set(d[self.PUBLIC]).isdisjoint(d[self.PRIVATE]))
479
480   def testNoOverlayType(self):
481     """If we specify overlay_type=None, no results should be returned."""
482     self.assertTrue(all(d[None] == [] for d in self.overlays.itervalues()))
483
484   def testNonExistentBoard(self):
485     """Test what happens when a non-existent board is supplied.
486
487     If we specify a non-existent board to FindOverlays, only generic
488     overlays should be returned.
489     """
490     self._MaybeSkip()
491
492     for o in (self.PUBLIC, self.BOTH):
493       self.assertLess(set(self.overlays[self.FAKE][o]),
494                           set(self.overlays[self.MARIO][o]))
495
496   def testAllBoards(self):
497     """If we specify board=None, all overlays should be returned."""
498     self._MaybeSkip()
499
500     for o in (self.PUBLIC, self.BOTH):
501       for b in (self.FAKE, self.MARIO):
502         self.assertLess(set(self.overlays[b][o]), set(self.overlays[None][o]))
503
504   def testMarioPrimaryOverlay(self):
505     """Verify that mario has a primary overlay.
506
507     Further, the only difference between the public overlays for mario and a
508     fake board is the primary overlay, which is listed last.
509     """
510     self._MaybeSkip()
511
512     mario_primary = portage_util.FindPrimaryOverlay(self.BOTH, self.MARIO,
513                                                     constants.SOURCE_ROOT)
514     self.assertIn(mario_primary, self.overlays[self.MARIO][self.BOTH])
515     self.assertNotIn(mario_primary, self.overlays[self.FAKE][self.BOTH])
516     self.assertEqual(mario_primary, self.overlays[self.MARIO][self.PUBLIC][-1])
517     self.assertEqual(self.overlays[self.MARIO][self.PUBLIC][:-1],
518                      self.overlays[self.FAKE][self.PUBLIC])
519
520   def testReadOverlayFile(self):
521     """Verify that the boards are examined in the right order"""
522     m = self.PatchObject(osutils, 'ReadFile',
523                          side_effect=IOError(os.errno.ENOENT, 'ENOENT'))
524     portage_util.ReadOverlayFile('test', self.PUBLIC, self.MARIO,
525                                  constants.SOURCE_ROOT)
526     read_overlays = [x[0][0][:-5] for x in m.call_args_list]
527     overlays = [x for x in reversed(self.overlays[self.MARIO][self.PUBLIC])]
528     self.assertEqual(read_overlays, overlays)
529
530
531 class UtilFuncsTest(cros_test_lib.TempDirTestCase):
532   """Basic tests for utility functions"""
533
534   def _CreateProfilesRepoName(self, name):
535     """Write |name| to profiles/repo_name"""
536     profiles = os.path.join(self.tempdir, 'profiles')
537     osutils.SafeMakedirs(profiles)
538     repo_name = os.path.join(profiles, 'repo_name')
539     osutils.WriteFile(repo_name, name)
540
541   def testGetOverlayNameNone(self):
542     """If the overlay has no name, it should be fine"""
543     self.assertEqual(portage_util.GetOverlayName(self.tempdir), None)
544
545   def testGetOverlayNameProfilesRepoName(self):
546     """Verify profiles/repo_name can be read"""
547     self._CreateProfilesRepoName('hi!')
548     self.assertEqual(portage_util.GetOverlayName(self.tempdir), 'hi!')
549
550   def testGetOverlayNameProfilesLayoutConf(self):
551     """Verify metadata/layout.conf is read before profiles/repo_name"""
552     self._CreateProfilesRepoName('hi!')
553     metadata = os.path.join(self.tempdir, 'metadata')
554     osutils.SafeMakedirs(metadata)
555     layout_conf = os.path.join(metadata, 'layout.conf')
556     osutils.WriteFile(layout_conf, 'repo-name = bye')
557     self.assertEqual(portage_util.GetOverlayName(self.tempdir), 'bye')
558
559   def testGetOverlayNameProfilesLayoutConfNoRepoName(self):
560     """Verify metadata/layout.conf w/out repo-name is ignored"""
561     self._CreateProfilesRepoName('hi!')
562     metadata = os.path.join(self.tempdir, 'metadata')
563     osutils.SafeMakedirs(metadata)
564     layout_conf = os.path.join(metadata, 'layout.conf')
565     osutils.WriteFile(layout_conf, 'here = we go')
566     self.assertEqual(portage_util.GetOverlayName(self.tempdir), 'hi!')
567
568
569 class BuildEBuildDictionaryTest(cros_test_lib.MoxTestCase):
570   """Tests of the EBuild Dictionary."""
571
572   def setUp(self):
573     self.mox.StubOutWithMock(os, 'walk')
574     self.mox.StubOutWithMock(cros_build_lib, 'RunCommand')
575     self.package = 'chromeos-base/test_package'
576     self.root = '/overlay/chromeos-base/test_package'
577     self.package_path = self.root + '/test_package-0.0.1.ebuild'
578     paths = [[self.root, [], []]]
579     os.walk("/overlay").AndReturn(paths)
580     self.mox.StubOutWithMock(portage_util, '_FindUprevCandidates')
581
582   def testWantedPackage(self):
583     overlays = {"/overlay": []}
584     package = _Package(self.package)
585     portage_util._FindUprevCandidates([]).AndReturn(package)
586     self.mox.ReplayAll()
587     portage_util.BuildEBuildDictionary(overlays, False, [self.package])
588     self.mox.VerifyAll()
589     self.assertEquals(len(overlays), 1)
590     self.assertEquals(overlays["/overlay"], [package])
591
592   def testUnwantedPackage(self):
593     overlays = {"/overlay": []}
594     package = _Package(self.package)
595     portage_util._FindUprevCandidates([]).AndReturn(package)
596     self.mox.ReplayAll()
597     portage_util.BuildEBuildDictionary(overlays, False, [])
598     self.assertEquals(len(overlays), 1)
599     self.assertEquals(overlays["/overlay"], [])
600     self.mox.VerifyAll()
601
602
603 class ProjectMappingTest(cros_test_lib.TestCase):
604   """Tests related to Proejct Mapping."""
605
606   def testSplitEbuildPath(self):
607     """Test if we can split an ebuild path into its components."""
608     ebuild_path = 'chromeos-base/platform2/platform2-9999.ebuild'
609     components = ['chromeos-base', 'platform2', 'platform2-9999']
610     for path in (ebuild_path, './' + ebuild_path, 'foo.bar/' + ebuild_path):
611       self.assertEquals(components, portage_util.SplitEbuildPath(path))
612
613   def testSplitPV(self):
614     """Test splitting PVs into package and version components."""
615     pv = 'bar-1.2.3_rc1-r5'
616     package, version_no_rev, rev = tuple(pv.split('-'))
617     split_pv = portage_util.SplitPV(pv)
618     self.assertEquals(split_pv.pv, pv)
619     self.assertEquals(split_pv.package, package)
620     self.assertEquals(split_pv.version_no_rev, version_no_rev)
621     self.assertEquals(split_pv.rev, rev)
622     self.assertEquals(split_pv.version, '%s-%s' % (version_no_rev, rev))
623
624   def testSplitCPV(self):
625     """Test splitting CPV into components."""
626     cpv = 'foo/bar-4.5.6_alpha-r6'
627     cat, pv = cpv.split('/', 1)
628     split_pv = portage_util.SplitPV(pv)
629     split_cpv = portage_util.SplitCPV(cpv)
630     self.assertEquals(split_cpv.category, cat)
631     for k, v in split_pv._asdict().iteritems():
632       self.assertEquals(getattr(split_cpv, k), v)
633
634   def testFindWorkonProjects(self):
635     """Test if we can find the list of workon projects."""
636     ply_image = 'media-gfx/ply-image'
637     ply_image_project = 'chromiumos/third_party/ply-image'
638     kernel = 'sys-kernel/chromeos-kernel'
639     kernel_project = 'chromiumos/third_party/kernel'
640     matches = [
641       ([ply_image], set([ply_image_project])),
642       ([kernel], set([kernel_project])),
643       ([ply_image, kernel], set([ply_image_project, kernel_project]))
644     ]
645     if portage_util.FindOverlays(constants.BOTH_OVERLAYS):
646       for packages, projects in matches:
647         self.assertEquals(projects,
648                           portage_util.FindWorkonProjects(packages))
649
650
651 class PackageDBTest(cros_test_lib.MoxTempDirTestCase):
652   """Package Database related tests."""
653
654   fake_pkgdb = { 'category1' : [ 'package-1', 'package-2' ],
655                  'category2' : [ 'package-3', 'package-4' ],
656                  'category3' : [ 'invalid', 'semi-invalid' ],
657                  'invalid' : [], }
658   fake_packages = []
659   build_root = None
660   fake_chroot = None
661
662   def setUp(self):
663     self.build_root = self.tempdir
664     self.fake_packages = []
665     # Prepare a fake chroot.
666     self.fake_chroot = os.path.join(self.build_root, 'chroot/build/amd64-host')
667     fake_pkgdb_path = os.path.join(self.fake_chroot, 'var/db/pkg')
668     os.makedirs(fake_pkgdb_path)
669     for cat, pkgs in self.fake_pkgdb.iteritems():
670       catpath = os.path.join(fake_pkgdb_path, cat)
671       if cat == 'invalid':
672         # Invalid category is a file. Should not be delved into.
673         osutils.Touch(catpath)
674         continue
675       os.makedirs(catpath)
676       for pkg in pkgs:
677         pkgpath = os.path.join(catpath, pkg)
678         if pkg == 'invalid':
679           # Invalid package is a file instead of a directory/
680           osutils.Touch(pkgpath)
681           continue
682         os.makedirs(pkgpath)
683         if pkg.endswith('-invalid'):
684           # Invalid package does not meet existence of "%s/%s.ebuild" file.
685           osutils.Touch(os.path.join(pkgpath, 'whatever'))
686           continue
687         # Correct pkg.
688         osutils.Touch(os.path.join(pkgpath, pkg + '.ebuild'))
689         pv = portage_util.SplitPV(pkg)
690         key = '%s/%s' % (cat, pv.package)
691         self.fake_packages.append((key, pv.version))
692
693   def testListInstalledPackages(self):
694     """Test if listing packages installed into a root works."""
695     packages = portage_util.ListInstalledPackages(self.fake_chroot)
696     # Sort the lists, because the filesystem might reorder the entries for us.
697     packages.sort()
698     self.fake_packages.sort()
699     self.assertEquals(self.fake_packages, packages)
700
701   def testIsPackageInstalled(self):
702     """Test if checking the existence of an installed package works."""
703     self.assertTrue(portage_util.IsPackageInstalled(
704         'category1/package',
705         sysroot=self.fake_chroot))
706     self.assertFalse(portage_util.IsPackageInstalled(
707         'category1/foo',
708         sysroot=self.fake_chroot))
709
710
711 if __name__ == '__main__':
712   cros_test_lib.main()