blob: c5e7ec3bd6e8c263a6f6a424f5fada9f241be6f5 [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):
Gilad Arnold38e828c2015-04-24 13:52:07 -070080 """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'),
Gilad Arnold38e828c2015-04-24 13:52:07 -070089 self.mock_xb.LookupAlias(alias, board='parrot',
90 version='1.2.3'))
Gilad Arnold896c6d82015-03-13 16:20:29 -070091
92 def testLookupAliasSuffix(self):
Gilad Arnold38e828c2015-04-24 13:52:07 -070093 """Tests LookupAlias of location suffix."""
Gilad Arnold896c6d82015-03-13 16:20:29 -070094 alias = 'foobar'
95 suffix = '-random'
96 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
97 self.mock_xb.config.get('LOCATION_SUFFIXES', alias).AndReturn(suffix)
98 self.mock_xb.config.get('PATH_REWRITES', alias).AndRaise(
99 ConfigParser.Error())
100 self.mox.ReplayAll()
101 self.assertEqual((alias, suffix),
Gilad Arnold38e828c2015-04-24 13:52:07 -0700102 self.mock_xb.LookupAlias(alias, board='parrot',
103 version='1.2.3'))
Gilad Arnold896c6d82015-03-13 16:20:29 -0700104
105 def testLookupAliasPathRewriteAndSuffix(self):
Gilad Arnold38e828c2015-04-24 13:52:07 -0700106 """Tests LookupAlias with both path rewrite and suffix."""
Gilad Arnold896c6d82015-03-13 16:20:29 -0700107 alias = 'foobar'
108 path = 'remote/BOARD/VERSION/test'
109 suffix = '-random'
110 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
111 self.mock_xb.config.get('LOCATION_SUFFIXES', alias).AndReturn(suffix)
112 self.mock_xb.config.get('PATH_REWRITES', alias).AndReturn(path)
113 self.mox.ReplayAll()
114 self.assertEqual(('remote/parrot/1.2.3/test', suffix),
Gilad Arnold38e828c2015-04-24 13:52:07 -0700115 self.mock_xb.LookupAlias(alias, board='parrot',
116 version='1.2.3'))
Gilad Arnoldd04fcab2015-02-19 12:00:45 -0800117
Chris Sosaea734d92013-10-11 11:28:58 -0700118 def testResolveVersionToBuildId_Official(self):
119 """Check _ResolveVersionToBuildId recognizes aliases for official builds."""
joychenf8f07e22013-07-12 17:45:51 -0700120 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700121 suffix = '-s'
joychenf8f07e22013-07-12 17:45:51 -0700122
123 # aliases that should be redirected to LookupOfficial
Chris Sosaea734d92013-10-11 11:28:58 -0700124
joychenf8f07e22013-07-12 17:45:51 -0700125 self.mox.StubOutWithMock(self.mock_xb, '_LookupOfficial')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700126 self.mock_xb._LookupOfficial(board, suffix, image_dir=None)
127 self.mock_xb._LookupOfficial(board, suffix,
Simran Basi99e63c02014-05-20 10:39:52 -0700128 image_dir=GS_ALTERNATE_DIR)
129 self.mock_xb._LookupOfficial(board, 'paladin', image_dir=None)
130 self.mock_xb._LookupOfficial(board, 'paladin',
131 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700132
133 self.mox.ReplayAll()
134 version = 'latest-official'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700135 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
136 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700137 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700138 version = 'latest-official-paladin'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700139 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
140 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700141 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700142 self.mox.VerifyAll()
143
Chris Sosaea734d92013-10-11 11:28:58 -0700144 def testResolveVersionToBuildId_Channel(self):
145 """Check _ResolveVersionToBuildId recognizes aliases for channels."""
joychenf8f07e22013-07-12 17:45:51 -0700146 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700147 suffix = '-s'
joychenf8f07e22013-07-12 17:45:51 -0700148
149 # aliases that should be redirected to LookupChannel
150 self.mox.StubOutWithMock(self.mock_xb, '_LookupChannel')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700151 self.mock_xb._LookupChannel(board, suffix, image_dir=None)
152 self.mock_xb._LookupChannel(board, suffix, image_dir=GS_ALTERNATE_DIR)
153 self.mock_xb._LookupChannel(board, suffix, channel='dev', image_dir=None)
154 self.mock_xb._LookupChannel(board, suffix, channel='dev',
155 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700156
157 self.mox.ReplayAll()
158 version = 'latest'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700159 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
160 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700161 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700162 version = 'latest-dev'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700163 self.mock_xb._ResolveVersionToBuildId(board, suffix, version)
164 self.mock_xb._ResolveVersionToBuildId(board, suffix, version,
Simran Basi99e63c02014-05-20 10:39:52 -0700165 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700166 self.mox.VerifyAll()
joychen3cb228e2013-06-12 12:13:13 -0700167
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800168 def testResolveVersionToBuildId_BaseVersion(self):
169 """Check _ResolveVersionToBuildId handles a base version."""
170 board = 'b'
Gilad Arnold896c6d82015-03-13 16:20:29 -0700171 suffix = '-s'
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800172
173 self.mox.StubOutWithMock(self.mock_xb, '_ResolveBuildVersion')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700174 self.mock_xb._ResolveBuildVersion(board, suffix, '1.2.3').AndReturn(
175 'R12-1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800176 self.mox.StubOutWithMock(self.mock_xb, '_RemoteBuildId')
Gilad Arnold896c6d82015-03-13 16:20:29 -0700177 self.mock_xb._RemoteBuildId(board, suffix, 'R12-1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800178 self.mox.ReplayAll()
179
Gilad Arnold896c6d82015-03-13 16:20:29 -0700180 self.mock_xb._ResolveVersionToBuildId(board, suffix, '1.2.3')
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800181 self.mox.VerifyAll()
182
joychen3cb228e2013-06-12 12:13:13 -0700183 def testBasicInterpretPath(self):
184 """Basic checks for splitting a path"""
joychen121fc9b2013-08-02 14:30:30 -0700185 path = 'parrot/R27-2455.0.0/test'
joychen7df67f72013-07-18 14:21:12 -0700186 expected = ('test', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700187 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700188
joychen121fc9b2013-08-02 14:30:30 -0700189 path = 'parrot/R27-2455.0.0/full_payload'
190 expected = ('full_payload', 'parrot', 'R27-2455.0.0', True)
191 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
192
193 path = 'parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800194 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700195 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
196
197 path = 'remote/parrot/R27-2455.0.0'
198 expected = ('test', 'parrot', 'R27-2455.0.0', False)
199 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
200
201 path = 'local/parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800202 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700203 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
204
205 path = ''
Chris Sosa0eecf962014-02-03 14:14:39 -0800206 expected = ('ANY', None, 'latest', True)
207 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen3cb228e2013-06-12 12:13:13 -0700208
joychen121fc9b2013-08-02 14:30:30 -0700209 path = 'local'
Chris Sosa0eecf962014-02-03 14:14:39 -0800210 expected = ('ANY', None, 'latest', True)
211 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700212
joychenc3944cb2013-08-19 10:42:07 -0700213 path = 'local/parrot/latest/ANY'
214 expected = ('ANY', 'parrot', 'latest', True)
215 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
216
Gilad Arnoldd04fcab2015-02-19 12:00:45 -0800217 def testInterpretPathWithDefaults(self):
218 """Test path splitting with default board/version."""
219 path = ''
220 expected = ('ANY', 'parrot', 'latest', True)
221 self.assertEqual(expected, self.mock_xb._InterpretPath(
222 path=path, default_board='parrot'))
223
224 path = ''
225 expected = ('ANY', None, '1.2.3', True)
226 self.assertEqual(expected, self.mock_xb._InterpretPath(
227 path=path, default_version='1.2.3'))
228
229 path = ''
230 expected = ('ANY', 'parrot', '1.2.3', True)
231 self.assertEqual(expected, self.mock_xb._InterpretPath(
232 path=path, default_board='parrot', default_version='1.2.3'))
233
234 path = '1.2.3'
235 expected = ('ANY', None, '1.2.3', True)
236 self.assertEqual(expected, self.mock_xb._InterpretPath(
237 path=path, default_version='1.2.3'))
238
239 path = 'latest'
240 expected = ('ANY', None, 'latest', True)
241 self.assertEqual(expected, self.mock_xb._InterpretPath(
242 path=path, default_version='1.2.3'))
243
244 path = '1.2.3'
245 expected = ('ANY', 'parrot', '1.2.3', True)
246 self.assertEqual(expected, self.mock_xb._InterpretPath(
247 path=path, default_board='parrot', default_version='1.2.3'))
248
249 path = 'parrot'
250 expected = ('ANY', 'parrot', '1.2.3', True)
251 self.assertEqual(expected, self.mock_xb._InterpretPath(
252 path=path, default_version='1.2.3'))
joychen7df67f72013-07-18 14:21:12 -0700253
joychen3cb228e2013-06-12 12:13:13 -0700254 def testTimestampsAndList(self):
255 """Creation and listing of builds according to their timestamps."""
256 # make 3 different timestamp files
joychen921e1fb2013-06-28 11:12:20 -0700257 b_id11 = 'b1/v1'
258 b_id12 = 'b1/v2'
259 b_id23 = 'b2/v3'
260 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id11)
261 time.sleep(0.05)
262 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
263 time.sleep(0.05)
264 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id23)
joychen3cb228e2013-06-12 12:13:13 -0700265
266 # reference second one again
joychen921e1fb2013-06-28 11:12:20 -0700267 time.sleep(0.05)
268 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
joychen3cb228e2013-06-12 12:13:13 -0700269
270 # check that list returns the same 3 things, in last referenced order
joychen921e1fb2013-06-28 11:12:20 -0700271 result = self.mock_xb._ListBuildTimes()
272 self.assertEqual(result[0][0], b_id12)
273 self.assertEqual(result[1][0], b_id23)
274 self.assertEqual(result[2][0], b_id11)
275
276 def testSyncRegistry(self):
277 # check that there are no builds initially
278 result = self.mock_xb._ListBuildTimes()
279 self.assertEqual(len(result), 0)
280
281 # set up the dummy build/images directory with images
282 boards = ['a', 'b']
283 versions = ['v1', 'v2']
284 for b in boards:
285 os.makedirs(os.path.join(self.mock_xb.images_dir, b))
286 for v in versions:
287 os.makedirs(os.path.join(self.mock_xb.images_dir, b, v))
288
289 # Sync and check that they've been added to xBuddy's registry
290 self.mock_xb._SyncRegistryWithBuildImages()
291 result = self.mock_xb._ListBuildTimes()
292 self.assertEqual(len(result), 4)
joychen3cb228e2013-06-12 12:13:13 -0700293
294 ############### Public Methods
295 def testXBuddyCaching(self):
296 """Caching & replacement of timestamp files."""
joychen121fc9b2013-08-02 14:30:30 -0700297 path_a = ('remote', 'a', 'R0', 'test')
298 path_b = ('remote', 'b', 'R0', 'test')
Chris Sosaea734d92013-10-11 11:28:58 -0700299 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
300 self.mox.StubOutWithMock(self.mock_xb, '_Download')
joychen3cb228e2013-06-12 12:13:13 -0700301 self.mox.StubOutWithMock(self.mock_xb, '_Download')
302 for _ in range(8):
Chris Sosa75490802013-09-30 17:21:45 -0700303 self.mock_xb._Download(mox.IsA(str), mox.In(mox.IsA(str)))
joychen3cb228e2013-06-12 12:13:13 -0700304
Chris Sosaea734d92013-10-11 11:28:58 -0700305 # All non-release urls are invalid so we can meet expectations.
306 gsutil_util.GSUtilRun(mox.Not(mox.StrContains('-release')),
307 None).MultipleTimes().AndRaise(
308 gsutil_util.GSUtilError('bad url'))
309 gsutil_util.GSUtilRun(mox.StrContains('-release'), None).MultipleTimes()
310
joychen3cb228e2013-06-12 12:13:13 -0700311 self.mox.ReplayAll()
312
313 # requires default capacity
314 self.assertEqual(self.mock_xb.Capacity(), '5')
315
316 # Get 6 different images: a,b,c,d,e,f
joychen921e1fb2013-06-28 11:12:20 -0700317 images = ['a', 'b', 'c', 'd', 'e', 'f']
318 for c in images:
joychen562699a2013-08-13 15:22:14 -0700319 self.mock_xb.Get(('remote', c, 'R0', 'test'))
joychen921e1fb2013-06-28 11:12:20 -0700320 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700321
322 # check that b,c,d,e,f are still stored
joychen921e1fb2013-06-28 11:12:20 -0700323 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700324 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700325
326 # Flip the list to get reverse chronological order
327 images.reverse()
328 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700329 self.assertEqual(result[i][0], '%s-release/R0' % images[i])
joychen3cb228e2013-06-12 12:13:13 -0700330
331 # Get b,a
joychen562699a2013-08-13 15:22:14 -0700332 self.mock_xb.Get(path_b)
joychen921e1fb2013-06-28 11:12:20 -0700333 time.sleep(0.05)
joychen562699a2013-08-13 15:22:14 -0700334 self.mock_xb.Get(path_a)
joychen921e1fb2013-06-28 11:12:20 -0700335 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700336
337 # check that d,e,f,b,a are still stored
joychen921e1fb2013-06-28 11:12:20 -0700338 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700339 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700340 images_expected = ['a', 'b', 'f', 'e', 'd']
341 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700342 self.assertEqual(result[i][0], '%s-release/R0' % images_expected[i])
joychen3cb228e2013-06-12 12:13:13 -0700343
344 self.mox.VerifyAll()
345
346
347if __name__ == '__main__':
348 unittest.main()