manifest_versions_unittest.py revision 52ac9370d76ce669435589b71d0fdc57ef85535b
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 site_utils/manifest_versions.py."""
8
9# Turn off "access to protected member of class"
10# pylint: disable=W0212
11
12import datetime
13import os
14import re
15import time
16import unittest
17
18import mox
19
20import common
21from autotest_lib.client.common_lib import error
22from autotest_lib.client.common_lib import utils
23from autotest_lib.site_utils.suite_scheduler import manifest_versions
24
25
26class ManifestVersionsTest(mox.MoxTestBase):
27    """Unit tests for ManifestVersions.
28
29    @var _BRANCHES: canned branches that should parse out of the below.
30    @var _MANIFESTS_STRING: canned (string) list of manifest file paths.
31    """
32
33    _BRANCHES = [('release', '18'), ('release', '19'), ('release', '20'),
34                 ('factory', '20'), ('firmware', '20')]
35    _MANIFESTS_STRING = """
36build-name/x86-alex-release-group/pass/20/2057.0.9.xml
37
38
39build-name/x86-alex-release-group/pass/20/2057.0.10.xml
40
41
42build-name/x86-alex-release-group/pass/20/2054.0.0.xml
43
44
45build-name/x86-alex-release/pass/18/1660.103.0.xml
46
47
48build-name/x86-alex-release-group/pass/20/2051.0.0.xml
49
50
51build-name/x86-alex-firmware/pass/20/2048.1.1.xml
52
53
54build-name/x86-alex-release/pass/19/2046.3.0.xml
55
56
57build-name/x86-alex-release-group/pass/20/2050.0.0.xml
58
59
60build-name/x86-alex-release-group/pass/20/2048.0.0.xml
61
62
63build-name/x86-alex-factory/pass/20/2048.1.0.xml
64"""
65
66
67    def setUp(self):
68        """Initialization for unit tests."""
69        super(ManifestVersionsTest, self).setUp()
70        self.mv = manifest_versions.ManifestVersions()
71
72
73    def testInitialize(self):
74        """Ensure we can initialize a ManifestVersions."""
75        self.mox.StubOutWithMock(self.mv, '_Clone')
76        self.mox.StubOutWithMock(time, 'sleep')
77        self.mv._Clone()
78        self.mox.ReplayAll()
79        self.mv.Initialize()
80
81
82    def testInitializeRetry(self):
83        """Ensure we retry _Clone() the correct number of times."""
84        self.mox.StubOutWithMock(self.mv, '_Clone')
85        self.mox.StubOutWithMock(time, 'sleep')
86        for i in range(0, self.mv._CLONE_MAX_RETRIES):
87            self.mv._Clone().AndRaise(
88                error.CmdError('retried git clone failure',
89                               utils.CmdResult()))
90            time.sleep(self.mv._CLONE_RETRY_SECONDS)
91        self.mv._Clone()
92        self.mox.ReplayAll()
93        self.mv.Initialize()
94
95
96    def testInitializeFail(self):
97        """Ensure we fail after too many _Clone() retries."""
98        self.mox.StubOutWithMock(self.mv, '_Clone')
99        self.mox.StubOutWithMock(time, 'sleep')
100        for i in range(0, self.mv._CLONE_MAX_RETRIES):
101            self.mv._Clone().AndRaise(
102                error.CmdError('retried git clone failure',
103                               utils.CmdResult()))
104            time.sleep(self.mv._CLONE_RETRY_SECONDS)
105        self.mv._Clone().AndRaise(
106            error.CmdError('final git clone failure',
107                           utils.CmdResult()))
108        self.mox.ReplayAll()
109        self.assertRaises(manifest_versions.CloneException,
110                          self.mv.Initialize)
111
112
113    def testGlobs(self):
114        """Ensure that we expand globs correctly."""
115        desired_paths = ['one/path', 'two/path', 'three/path']
116        tempdir = self.mv._tempdir.name
117        for path in desired_paths:
118            os.makedirs(os.path.join(tempdir, path))
119        for path in self.mv._ExpandGlobMinusPrefix(tempdir, '*/path'):
120            self.assertTrue(path in desired_paths)
121
122
123    def _ExpectGlob(self, to_return):
124        self.mox.StubOutWithMock(self.mv, '_ExpandGlobMinusPrefix')
125        self.mv._ExpandGlobMinusPrefix(mox.IgnoreArg(),
126                                       mox.IgnoreArg()).AndReturn(to_return)
127
128
129    def testAnyManifestsSinceRev(self):
130        """Ensure we can tell if builds have succeeded since a given rev."""
131        rev = 'rev'
132        self._ExpectGlob(['some/paths'])
133        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
134        manifest_versions._SystemOutput(
135            mox.And(mox.StrContains('log'),
136                    mox.StrContains(rev))).MultipleTimes().AndReturn(
137                        self._MANIFESTS_STRING)
138        self.mox.ReplayAll()
139        self.assertTrue(self.mv.AnyManifestsSinceRev(rev))
140
141
142    def testNoManifestsSinceRev(self):
143        """Ensure we can tell if no builds have succeeded since a given rev."""
144        rev = 'rev'
145        self._ExpectGlob(['some/paths'])
146        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
147        manifest_versions._SystemOutput(
148            mox.And(mox.StrContains('log'),
149                    mox.StrContains(rev))).MultipleTimes().AndReturn(' ')
150        self.mox.ReplayAll()
151        self.assertFalse(self.mv.AnyManifestsSinceRev(rev))
152
153
154    def testNoManifestsPathsSinceRev(self):
155        """Ensure we can tell that we have no paths to check for new builds."""
156        rev = 'rev'
157        self._ExpectGlob([])
158        self.mox.ReplayAll()
159        self.assertFalse(self.mv.AnyManifestsSinceRev(rev))
160
161
162    def testManifestsSinceDate(self):
163        """Ensure we can get manifests for a board since N days ago."""
164        since_date = datetime.datetime(year=2015, month=2, day=1)
165        board = 'x86-alex'
166        self._ExpectGlob(['some/paths'])
167        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
168        manifest_versions._SystemOutput(
169            mox.StrContains('log')).MultipleTimes().AndReturn(
170                self._MANIFESTS_STRING)
171        self.mox.ReplayAll()
172        br_man = self.mv.ManifestsSinceDate(since_date, board)
173        for pair in br_man.keys():
174            self.assertTrue(pair, self._BRANCHES)
175        for manifest_list in br_man.itervalues():
176            self.assertTrue(manifest_list)
177        self.assertEquals(br_man[('release', '20')][-1], '2057.0.10')
178
179
180    def testNoManifestsSinceDate(self):
181        """Ensure we can deal with no manifests since N days ago."""
182        since_date = datetime.datetime(year=2015, month=2, day=1)
183        board = 'x86-alex'
184        self._ExpectGlob(['some/paths'])
185        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
186        manifest_versions._SystemOutput(mox.StrContains('log')).AndReturn([])
187        self.mox.ReplayAll()
188        br_man = self.mv.ManifestsSinceDate(since_date, board)
189        self.assertEquals(br_man, {})
190
191
192    def testNoManifestsPathsSinceDate(self):
193        """Ensure we can deal with finding no paths to pass to'git log'."""
194        since_date = datetime.datetime(year=2015, month=2, day=1)
195        board = 'x86-alex'
196        self._ExpectGlob([])
197        self.mox.ReplayAll()
198        br_man = self.mv.ManifestsSinceDate(since_date, board)
199        self.assertEquals(br_man, {})
200
201
202    def testManifestsSinceDateExplodes(self):
203        """Ensure we handle failures in querying manifests."""
204        since_date = datetime.datetime(year=2015, month=2, day=1)
205        board = 'x86-alex'
206        self._ExpectGlob(['some/paths'])
207        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
208        manifest_versions._SystemOutput(mox.StrContains('log')).AndRaise(
209            manifest_versions.QueryException())
210        self.mox.ReplayAll()
211        self.assertRaises(manifest_versions.QueryException,
212                          self.mv.ManifestsSinceDate, since_date, board)
213
214
215    def testUnparseableManifestPath(self):
216        """Ensure we don't explode if we encounter an unparseable path."""
217        since_date = datetime.datetime(year=2015, month=2, day=1)
218        board = 'link'
219        build_name = 'link-depthcharge-pgo-codename-release-suffix-part-two'
220        manifest = 'build-name/%s/pass/25/1234.0.0.xml' % build_name
221        self._ExpectGlob(['some/paths'])
222        self.mox.StubOutWithMock(manifest_versions, '_SystemOutput')
223        manifest_versions._SystemOutput(
224            mox.StrContains('log')).MultipleTimes().AndReturn(manifest)
225        self.mox.ReplayAll()
226        br_man = self.mv.ManifestsSinceDate(since_date, board)
227        # We should skip the manifest that we passed in, as we can't parse it,
228        # so we should get no manifests back.
229        self.assertEquals(br_man, {})
230
231
232    _BOARD_MANIFESTS = {
233        'lumpy': [
234            'lumpy-factory',
235            'lumpy-release',
236#            'lumpy-pgo-release',
237        ],
238        'x86-alex': [
239            'x86-alex-release',
240            'x86-alex-release-group',
241        ],
242        'link': [
243#            'link-depthcharge-firmware',
244        ],
245    }
246
247
248    def testBoardManifestRePattern(self):
249        """Ensure we can parse the names of builds that are produced."""
250        for board, builder_names in self._BOARD_MANIFESTS.items():
251            rgx = re.compile(
252                manifest_versions.ManifestVersions._BOARD_MANIFEST_RE_PATTERN %\
253                    board)
254            for builder_name in builder_names:
255                manifest = 'build-name/%s/pass/25/1234.0.0.xml' % builder_name
256                self.assertTrue(rgx.match(manifest), msg=builder_name)
257
258
259    def testGetManifests(self):
260        """Test _GetManifests when pattern is matched and not matched."""
261        rgx = re.compile(
262                self.mv._BOARD_MANIFEST_RE_PATTERN %
263                'lumpy')
264        self.assertEqual(self.mv._GetManifests(
265            rgx, ['build-name/lumpy-release/pass/25/1234.0.0.xml']),
266            {('release', '25'): ['1234.0.0']})
267        self.assertEqual(self.mv._GetManifests(
268            rgx, ['build-name/stumpy-release/pass/25/1234.0.0.xml']), {})
269
270
271if __name__ == '__main__':
272    unittest.main()
273