blob: e31e18eb063ec7161c0714f3c85564d0cb24e9ef [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
joychen3cb228e2013-06-12 12:13:13 -070011import os
12import shutil
joychen921e1fb2013-06-28 11:12:20 -070013import tempfile
joychen3cb228e2013-06-12 12:13:13 -070014import time
15import unittest
16
17import mox
18
joychenf8f07e22013-07-12 17:45:51 -070019import gsutil_util
joychen3cb228e2013-06-12 12:13:13 -070020import xbuddy
21
22#pylint: disable=W0212
Simran Basi99e63c02014-05-20 10:39:52 -070023
24GS_ALTERNATE_DIR = 'gs://chromeos-alternate-archive/'
25
26
joychen3cb228e2013-06-12 12:13:13 -070027class xBuddyTest(mox.MoxTestBase):
28 """Regression tests for xbuddy."""
29 def setUp(self):
30 mox.MoxTestBase.setUp(self)
31
joychen921e1fb2013-06-28 11:12:20 -070032 self.static_image_dir = tempfile.mkdtemp('xbuddy_unittest_static')
joychen3cb228e2013-06-12 12:13:13 -070033
joychen921e1fb2013-06-28 11:12:20 -070034 self.mock_xb = xbuddy.XBuddy(
Gilad Arnold5f46d8e2015-02-19 12:17:55 -080035 True,
36 static_dir=self.static_image_dir
joychen921e1fb2013-06-28 11:12:20 -070037 )
38 self.images_dir = tempfile.mkdtemp('xbuddy_unittest_images')
39 self.mock_xb.images_dir = self.images_dir
joychen3cb228e2013-06-12 12:13:13 -070040
41 def tearDown(self):
42 """Removes testing files."""
43 shutil.rmtree(self.static_image_dir)
joychen921e1fb2013-06-28 11:12:20 -070044 shutil.rmtree(self.images_dir)
joychen3cb228e2013-06-12 12:13:13 -070045
46 def testParseBoolean(self):
47 """Check that some common True/False strings are handled."""
48 self.assertEqual(xbuddy.XBuddy.ParseBoolean(None), False)
49 self.assertEqual(xbuddy.XBuddy.ParseBoolean('false'), False)
50 self.assertEqual(xbuddy.XBuddy.ParseBoolean('bs'), False)
51 self.assertEqual(xbuddy.XBuddy.ParseBoolean('true'), True)
52 self.assertEqual(xbuddy.XBuddy.ParseBoolean('y'), True)
53
joychenf8f07e22013-07-12 17:45:51 -070054 def testLookupOfficial(self):
55 """Basic test of _LookupOfficial. Checks that a given suffix is handled."""
56 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
57 gsutil_util.GSUtilRun(mox.IgnoreArg(),
58 mox.IgnoreArg()).AndReturn('v')
59 expected = 'b-s/v'
60 self.mox.ReplayAll()
Chris Sosaea734d92013-10-11 11:28:58 -070061 self.assertEqual(self.mock_xb._LookupOfficial('b', '-s'), expected)
joychenf8f07e22013-07-12 17:45:51 -070062 self.mox.VerifyAll()
63
64 def testLookupChannel(self):
65 """Basic test of _LookupChannel. Checks that a given suffix is handled."""
66 self.mox.StubOutWithMock(gsutil_util, 'GetLatestVersionFromGSDir')
67 mock_data1 = '4100.68.0'
joychen562699a2013-08-13 15:22:14 -070068 gsutil_util.GetLatestVersionFromGSDir(
69 mox.IgnoreArg(), with_release=False).AndReturn(mock_data1)
joychenf8f07e22013-07-12 17:45:51 -070070 mock_data2 = 'R28-4100.68.0'
71 gsutil_util.GetLatestVersionFromGSDir(mox.IgnoreArg()).AndReturn(mock_data2)
72 self.mox.ReplayAll()
73 expected = 'b-release/R28-4100.68.0'
Simran Basi99e63c02014-05-20 10:39:52 -070074 self.assertEqual(self.mock_xb._LookupChannel('b'),
75 expected)
joychenf8f07e22013-07-12 17:45:51 -070076 self.mox.VerifyAll()
77
Gilad Arnoldd04fcab2015-02-19 12:00:45 -080078 def testLookupAlias(self):
79 """Tests _LookupAlias, including keyword substitution."""
80 alias = 'foobar'
81 path = 'remote/BOARD/VERSION/test'
82 self.mox.StubOutWithMock(self.mock_xb.config, 'get')
83 self.mock_xb.config.get(mox.IgnoreArg(), alias).AndReturn(path)
84 self.mox.ReplayAll()
85 self.assertEqual('remote/parrot/1.2.3/test',
86 self.mock_xb._LookupAlias(alias, 'parrot', '1.2.3'))
87
Chris Sosaea734d92013-10-11 11:28:58 -070088 def testResolveVersionToBuildId_Official(self):
89 """Check _ResolveVersionToBuildId recognizes aliases for official builds."""
joychenf8f07e22013-07-12 17:45:51 -070090 board = 'b'
91
92 # aliases that should be redirected to LookupOfficial
Chris Sosaea734d92013-10-11 11:28:58 -070093
joychenf8f07e22013-07-12 17:45:51 -070094 self.mox.StubOutWithMock(self.mock_xb, '_LookupOfficial')
Simran Basi99e63c02014-05-20 10:39:52 -070095 self.mock_xb._LookupOfficial(board, image_dir=None)
96 self.mock_xb._LookupOfficial(board,
97 image_dir=GS_ALTERNATE_DIR)
98 self.mock_xb._LookupOfficial(board, 'paladin', image_dir=None)
99 self.mock_xb._LookupOfficial(board, 'paladin',
100 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700101
102 self.mox.ReplayAll()
103 version = 'latest-official'
Chris Sosaea734d92013-10-11 11:28:58 -0700104 self.mock_xb._ResolveVersionToBuildId(board, version)
Simran Basi99e63c02014-05-20 10:39:52 -0700105 self.mock_xb._ResolveVersionToBuildId(board, version,
106 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700107 version = 'latest-official-paladin'
Chris Sosaea734d92013-10-11 11:28:58 -0700108 self.mock_xb._ResolveVersionToBuildId(board, version)
Simran Basi99e63c02014-05-20 10:39:52 -0700109 self.mock_xb._ResolveVersionToBuildId(board, version,
110 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700111 self.mox.VerifyAll()
112
Chris Sosaea734d92013-10-11 11:28:58 -0700113 def testResolveVersionToBuildId_Channel(self):
114 """Check _ResolveVersionToBuildId recognizes aliases for channels."""
joychenf8f07e22013-07-12 17:45:51 -0700115 board = 'b'
116
117 # aliases that should be redirected to LookupChannel
118 self.mox.StubOutWithMock(self.mock_xb, '_LookupChannel')
Simran Basi99e63c02014-05-20 10:39:52 -0700119 self.mock_xb._LookupChannel(board, image_dir=None)
120 self.mock_xb._LookupChannel(board, image_dir=GS_ALTERNATE_DIR)
121 self.mock_xb._LookupChannel(board, 'dev', image_dir=None)
122 self.mock_xb._LookupChannel(board, 'dev', image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700123
124 self.mox.ReplayAll()
125 version = 'latest'
Chris Sosaea734d92013-10-11 11:28:58 -0700126 self.mock_xb._ResolveVersionToBuildId(board, version)
Simran Basi99e63c02014-05-20 10:39:52 -0700127 self.mock_xb._ResolveVersionToBuildId(board, version,
128 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700129 version = 'latest-dev'
Chris Sosaea734d92013-10-11 11:28:58 -0700130 self.mock_xb._ResolveVersionToBuildId(board, version)
Simran Basi99e63c02014-05-20 10:39:52 -0700131 self.mock_xb._ResolveVersionToBuildId(board, version,
132 image_dir=GS_ALTERNATE_DIR)
joychenf8f07e22013-07-12 17:45:51 -0700133 self.mox.VerifyAll()
joychen3cb228e2013-06-12 12:13:13 -0700134
Gilad Arnold869e8ab2015-02-19 23:34:49 -0800135 def testResolveVersionToBuildId_BaseVersion(self):
136 """Check _ResolveVersionToBuildId handles a base version."""
137 board = 'b'
138
139 self.mox.StubOutWithMock(self.mock_xb, '_ResolveBuildVersion')
140 self.mock_xb._ResolveBuildVersion(board, '1.2.3').AndReturn('R12-1.2.3')
141 self.mox.StubOutWithMock(self.mock_xb, '_RemoteBuildId')
142 self.mock_xb._RemoteBuildId(board, 'R12-1.2.3')
143 self.mox.ReplayAll()
144
145 self.mock_xb._ResolveVersionToBuildId(board, '1.2.3')
146 self.mox.VerifyAll()
147
joychen3cb228e2013-06-12 12:13:13 -0700148 def testBasicInterpretPath(self):
149 """Basic checks for splitting a path"""
joychen121fc9b2013-08-02 14:30:30 -0700150 path = 'parrot/R27-2455.0.0/test'
joychen7df67f72013-07-18 14:21:12 -0700151 expected = ('test', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700152 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700153
joychen121fc9b2013-08-02 14:30:30 -0700154 path = 'parrot/R27-2455.0.0/full_payload'
155 expected = ('full_payload', 'parrot', 'R27-2455.0.0', True)
156 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
157
158 path = 'parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800159 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700160 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
161
162 path = 'remote/parrot/R27-2455.0.0'
163 expected = ('test', 'parrot', 'R27-2455.0.0', False)
164 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
165
166 path = 'local/parrot/R27-2455.0.0'
Chris Sosa0eecf962014-02-03 14:14:39 -0800167 expected = ('ANY', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700168 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
169
170 path = ''
Chris Sosa0eecf962014-02-03 14:14:39 -0800171 expected = ('ANY', None, 'latest', True)
172 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen3cb228e2013-06-12 12:13:13 -0700173
joychen121fc9b2013-08-02 14:30:30 -0700174 path = 'local'
Chris Sosa0eecf962014-02-03 14:14:39 -0800175 expected = ('ANY', None, 'latest', True)
176 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700177
joychenc3944cb2013-08-19 10:42:07 -0700178 path = 'local/parrot/latest/ANY'
179 expected = ('ANY', 'parrot', 'latest', True)
180 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
181
Gilad Arnoldd04fcab2015-02-19 12:00:45 -0800182 def testInterpretPathWithDefaults(self):
183 """Test path splitting with default board/version."""
184 path = ''
185 expected = ('ANY', 'parrot', 'latest', True)
186 self.assertEqual(expected, self.mock_xb._InterpretPath(
187 path=path, default_board='parrot'))
188
189 path = ''
190 expected = ('ANY', None, '1.2.3', True)
191 self.assertEqual(expected, self.mock_xb._InterpretPath(
192 path=path, default_version='1.2.3'))
193
194 path = ''
195 expected = ('ANY', 'parrot', '1.2.3', True)
196 self.assertEqual(expected, self.mock_xb._InterpretPath(
197 path=path, default_board='parrot', default_version='1.2.3'))
198
199 path = '1.2.3'
200 expected = ('ANY', None, '1.2.3', True)
201 self.assertEqual(expected, self.mock_xb._InterpretPath(
202 path=path, default_version='1.2.3'))
203
204 path = 'latest'
205 expected = ('ANY', None, 'latest', True)
206 self.assertEqual(expected, self.mock_xb._InterpretPath(
207 path=path, default_version='1.2.3'))
208
209 path = '1.2.3'
210 expected = ('ANY', 'parrot', '1.2.3', True)
211 self.assertEqual(expected, self.mock_xb._InterpretPath(
212 path=path, default_board='parrot', default_version='1.2.3'))
213
214 path = 'parrot'
215 expected = ('ANY', 'parrot', '1.2.3', True)
216 self.assertEqual(expected, self.mock_xb._InterpretPath(
217 path=path, default_version='1.2.3'))
joychen7df67f72013-07-18 14:21:12 -0700218
joychen3cb228e2013-06-12 12:13:13 -0700219 def testTimestampsAndList(self):
220 """Creation and listing of builds according to their timestamps."""
221 # make 3 different timestamp files
joychen921e1fb2013-06-28 11:12:20 -0700222 b_id11 = 'b1/v1'
223 b_id12 = 'b1/v2'
224 b_id23 = 'b2/v3'
225 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id11)
226 time.sleep(0.05)
227 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
228 time.sleep(0.05)
229 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id23)
joychen3cb228e2013-06-12 12:13:13 -0700230
231 # reference second one again
joychen921e1fb2013-06-28 11:12:20 -0700232 time.sleep(0.05)
233 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
joychen3cb228e2013-06-12 12:13:13 -0700234
235 # check that list returns the same 3 things, in last referenced order
joychen921e1fb2013-06-28 11:12:20 -0700236 result = self.mock_xb._ListBuildTimes()
237 self.assertEqual(result[0][0], b_id12)
238 self.assertEqual(result[1][0], b_id23)
239 self.assertEqual(result[2][0], b_id11)
240
241 def testSyncRegistry(self):
242 # check that there are no builds initially
243 result = self.mock_xb._ListBuildTimes()
244 self.assertEqual(len(result), 0)
245
246 # set up the dummy build/images directory with images
247 boards = ['a', 'b']
248 versions = ['v1', 'v2']
249 for b in boards:
250 os.makedirs(os.path.join(self.mock_xb.images_dir, b))
251 for v in versions:
252 os.makedirs(os.path.join(self.mock_xb.images_dir, b, v))
253
254 # Sync and check that they've been added to xBuddy's registry
255 self.mock_xb._SyncRegistryWithBuildImages()
256 result = self.mock_xb._ListBuildTimes()
257 self.assertEqual(len(result), 4)
joychen3cb228e2013-06-12 12:13:13 -0700258
259 ############### Public Methods
260 def testXBuddyCaching(self):
261 """Caching & replacement of timestamp files."""
joychen121fc9b2013-08-02 14:30:30 -0700262 path_a = ('remote', 'a', 'R0', 'test')
263 path_b = ('remote', 'b', 'R0', 'test')
Chris Sosaea734d92013-10-11 11:28:58 -0700264 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
265 self.mox.StubOutWithMock(self.mock_xb, '_Download')
joychen3cb228e2013-06-12 12:13:13 -0700266 self.mox.StubOutWithMock(self.mock_xb, '_Download')
267 for _ in range(8):
Chris Sosa75490802013-09-30 17:21:45 -0700268 self.mock_xb._Download(mox.IsA(str), mox.In(mox.IsA(str)))
joychen3cb228e2013-06-12 12:13:13 -0700269
Chris Sosaea734d92013-10-11 11:28:58 -0700270 # All non-release urls are invalid so we can meet expectations.
271 gsutil_util.GSUtilRun(mox.Not(mox.StrContains('-release')),
272 None).MultipleTimes().AndRaise(
273 gsutil_util.GSUtilError('bad url'))
274 gsutil_util.GSUtilRun(mox.StrContains('-release'), None).MultipleTimes()
275
joychen3cb228e2013-06-12 12:13:13 -0700276 self.mox.ReplayAll()
277
278 # requires default capacity
279 self.assertEqual(self.mock_xb.Capacity(), '5')
280
281 # Get 6 different images: a,b,c,d,e,f
joychen921e1fb2013-06-28 11:12:20 -0700282 images = ['a', 'b', 'c', 'd', 'e', 'f']
283 for c in images:
joychen562699a2013-08-13 15:22:14 -0700284 self.mock_xb.Get(('remote', c, 'R0', 'test'))
joychen921e1fb2013-06-28 11:12:20 -0700285 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700286
287 # check that b,c,d,e,f are still stored
joychen921e1fb2013-06-28 11:12:20 -0700288 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700289 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700290
291 # Flip the list to get reverse chronological order
292 images.reverse()
293 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700294 self.assertEqual(result[i][0], '%s-release/R0' % images[i])
joychen3cb228e2013-06-12 12:13:13 -0700295
296 # Get b,a
joychen562699a2013-08-13 15:22:14 -0700297 self.mock_xb.Get(path_b)
joychen921e1fb2013-06-28 11:12:20 -0700298 time.sleep(0.05)
joychen562699a2013-08-13 15:22:14 -0700299 self.mock_xb.Get(path_a)
joychen921e1fb2013-06-28 11:12:20 -0700300 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700301
302 # check that d,e,f,b,a are still stored
joychen921e1fb2013-06-28 11:12:20 -0700303 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700304 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700305 images_expected = ['a', 'b', 'f', 'e', 'd']
306 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700307 self.assertEqual(result[i][0], '%s-release/R0' % images_expected[i])
joychen3cb228e2013-06-12 12:13:13 -0700308
309 self.mox.VerifyAll()
310
311
312if __name__ == '__main__':
313 unittest.main()