blob: 16cccb3d24b60603d318192fa7553d3ccebc3d29 [file] [log] [blame]
Gilad Arnold5f46d8e2015-02-19 12:17:55 -08001#!/usr/bin/python2
joychen3cb228e2013-06-12 12:13:13 -07002
3# Copyright (c) 2013 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 xbuddy.py."""
8
Gilad Arnold5f46d8e2015-02-19 12:17:55 -08009from __future__ import print_function
10
Gilad Arnold896c6d82015-03-13 16:20:29 -070011import ConfigParser
joychen3cb228e2013-06-12 12:13:13 -070012import os
13import shutil
joychen921e1fb2013-06-28 11:12:20 -070014import tempfile
joychen3cb228e2013-06-12 12:13:13 -070015import time
16import unittest
17
18import mox
19
joychenf8f07e22013-07-12 17:45:51 -070020import gsutil_util
joychen3cb228e2013-06-12 12:13:13 -070021import xbuddy
22
23#pylint: disable=W0212
Simran Basi99e63c02014-05-20 10:39:52 -070024
25GS_ALTERNATE_DIR = 'gs://chromeos-alternate-archive/'
26
27
joychen3cb228e2013-06-12 12:13:13 -070028class xBuddyTest(mox.MoxTestBase):
29 """Regression tests for xbuddy."""
30 def setUp(self):
31 mox.MoxTestBase.setUp(self)
32
joychen921e1fb2013-06-28 11:12:20 -070033 self.static_image_dir = tempfile.mkdtemp('xbuddy_unittest_static')
joychen3cb228e2013-06-12 12:13:13 -070034
joychen921e1fb2013-06-28 11:12:20 -070035 self.mock_xb = xbuddy.XBuddy(
Gilad Arnold5f46d8e2015-02-19 12:17:55 -080036 True,
37 static_dir=self.static_image_dir
joychen921e1fb2013-06-28 11:12:20 -070038 )
39 self.images_dir = tempfile.mkdtemp('xbuddy_unittest_images')
40 self.mock_xb.images_dir = self.images_dir
joychen3cb228e2013-06-12 12:13:13 -070041
42 def tearDown(self):
43 """Removes testing files."""
44 shutil.rmtree(self.static_image_dir)
joychen921e1fb2013-06-28 11:12:20 -070045 shutil.rmtree(self.images_dir)
joychen3cb228e2013-06-12 12:13:13 -070046
47 def testParseBoolean(self):
48 """Check that some common True/False strings are handled."""
49 self.assertEqual(xbuddy.XBuddy.ParseBoolean(None), False)
50 self.assertEqual(xbuddy.XBuddy.ParseBoolean('false'), False)
51 self.assertEqual(xbuddy.XBuddy.ParseBoolean('bs'), False)
52 self.assertEqual(xbuddy.XBuddy.ParseBoolean('true'), True)
53 self.assertEqual(xbuddy.XBuddy.ParseBoolean('y'), True)
54
joychenf8f07e22013-07-12 17:45:51 -070055 def testLookupOfficial(self):
56 """Basic test of _LookupOfficial. Checks that a given suffix is handled."""
57 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
58 gsutil_util.GSUtilRun(mox.IgnoreArg(),
59 mox.IgnoreArg()).AndReturn('v')
60 expected = 'b-s/v'
61 self.mox.ReplayAll()
Gilad Arnold896c6d82015-03-13 16:20:29 -070062 self.assertEqual(self.mock_xb._LookupOfficial('b', suffix='-s'), expected)
joychenf8f07e22013-07-12 17:45:51 -070063 self.mox.VerifyAll()
64
65 def testLookupChannel(self):
66 """Basic test of _LookupChannel. Checks that a given suffix is handled."""
67 self.mox.StubOutWithMock(gsutil_util, 'GetLatestVersionFromGSDir')
68 mock_data1 = '4100.68.0'
joychen562699a2013-08-13 15:22:14 -070069 gsutil_util.GetLatestVersionFromGSDir(
70 mox.IgnoreArg(), with_release=False).AndReturn(mock_data1)
joychenf8f07e22013-07-12 17:45:51 -070071 mock_data2 = 'R28-4100.68.0'
72 gsutil_util.GetLatestVersionFromGSDir(mox.IgnoreArg()).AndReturn(mock_data2)
73 self.mox.ReplayAll()
74 expected = 'b-release/R28-4100.68.0'
Gilad Arnold896c6d82015-03-13 16:20:29 -070075 self.assertEqual(self.mock_xb._LookupChannel('b', '-release'),
Simran Basi99e63c02014-05-20 10:39:52 -070076 expected)
joychenf8f07e22013-07-12 17:45:51 -070077 self.mox.VerifyAll()
78
Gilad Arnold896c6d82015-03-13 16:20:29 -070079 def testLookupAliasPathRewrite(self):
80 """Tests _LookupAlias of path rewrite, including keyword substitution."""
Gilad Arnoldd04fcab2015-02-19 12:00:45 -080081 alias = 'foobar'
82 path = 'remote/BOARD/VERSION/test'
83 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
Gilad Arnold896c6d82015-03-13 16:20:29 -070084 self.mock_xb.config.get('LOCATION_SUFFIXES', alias).AndRaise(
85 ConfigParser.Error())
86 self.mock_xb.config.get('PATH_REWRITES', alias).AndReturn(path)
Gilad Arnoldd04fcab2015-02-19 12:00:45 -080087 self.mox.ReplayAll()
Gilad Arnold896c6d82015-03-13 16:20:29 -070088 self.assertEqual(('remote/parrot/1.2.3/test', '-release'),
89 self.mock_xb._LookupAlias(alias, 'parrot', '1.2.3'))
90
91 def testLookupAliasSuffix(self):
92 """Tests _LookupAlias of location suffix."""
93 alias = 'foobar'
94 suffix = '-random'
95 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
96 self.mock_xb.config.get('LOCATION_SUFFIXES', alias).AndReturn(suffix)
97 self.mock_xb.config.get('PATH_REWRITES', alias).AndRaise(
98 ConfigParser.Error())
99 self.mox.ReplayAll()
100 self.assertEqual((alias, suffix),
101 self.mock_xb._LookupAlias(alias, 'parrot', '1.2.3'))
102
103 def testLookupAliasPathRewriteAndSuffix(self):
104 """Tests _LookupAlias with both path rewrite and suffix."""
105 alias = 'foobar'
106 path = 'remote/BOARD/VERSION/test'
107 suffix = '-random'
108 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
109 self.mock_xb.config.get('LOCATION_SUFFIXES', alias).AndReturn(suffix)
110 self.mock_xb.config.get('PATH_REWRITES', alias).AndReturn(path)
111 self.mox.ReplayAll()
112 self.assertEqual(('remote/parrot/1.2.3/test', suffix),
Gilad Arnoldd04fcab2015-02-19 12:00:45 -0800113 self.mock_xb._LookupAlias(alias, 'parrot', '1.2.3'))
114
Chris Sosaea734d92013-10-11 11:28:58 -0700115 def testResolveVersionToBuildId_Official(self):
116 """Check _ResolveVersionToBuildId recognizes aliases for official builds."""
joychenf8f07e22013-07-12 17:45:51 -0700117 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700118 suffix = '-s'
joychenf8f07e22013-07-12 17:45:51 -0700119
120 # aliases that should be redirected to LookupOfficial
Chris Sosaea734d92013-10-11 11:28:58 -0700121
joychenf8f07e22013-07-12 17:45:51 -0700122 self.mox.StubOutWithMock(self.mock_xb, '_LookupOfficial')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700123 self.mock_xb._LookupOfficial(board, suffix, image_dir=None)
124 self.mock_xb._LookupOfficial(board, suffix,
Simran Basi99e63c02014-05-20 10:39:52 -0700125 image_dir=GS_ALTERNATE_DIR)
126 self.mock_xb._LookupOfficial(board, 'paladin', image_dir=None)
127 self.mock_xb._LookupOfficial(board, 'paladin',
128 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700129
130 self.mox.ReplayAll()
131 version = 'latest-official'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700132 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
133 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700134 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700135 version = 'latest-official-paladin'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700136 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
137 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700138 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700139 self.mox.VerifyAll()
140
Chris Sosaea734d92013-10-11 11:28:58 -0700141 def testResolveVersionToBuildId_Channel(self):
142 """Check _ResolveVersionToBuildId recognizes aliases for channels."""
joychenf8f07e22013-07-12 17:45:51 -0700143 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700144 suffix = '-s'
joychenf8f07e22013-07-12 17:45:51 -0700145
146 # aliases that should be redirected to LookupChannel
147 self.mox.StubOutWithMock(self.mock_xb, '_LookupChannel')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700148 self.mock_xb._LookupChannel(board, suffix, image_dir=None)
149 self.mock_xb._LookupChannel(board, suffix, image_dir=GS_ALTERNATE_DIR)
150 self.mock_xb._LookupChannel(board, suffix, channel='dev', image_dir=None)
151 self.mock_xb._LookupChannel(board, suffix, channel='dev',
152 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700153
154 self.mox.ReplayAll()
155 version = 'latest'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700156 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
157 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700158 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700159 version = 'latest-dev'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700160 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
161 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700162 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700163 self.mox.VerifyAll()
joychen3cb228e2013-06-12 12:13:13 -0700164
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800165 def testResolveVersionToBuildId_BaseVersion(self):
166 """Check _ResolveVersionToBuildId handles a base version."""
167 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700168 suffix = '-s'
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800169
170 self.mox.StubOutWithMock(self.mock_xb, '_ResolveBuildVersion')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700171 self.mock_xb._ResolveBuildVersion(board, suffix, '1.2.3').AndReturn(
172 'R12-1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800173 self.mox.StubOutWithMock(self.mock_xb, '_RemoteBuildId')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700174 self.mock_xb._RemoteBuildId(board, suffix, 'R12-1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800175 self.mox.ReplayAll()
176
Gilad Arnold896c6d82015-03-13 16:20:29 -0700177 self.mock_xb._ResolveVersionToBuildId(board, suffix, '1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800178 self.mox.VerifyAll()
179
joychen3cb228e2013-06-12 12:13:13 -0700180 def testBasicInterpretPath(self):
181 """Basic checks for splitting a path"""
joychen121fc9b2013-08-02 14:30:30 -0700182 path = 'parrot/R27-2455.0.0/test'
joychen7df67f72013-07-18 14:21:12 -0700183 expected = ('test', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700184 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700185
joychen121fc9b2013-08-02 14:30:30 -0700186 path = 'parrot/R27-2455.0.0/full_payload'
187 expected = ('full_payload', 'parrot', 'R27-2455.0.0', True)
188 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
189
190 path = 'parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800191 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700192 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
193
194 path = 'remote/parrot/R27-2455.0.0'
195 expected = ('test', 'parrot', 'R27-2455.0.0', False)
196 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
197
198 path = 'local/parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800199 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700200 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
201
202 path = ''
Chris Sosa0eecf962014-02-03 14:14:39 -0800203 expected = ('ANY', None, 'latest', True)
204 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen3cb228e2013-06-12 12:13:13 -0700205
joychen121fc9b2013-08-02 14:30:30 -0700206 path = 'local'
Chris Sosa0eecf962014-02-03 14:14:39 -0800207 expected = ('ANY', None, 'latest', True)
208 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700209
joychenc3944cb2013-08-19 10:42:07 -0700210 path = 'local/parrot/latest/ANY'
211 expected = ('ANY', 'parrot', 'latest', True)
212 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
213
Gilad Arnoldd04fcab2015-02-19 12:00:45 -0800214 def testInterpretPathWithDefaults(self):
215 """Test path splitting with default board/version."""
216 path = ''
217 expected = ('ANY', 'parrot', 'latest', True)
218 self.assertEqual(expected, self.mock_xb._InterpretPath(
219 path=path, default_board='parrot'))
220
221 path = ''
222 expected = ('ANY', None, '1.2.3', True)
223 self.assertEqual(expected, self.mock_xb._InterpretPath(
224 path=path, default_version='1.2.3'))
225
226 path = ''
227 expected = ('ANY', 'parrot', '1.2.3', True)
228 self.assertEqual(expected, self.mock_xb._InterpretPath(
229 path=path, default_board='parrot', default_version='1.2.3'))
230
231 path = '1.2.3'
232 expected = ('ANY', None, '1.2.3', True)
233 self.assertEqual(expected, self.mock_xb._InterpretPath(
234 path=path, default_version='1.2.3'))
235
236 path = 'latest'
237 expected = ('ANY', None, 'latest', True)
238 self.assertEqual(expected, self.mock_xb._InterpretPath(
239 path=path, default_version='1.2.3'))
240
241 path = '1.2.3'
242 expected = ('ANY', 'parrot', '1.2.3', True)
243 self.assertEqual(expected, self.mock_xb._InterpretPath(
244 path=path, default_board='parrot', default_version='1.2.3'))
245
246 path = 'parrot'
247 expected = ('ANY', 'parrot', '1.2.3', True)
248 self.assertEqual(expected, self.mock_xb._InterpretPath(
249 path=path, default_version='1.2.3'))
joychen7df67f72013-07-18 14:21:12 -0700250
joychen3cb228e2013-06-12 12:13:13 -0700251 def testTimestampsAndList(self):
252 """Creation and listing of builds according to their timestamps."""
253 # make 3 different timestamp files
joychen921e1fb2013-06-28 11:12:20 -0700254 b_id11 = 'b1/v1'
255 b_id12 = 'b1/v2'
256 b_id23 = 'b2/v3'
257 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id11)
258 time.sleep(0.05)
259 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
260 time.sleep(0.05)
261 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id23)
joychen3cb228e2013-06-12 12:13:13 -0700262
263 # reference second one again
joychen921e1fb2013-06-28 11:12:20 -0700264 time.sleep(0.05)
265 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
joychen3cb228e2013-06-12 12:13:13 -0700266
267 # check that list returns the same 3 things, in last referenced order
joychen921e1fb2013-06-28 11:12:20 -0700268 result = self.mock_xb._ListBuildTimes()
269 self.assertEqual(result[0][0], b_id12)
270 self.assertEqual(result[1][0], b_id23)
271 self.assertEqual(result[2][0], b_id11)
272
273 def testSyncRegistry(self):
274 # check that there are no builds initially
275 result = self.mock_xb._ListBuildTimes()
276 self.assertEqual(len(result), 0)
277
278 # set up the dummy build/images directory with images
279 boards = ['a', 'b']
280 versions = ['v1', 'v2']
281 for b in boards:
282 os.makedirs(os.path.join(self.mock_xb.images_dir, b))
283 for v in versions:
284 os.makedirs(os.path.join(self.mock_xb.images_dir, b, v))
285
286 # Sync and check that they've been added to xBuddy's registry
287 self.mock_xb._SyncRegistryWithBuildImages()
288 result = self.mock_xb._ListBuildTimes()
289 self.assertEqual(len(result), 4)
joychen3cb228e2013-06-12 12:13:13 -0700290
291 ############### Public Methods
292 def testXBuddyCaching(self):
293 """Caching & replacement of timestamp files."""
joychen121fc9b2013-08-02 14:30:30 -0700294 path_a = ('remote', 'a', 'R0', 'test')
295 path_b = ('remote', 'b', 'R0', 'test')
Chris Sosaea734d92013-10-11 11:28:58 -0700296 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
297 self.mox.StubOutWithMock(self.mock_xb, '_Download')
joychen3cb228e2013-06-12 12:13:13 -0700298 self.mox.StubOutWithMock(self.mock_xb, '_Download')
299 for _ in range(8):
Chris Sosa75490802013-09-30 17:21:45 -0700300 self.mock_xb._Download(mox.IsA(str), mox.In(mox.IsA(str)))
joychen3cb228e2013-06-12 12:13:13 -0700301
Chris Sosaea734d92013-10-11 11:28:58 -0700302 # All non-release urls are invalid so we can meet expectations.
303 gsutil_util.GSUtilRun(mox.Not(mox.StrContains('-release')),
304 None).MultipleTimes().AndRaise(
305 gsutil_util.GSUtilError('bad url'))
306 gsutil_util.GSUtilRun(mox.StrContains('-release'), None).MultipleTimes()
307
joychen3cb228e2013-06-12 12:13:13 -0700308 self.mox.ReplayAll()
309
310 # requires default capacity
311 self.assertEqual(self.mock_xb.Capacity(), '5')
312
313 # Get 6 different images: a,b,c,d,e,f
joychen921e1fb2013-06-28 11:12:20 -0700314 images = ['a', 'b', 'c', 'd', 'e', 'f']
315 for c in images:
joychen562699a2013-08-13 15:22:14 -0700316 self.mock_xb.Get(('remote', c, 'R0', 'test'))
joychen921e1fb2013-06-28 11:12:20 -0700317 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700318
319 # check that b,c,d,e,f are still stored
joychen921e1fb2013-06-28 11:12:20 -0700320 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700321 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700322
323 # Flip the list to get reverse chronological order
324 images.reverse()
325 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700326 self.assertEqual(result[i][0], '%s-release/R0' % images[i])
joychen3cb228e2013-06-12 12:13:13 -0700327
328 # Get b,a
joychen562699a2013-08-13 15:22:14 -0700329 self.mock_xb.Get(path_b)
joychen921e1fb2013-06-28 11:12:20 -0700330 time.sleep(0.05)
joychen562699a2013-08-13 15:22:14 -0700331 self.mock_xb.Get(path_a)
joychen921e1fb2013-06-28 11:12:20 -0700332 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700333
334 # check that d,e,f,b,a are still stored
joychen921e1fb2013-06-28 11:12:20 -0700335 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700336 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700337 images_expected = ['a', 'b', 'f', 'e', 'd']
338 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700339 self.assertEqual(result[i][0], '%s-release/R0' % images_expected[i])
joychen3cb228e2013-06-12 12:13:13 -0700340
341 self.mox.VerifyAll()
342
343
344if __name__ == '__main__':
345 unittest.main()