blob: ea86072e4991da3fdc964e9d6f1e7c8c2b2d3ed9 [file] [log] [blame]
joychen3cb228e2013-06-12 12:13:13 -07001#!/usr/bin/python
2
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
9import os
10import shutil
joychen921e1fb2013-06-28 11:12:20 -070011import tempfile
joychen3cb228e2013-06-12 12:13:13 -070012import time
13import unittest
14
15import mox
16
joychenf8f07e22013-07-12 17:45:51 -070017import gsutil_util
joychen3cb228e2013-06-12 12:13:13 -070018import xbuddy
19
20#pylint: disable=W0212
21class xBuddyTest(mox.MoxTestBase):
22 """Regression tests for xbuddy."""
23 def setUp(self):
24 mox.MoxTestBase.setUp(self)
25
joychen921e1fb2013-06-28 11:12:20 -070026 self.static_image_dir = tempfile.mkdtemp('xbuddy_unittest_static')
joychen3cb228e2013-06-12 12:13:13 -070027
joychen921e1fb2013-06-28 11:12:20 -070028 self.mock_xb = xbuddy.XBuddy(
joychen5260b9a2013-07-16 14:48:01 -070029 True,
joychen921e1fb2013-06-28 11:12:20 -070030 static_dir=self.static_image_dir
31 )
32 self.images_dir = tempfile.mkdtemp('xbuddy_unittest_images')
33 self.mock_xb.images_dir = self.images_dir
joychen3cb228e2013-06-12 12:13:13 -070034
35 def tearDown(self):
36 """Removes testing files."""
37 shutil.rmtree(self.static_image_dir)
joychen921e1fb2013-06-28 11:12:20 -070038 shutil.rmtree(self.images_dir)
joychen3cb228e2013-06-12 12:13:13 -070039
40 def testParseBoolean(self):
41 """Check that some common True/False strings are handled."""
42 self.assertEqual(xbuddy.XBuddy.ParseBoolean(None), False)
43 self.assertEqual(xbuddy.XBuddy.ParseBoolean('false'), False)
44 self.assertEqual(xbuddy.XBuddy.ParseBoolean('bs'), False)
45 self.assertEqual(xbuddy.XBuddy.ParseBoolean('true'), True)
46 self.assertEqual(xbuddy.XBuddy.ParseBoolean('y'), True)
47
joychenf8f07e22013-07-12 17:45:51 -070048 def testLookupOfficial(self):
49 """Basic test of _LookupOfficial. Checks that a given suffix is handled."""
50 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
51 gsutil_util.GSUtilRun(mox.IgnoreArg(),
52 mox.IgnoreArg()).AndReturn('v')
53 expected = 'b-s/v'
54 self.mox.ReplayAll()
Chris Sosaea734d92013-10-11 11:28:58 -070055 self.assertEqual(self.mock_xb._LookupOfficial('b', '-s'), expected)
joychenf8f07e22013-07-12 17:45:51 -070056 self.mox.VerifyAll()
57
58 def testLookupChannel(self):
59 """Basic test of _LookupChannel. Checks that a given suffix is handled."""
60 self.mox.StubOutWithMock(gsutil_util, 'GetLatestVersionFromGSDir')
61 mock_data1 = '4100.68.0'
joychen562699a2013-08-13 15:22:14 -070062 gsutil_util.GetLatestVersionFromGSDir(
63 mox.IgnoreArg(), with_release=False).AndReturn(mock_data1)
joychenf8f07e22013-07-12 17:45:51 -070064 mock_data2 = 'R28-4100.68.0'
65 gsutil_util.GetLatestVersionFromGSDir(mox.IgnoreArg()).AndReturn(mock_data2)
66 self.mox.ReplayAll()
67 expected = 'b-release/R28-4100.68.0'
68 self.assertEqual(self.mock_xb._LookupChannel('b'), expected)
69 self.mox.VerifyAll()
70
Chris Sosaea734d92013-10-11 11:28:58 -070071 def testResolveVersionToBuildId_Official(self):
72 """Check _ResolveVersionToBuildId recognizes aliases for official builds."""
joychenf8f07e22013-07-12 17:45:51 -070073 board = 'b'
74
75 # aliases that should be redirected to LookupOfficial
Chris Sosaea734d92013-10-11 11:28:58 -070076
joychenf8f07e22013-07-12 17:45:51 -070077 self.mox.StubOutWithMock(self.mock_xb, '_LookupOfficial')
78 self.mock_xb._LookupOfficial(board)
79 self.mock_xb._LookupOfficial(board, 'paladin')
80
81 self.mox.ReplayAll()
82 version = 'latest-official'
Chris Sosaea734d92013-10-11 11:28:58 -070083 self.mock_xb._ResolveVersionToBuildId(board, version)
joychenf8f07e22013-07-12 17:45:51 -070084 version = 'latest-official-paladin'
Chris Sosaea734d92013-10-11 11:28:58 -070085 self.mock_xb._ResolveVersionToBuildId(board, version)
joychenf8f07e22013-07-12 17:45:51 -070086 self.mox.VerifyAll()
87
Chris Sosaea734d92013-10-11 11:28:58 -070088 def testResolveVersionToBuildId_Channel(self):
89 """Check _ResolveVersionToBuildId recognizes aliases for channels."""
joychenf8f07e22013-07-12 17:45:51 -070090 board = 'b'
91
92 # aliases that should be redirected to LookupChannel
93 self.mox.StubOutWithMock(self.mock_xb, '_LookupChannel')
94 self.mock_xb._LookupChannel(board)
95 self.mock_xb._LookupChannel(board, 'dev')
96
97 self.mox.ReplayAll()
98 version = 'latest'
Chris Sosaea734d92013-10-11 11:28:58 -070099 self.mock_xb._ResolveVersionToBuildId(board, version)
joychenf8f07e22013-07-12 17:45:51 -0700100 version = 'latest-dev'
Chris Sosaea734d92013-10-11 11:28:58 -0700101 self.mock_xb._ResolveVersionToBuildId(board, version)
joychenf8f07e22013-07-12 17:45:51 -0700102 self.mox.VerifyAll()
joychen3cb228e2013-06-12 12:13:13 -0700103
104 def testBasicInterpretPath(self):
105 """Basic checks for splitting a path"""
joychen121fc9b2013-08-02 14:30:30 -0700106 path = 'parrot/R27-2455.0.0/test'
joychen7df67f72013-07-18 14:21:12 -0700107 expected = ('test', 'parrot', 'R27-2455.0.0', True)
joychen121fc9b2013-08-02 14:30:30 -0700108 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
joychen7df67f72013-07-18 14:21:12 -0700109
joychen121fc9b2013-08-02 14:30:30 -0700110 path = 'parrot/R27-2455.0.0/full_payload'
111 expected = ('full_payload', 'parrot', 'R27-2455.0.0', True)
112 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
113
114 path = 'parrot/R27-2455.0.0'
115 expected = ('test', 'parrot', 'R27-2455.0.0', True)
116 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
117
118 path = 'remote/parrot/R27-2455.0.0'
119 expected = ('test', 'parrot', 'R27-2455.0.0', False)
120 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
121
122 path = 'local/parrot/R27-2455.0.0'
123 expected = ('test', 'parrot', 'R27-2455.0.0', True)
124 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
125
126 path = ''
joycheneaf4cfc2013-07-02 08:38:57 -0700127 self.assertRaises(xbuddy.XBuddyException,
128 self.mock_xb._InterpretPath,
joychen121fc9b2013-08-02 14:30:30 -0700129 path=path)
joychen3cb228e2013-06-12 12:13:13 -0700130
joychen121fc9b2013-08-02 14:30:30 -0700131 path = 'local'
joychen7df67f72013-07-18 14:21:12 -0700132 self.assertRaises(xbuddy.XBuddyException,
133 self.mock_xb._InterpretPath,
joychen121fc9b2013-08-02 14:30:30 -0700134 path=path)
joychen7df67f72013-07-18 14:21:12 -0700135
joychenc3944cb2013-08-19 10:42:07 -0700136 path = 'local/parrot/latest/ANY'
137 expected = ('ANY', 'parrot', 'latest', True)
138 self.assertEqual(self.mock_xb._InterpretPath(path=path), expected)
139
joychen7df67f72013-07-18 14:21:12 -0700140
joychen3cb228e2013-06-12 12:13:13 -0700141 def testTimestampsAndList(self):
142 """Creation and listing of builds according to their timestamps."""
143 # make 3 different timestamp files
joychen921e1fb2013-06-28 11:12:20 -0700144 b_id11 = 'b1/v1'
145 b_id12 = 'b1/v2'
146 b_id23 = 'b2/v3'
147 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id11)
148 time.sleep(0.05)
149 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
150 time.sleep(0.05)
151 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id23)
joychen3cb228e2013-06-12 12:13:13 -0700152
153 # reference second one again
joychen921e1fb2013-06-28 11:12:20 -0700154 time.sleep(0.05)
155 xbuddy.Timestamp.UpdateTimestamp(self.mock_xb._timestamp_folder, b_id12)
joychen3cb228e2013-06-12 12:13:13 -0700156
157 # check that list returns the same 3 things, in last referenced order
joychen921e1fb2013-06-28 11:12:20 -0700158 result = self.mock_xb._ListBuildTimes()
159 self.assertEqual(result[0][0], b_id12)
160 self.assertEqual(result[1][0], b_id23)
161 self.assertEqual(result[2][0], b_id11)
162
163 def testSyncRegistry(self):
164 # check that there are no builds initially
165 result = self.mock_xb._ListBuildTimes()
166 self.assertEqual(len(result), 0)
167
168 # set up the dummy build/images directory with images
169 boards = ['a', 'b']
170 versions = ['v1', 'v2']
171 for b in boards:
172 os.makedirs(os.path.join(self.mock_xb.images_dir, b))
173 for v in versions:
174 os.makedirs(os.path.join(self.mock_xb.images_dir, b, v))
175
176 # Sync and check that they've been added to xBuddy's registry
177 self.mock_xb._SyncRegistryWithBuildImages()
178 result = self.mock_xb._ListBuildTimes()
179 self.assertEqual(len(result), 4)
joychen3cb228e2013-06-12 12:13:13 -0700180
181 ############### Public Methods
182 def testXBuddyCaching(self):
183 """Caching & replacement of timestamp files."""
joychen121fc9b2013-08-02 14:30:30 -0700184 path_a = ('remote', 'a', 'R0', 'test')
185 path_b = ('remote', 'b', 'R0', 'test')
Chris Sosaea734d92013-10-11 11:28:58 -0700186 self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun')
187 self.mox.StubOutWithMock(self.mock_xb, '_Download')
joychen3cb228e2013-06-12 12:13:13 -0700188 self.mox.StubOutWithMock(self.mock_xb, '_Download')
189 for _ in range(8):
Chris Sosa75490802013-09-30 17:21:45 -0700190 self.mock_xb._Download(mox.IsA(str), mox.In(mox.IsA(str)))
joychen3cb228e2013-06-12 12:13:13 -0700191
Chris Sosaea734d92013-10-11 11:28:58 -0700192 # All non-release urls are invalid so we can meet expectations.
193 gsutil_util.GSUtilRun(mox.Not(mox.StrContains('-release')),
194 None).MultipleTimes().AndRaise(
195 gsutil_util.GSUtilError('bad url'))
196 gsutil_util.GSUtilRun(mox.StrContains('-release'), None).MultipleTimes()
197
joychen3cb228e2013-06-12 12:13:13 -0700198 self.mox.ReplayAll()
199
200 # requires default capacity
201 self.assertEqual(self.mock_xb.Capacity(), '5')
202
203 # Get 6 different images: a,b,c,d,e,f
joychen921e1fb2013-06-28 11:12:20 -0700204 images = ['a', 'b', 'c', 'd', 'e', 'f']
205 for c in images:
joychen562699a2013-08-13 15:22:14 -0700206 self.mock_xb.Get(('remote', c, 'R0', 'test'))
joychen921e1fb2013-06-28 11:12:20 -0700207 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700208
209 # check that b,c,d,e,f are still stored
joychen921e1fb2013-06-28 11:12:20 -0700210 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700211 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700212
213 # Flip the list to get reverse chronological order
214 images.reverse()
215 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700216 self.assertEqual(result[i][0], '%s-release/R0' % images[i])
joychen3cb228e2013-06-12 12:13:13 -0700217
218 # Get b,a
joychen562699a2013-08-13 15:22:14 -0700219 self.mock_xb.Get(path_b)
joychen921e1fb2013-06-28 11:12:20 -0700220 time.sleep(0.05)
joychen562699a2013-08-13 15:22:14 -0700221 self.mock_xb.Get(path_a)
joychen921e1fb2013-06-28 11:12:20 -0700222 time.sleep(0.05)
joychen3cb228e2013-06-12 12:13:13 -0700223
224 # check that d,e,f,b,a are still stored
joychen921e1fb2013-06-28 11:12:20 -0700225 result = self.mock_xb._ListBuildTimes()
joychen3cb228e2013-06-12 12:13:13 -0700226 self.assertEqual(len(result), 5)
joychen921e1fb2013-06-28 11:12:20 -0700227 images_expected = ['a', 'b', 'f', 'e', 'd']
228 for i in range(5):
joychenf8f07e22013-07-12 17:45:51 -0700229 self.assertEqual(result[i][0], '%s-release/R0' % images_expected[i])
joychen3cb228e2013-06-12 12:13:13 -0700230
231 self.mox.VerifyAll()
232
233
234if __name__ == '__main__':
235 unittest.main()