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