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