blob: 143d302e05348d5ee75c057c39b8429fb61a4f28 [file] [log] [blame]
Allen Li4ad0c3b2017-05-05 13:12:11 -07001#!/usr/bin/python
Michael Tang97d188c2016-06-25 11:18:42 -07002# Copyright 2016 The Chromium OS Authors. All rights reserved.
J. Richard Barnetteea785362014-03-17 16:00:53 -07003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Keith Haddow5ba5fb82016-11-09 11:39:36 -08006import __builtin__
J. Richard Barnetteea785362014-03-17 16:00:53 -07007import Queue
Michael Tang97d188c2016-06-25 11:18:42 -07008import base64
J. Richard Barnetteea785362014-03-17 16:00:53 -07009import datetime
10import logging
11import os
12import shutil
J. Richard Barnette2e443ef2014-05-20 12:31:35 -070013import signal
Laurence Goodbyca7726d2017-02-14 17:09:07 -080014import stat
J. Richard Barnetteea785362014-03-17 16:00:53 -070015import sys
16import tempfile
17import time
18import unittest
19
Allen Li9579b382017-05-05 17:07:43 -070020import mock
J. Richard Barnetteea785362014-03-17 16:00:53 -070021import mox
22
23import common
Allen Li5ed7e632017-02-03 16:31:33 -080024from autotest_lib.client.common_lib import global_config
Dan Shi1b4c7c32015-10-05 10:38:57 -070025from autotest_lib.client.common_lib import time_utils
26from autotest_lib.client.common_lib import utils
Prathmesh Prabhubeb9e012017-01-30 16:18:39 -080027from autotest_lib.site_utils import gs_offloader
28from autotest_lib.site_utils import job_directories
Ningning Xia2d981ee2016-07-06 17:59:54 -070029from autotest_lib.tko import models
Allen Lib41527d2017-06-22 17:28:00 -070030from autotest_lib.utils import gslib
31from chromite.lib import timeout_util
Jakob Juelich24f22c22014-09-26 11:46:11 -070032
J. Richard Barnetteea785362014-03-17 16:00:53 -070033# Test value to use for `days_old`, if nothing else is required.
34_TEST_EXPIRATION_AGE = 7
35
36# When constructing sample time values for testing expiration,
37# allow this many seconds between the expiration time and the
38# current time.
39_MARGIN_SECS = 10.0
40
41
42def _get_options(argv):
43 """Helper function to exercise command line parsing.
44
45 @param argv Value of sys.argv to be parsed.
46
47 """
48 sys.argv = ['bogus.py'] + argv
49 return gs_offloader.parse_options()
50
51
Laurence Goodbyca7726d2017-02-14 17:09:07 -080052def is_fifo(path):
Allen Li93585382017-05-05 14:24:53 -070053 """Determines whether a path is a fifo.
54
55 @param path: fifo path string.
56 """
Laurence Goodbyca7726d2017-02-14 17:09:07 -080057 return stat.S_ISFIFO(os.lstat(path).st_mode)
58
59
Simran Basidd129972014-09-11 14:34:49 -070060class OffloaderOptionsTests(mox.MoxTestBase):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -070061 """Tests for the `Offloader` constructor.
62
63 Tests that offloader instance fields are set as expected
64 for given command line options.
65
66 """
67
68 _REGULAR_ONLY = set([job_directories.RegularJobDirectory])
69 _SPECIAL_ONLY = set([job_directories.SpecialJobDirectory])
70 _BOTH = _REGULAR_ONLY | _SPECIAL_ONLY
J. Richard Barnetteea785362014-03-17 16:00:53 -070071
Jakob Juelich24f22c22014-09-26 11:46:11 -070072
Simran Basidd129972014-09-11 14:34:49 -070073 def setUp(self):
74 super(OffloaderOptionsTests, self).setUp()
75 self.mox.StubOutWithMock(utils, 'get_offload_gsuri')
Simran Basif3e305f2014-10-03 14:43:53 -070076 gs_offloader.GS_OFFLOADING_ENABLED = True
Michael Tang0df2eb42016-05-13 19:06:54 -070077 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
Simran Basidd129972014-09-11 14:34:49 -070078
Jakob Juelich24f22c22014-09-26 11:46:11 -070079
Allen Lib41527d2017-06-22 17:28:00 -070080 def _mock_get_sub_offloader(self, is_moblab, multiprocessing=False,
Keith Haddow5ba5fb82016-11-09 11:39:36 -080081 pubsub_topic=None, delete_age=0):
Simran Basidd129972014-09-11 14:34:49 -070082 """Mock the process of getting the offload_dir function."""
83 if is_moblab:
84 expected_gsuri = '%sresults/%s/%s/' % (
85 global_config.global_config.get_config_value(
86 'CROS', 'image_storage_server'),
87 'Fa:ke:ma:c0:12:34', 'rand0m-uu1d')
88 else:
89 expected_gsuri = utils.DEFAULT_OFFLOAD_GSURI
90 utils.get_offload_gsuri().AndReturn(expected_gsuri)
Allen Lib41527d2017-06-22 17:28:00 -070091 sub_offloader = gs_offloader.GSOffloader(expected_gsuri,
Keith Haddow5ba5fb82016-11-09 11:39:36 -080092 multiprocessing, delete_age, pubsub_topic)
Allen Lib41527d2017-06-22 17:28:00 -070093 self.mox.StubOutWithMock(gs_offloader, 'GSOffloader')
94 gs_offloader.GSOffloader(expected_gsuri, multiprocessing,
95 delete_age, pubsub_topic).AndReturn(sub_offloader)
Simran Basidd129972014-09-11 14:34:49 -070096 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -070097 return sub_offloader
Simran Basidd129972014-09-11 14:34:49 -070098
Jakob Juelich24f22c22014-09-26 11:46:11 -070099
J. Richard Barnetteea785362014-03-17 16:00:53 -0700100 def test_process_no_options(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700101 """Test default offloader options."""
Allen Lib41527d2017-06-22 17:28:00 -0700102 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700103 offloader = gs_offloader.Offloader(_get_options([]))
104 self.assertEqual(set(offloader._jobdir_classes),
105 self._REGULAR_ONLY)
106 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700107 self.assertEqual(offloader._gs_offloader,
108 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800109 self.assertEqual(offloader._upload_age_limit, 0)
110 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700111
Jakob Juelich24f22c22014-09-26 11:46:11 -0700112
J. Richard Barnetteea785362014-03-17 16:00:53 -0700113 def test_process_all_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700114 """Test offloader handling for the --all option."""
Allen Lib41527d2017-06-22 17:28:00 -0700115 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700116 offloader = gs_offloader.Offloader(_get_options(['--all']))
117 self.assertEqual(set(offloader._jobdir_classes), self._BOTH)
118 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700119 self.assertEqual(offloader._gs_offloader,
120 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800121 self.assertEqual(offloader._upload_age_limit, 0)
122 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700123
Jakob Juelich24f22c22014-09-26 11:46:11 -0700124
J. Richard Barnetteea785362014-03-17 16:00:53 -0700125 def test_process_hosts_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700126 """Test offloader handling for the --hosts option."""
Allen Lib41527d2017-06-22 17:28:00 -0700127 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700128 offloader = gs_offloader.Offloader(
129 _get_options(['--hosts']))
130 self.assertEqual(set(offloader._jobdir_classes),
131 self._SPECIAL_ONLY)
132 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700133 self.assertEqual(offloader._gs_offloader,
134 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800135 self.assertEqual(offloader._upload_age_limit, 0)
136 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700137
Jakob Juelich24f22c22014-09-26 11:46:11 -0700138
J. Richard Barnetteea785362014-03-17 16:00:53 -0700139 def test_parallelism_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700140 """Test offloader handling for the --parallelism option."""
Allen Lib41527d2017-06-22 17:28:00 -0700141 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700142 offloader = gs_offloader.Offloader(
143 _get_options(['--parallelism', '2']))
144 self.assertEqual(set(offloader._jobdir_classes),
145 self._REGULAR_ONLY)
146 self.assertEqual(offloader._processes, 2)
Allen Lib41527d2017-06-22 17:28:00 -0700147 self.assertEqual(offloader._gs_offloader,
148 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800149 self.assertEqual(offloader._upload_age_limit, 0)
150 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700151
Jakob Juelich24f22c22014-09-26 11:46:11 -0700152
J. Richard Barnetteea785362014-03-17 16:00:53 -0700153 def test_delete_only_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700154 """Test offloader handling for the --delete_only option."""
155 offloader = gs_offloader.Offloader(
156 _get_options(['--delete_only']))
157 self.assertEqual(set(offloader._jobdir_classes),
158 self._REGULAR_ONLY)
159 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700160 self.assertIsInstance(offloader._gs_offloader,
161 gs_offloader.FakeGSOffloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800162 self.assertEqual(offloader._upload_age_limit, 0)
163 self.assertEqual(offloader._delete_age_limit, 0)
Michael Tang97d188c2016-06-25 11:18:42 -0700164 self.assertIsNone(offloader._pubsub_topic)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700165
Jakob Juelich24f22c22014-09-26 11:46:11 -0700166
Simran Basidf4751e2014-10-10 14:19:22 -0700167 def test_days_old_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700168 """Test offloader handling for the --days_old option."""
Allen Lib41527d2017-06-22 17:28:00 -0700169 sub_offloader = self._mock_get_sub_offloader(False, delete_age=7)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700170 offloader = gs_offloader.Offloader(
171 _get_options(['--days_old', '7']))
172 self.assertEqual(set(offloader._jobdir_classes),
173 self._REGULAR_ONLY)
174 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700175 self.assertEqual(offloader._gs_offloader,
176 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800177 self.assertEqual(offloader._upload_age_limit, 7)
178 self.assertEqual(offloader._delete_age_limit, 7)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700179
Jakob Juelich24f22c22014-09-26 11:46:11 -0700180
Simran Basidd129972014-09-11 14:34:49 -0700181 def test_moblab_gsuri_generation(self):
182 """Test offloader construction for Moblab."""
Allen Lib41527d2017-06-22 17:28:00 -0700183 sub_offloader = self._mock_get_sub_offloader(True)
Simran Basidd129972014-09-11 14:34:49 -0700184 offloader = gs_offloader.Offloader(_get_options([]))
185 self.assertEqual(set(offloader._jobdir_classes),
186 self._REGULAR_ONLY)
187 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700188 self.assertEqual(offloader._gs_offloader,
189 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800190 self.assertEqual(offloader._upload_age_limit, 0)
191 self.assertEqual(offloader._delete_age_limit, 0)
Simran Basidd129972014-09-11 14:34:49 -0700192
J. Richard Barnetteea785362014-03-17 16:00:53 -0700193
Simran Basif3e305f2014-10-03 14:43:53 -0700194 def test_globalconfig_offloading_flag(self):
195 """Test enabling of --delete_only via global_config."""
196 gs_offloader.GS_OFFLOADING_ENABLED = False
197 offloader = gs_offloader.Offloader(
198 _get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700199 self.assertIsInstance(offloader._gs_offloader,
200 gs_offloader.FakeGSOffloader)
Simran Basif3e305f2014-10-03 14:43:53 -0700201
Michael Tang0df2eb42016-05-13 19:06:54 -0700202 def test_offloader_multiprocessing_flag_set(self):
203 """Test multiprocessing is set."""
Allen Lib41527d2017-06-22 17:28:00 -0700204 sub_offloader = self._mock_get_sub_offloader(True, True)
Michael Tang0df2eb42016-05-13 19:06:54 -0700205 offloader = gs_offloader.Offloader(_get_options(['-m']))
Allen Lib41527d2017-06-22 17:28:00 -0700206 self.assertEqual(offloader._gs_offloader,
207 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700208 self.mox.VerifyAll()
209
210 def test_offloader_multiprocessing_flag_not_set_default_false(self):
211 """Test multiprocessing is set."""
212 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
Allen Lib41527d2017-06-22 17:28:00 -0700213 sub_offloader = self._mock_get_sub_offloader(True, False)
Michael Tang0df2eb42016-05-13 19:06:54 -0700214 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700215 self.assertEqual(offloader._gs_offloader,
216 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700217 self.mox.VerifyAll()
218
219 def test_offloader_multiprocessing_flag_not_set_default_true(self):
220 """Test multiprocessing is set."""
221 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = True
Allen Lib41527d2017-06-22 17:28:00 -0700222 sub_offloader = self._mock_get_sub_offloader(True, True)
Michael Tang0df2eb42016-05-13 19:06:54 -0700223 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700224 self.assertEqual(offloader._gs_offloader,
225 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700226 self.mox.VerifyAll()
227
Michael Tang97d188c2016-06-25 11:18:42 -0700228 def test_offloader_pubsub_topic_not_set(self):
229 """Test multiprocessing is set."""
Allen Lib41527d2017-06-22 17:28:00 -0700230 sub_offloader = self._mock_get_sub_offloader(True, False)
Michael Tang97d188c2016-06-25 11:18:42 -0700231 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700232 self.assertEqual(offloader._gs_offloader,
233 sub_offloader)
Michael Tang97d188c2016-06-25 11:18:42 -0700234 self.mox.VerifyAll()
235
236 def test_offloader_pubsub_topic_set(self):
237 """Test multiprocessing is set."""
Allen Lib41527d2017-06-22 17:28:00 -0700238 sub_offloader = self._mock_get_sub_offloader(True, False, 'test-topic')
Michael Tang97d188c2016-06-25 11:18:42 -0700239 offloader = gs_offloader.Offloader(_get_options(['-t', 'test-topic']))
Allen Lib41527d2017-06-22 17:28:00 -0700240 self.assertEqual(offloader._gs_offloader,
241 sub_offloader)
Michael Tang97d188c2016-06-25 11:18:42 -0700242 self.mox.VerifyAll()
243
Simran Basif3e305f2014-10-03 14:43:53 -0700244
J. Richard Barnetteea785362014-03-17 16:00:53 -0700245def _make_timestamp(age_limit, is_expired):
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800246 """Create a timestamp for use by `job_directories.is_job_expired()`.
J. Richard Barnetteea785362014-03-17 16:00:53 -0700247
248 The timestamp will meet the syntactic requirements for
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800249 timestamps used as input to `is_job_expired()`. If
J. Richard Barnetteea785362014-03-17 16:00:53 -0700250 `is_expired` is true, the timestamp will be older than
251 `age_limit` days before the current time; otherwise, the
252 date will be younger.
253
254 @param age_limit The number of days before expiration of the
255 target timestamp.
256 @param is_expired Whether the timestamp should be expired
257 relative to `age_limit`.
258
259 """
260 seconds = -_MARGIN_SECS
261 if is_expired:
262 seconds = -seconds
263 delta = datetime.timedelta(days=age_limit, seconds=seconds)
264 reference_time = datetime.datetime.now() - delta
Dan Shidfea3682014-08-10 23:38:40 -0700265 return reference_time.strftime(time_utils.TIME_FMT)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700266
267
268class JobExpirationTests(unittest.TestCase):
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800269 """Tests to exercise `job_directories.is_job_expired()`."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700270
271 def test_expired(self):
272 """Test detection of an expired job."""
273 timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, True)
274 self.assertTrue(
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800275 job_directories.is_job_expired(
J. Richard Barnetteea785362014-03-17 16:00:53 -0700276 _TEST_EXPIRATION_AGE, timestamp))
277
278
279 def test_alive(self):
280 """Test detection of a job that's not expired."""
281 # N.B. This test may fail if its run time exceeds more than
282 # about _MARGIN_SECS seconds.
283 timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, False)
284 self.assertFalse(
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800285 job_directories.is_job_expired(
J. Richard Barnetteea785362014-03-17 16:00:53 -0700286 _TEST_EXPIRATION_AGE, timestamp))
287
288
289class _MockJobDirectory(job_directories._JobDirectory):
290 """Subclass of `_JobDirectory` used as a helper for tests."""
291
292 GLOB_PATTERN = '[0-9]*-*'
293
Jakob Juelich24f22c22014-09-26 11:46:11 -0700294
J. Richard Barnetteea785362014-03-17 16:00:53 -0700295 def __init__(self, resultsdir):
296 """Create new job in initial state."""
297 super(_MockJobDirectory, self).__init__(resultsdir)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700298 self._timestamp = None
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800299 self.queue_args = [resultsdir, os.path.dirname(resultsdir), self._timestamp]
J. Richard Barnetteea785362014-03-17 16:00:53 -0700300
Jakob Juelich24f22c22014-09-26 11:46:11 -0700301
J. Richard Barnetteea785362014-03-17 16:00:53 -0700302 def get_timestamp_if_finished(self):
303 return self._timestamp
304
Jakob Juelich24f22c22014-09-26 11:46:11 -0700305
J. Richard Barnetteea785362014-03-17 16:00:53 -0700306 def set_finished(self, days_old):
307 """Make this job appear to be finished.
308
309 After calling this function, calls to `enqueue_offload()`
310 will find this job as finished, but not expired and ready
311 for offload. Note that when `days_old` is 0,
312 `enqueue_offload()` will treat a finished job as eligible
313 for offload.
314
315 @param days_old The value of the `days_old` parameter that
316 will be passed to `enqueue_offload()` for
317 testing.
318
319 """
320 self._timestamp = _make_timestamp(days_old, False)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800321 self.queue_args[2] = self._timestamp
J. Richard Barnetteea785362014-03-17 16:00:53 -0700322
Jakob Juelich24f22c22014-09-26 11:46:11 -0700323
J. Richard Barnetteea785362014-03-17 16:00:53 -0700324 def set_expired(self, days_old):
325 """Make this job eligible to be offloaded.
326
327 After calling this function, calls to `offload` will attempt
328 to offload this job.
329
330 @param days_old The value of the `days_old` parameter that
331 will be passed to `enqueue_offload()` for
332 testing.
333
334 """
335 self._timestamp = _make_timestamp(days_old, True)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800336 self.queue_args[2] = self._timestamp
J. Richard Barnetteea785362014-03-17 16:00:53 -0700337
Jakob Juelich24f22c22014-09-26 11:46:11 -0700338
J. Richard Barnetteea785362014-03-17 16:00:53 -0700339 def set_incomplete(self):
340 """Make this job appear to have failed offload just once."""
Allen Lib41527d2017-06-22 17:28:00 -0700341 self.offload_count += 1
342 self.first_offload_start = time.time()
343 if not os.path.isdir(self.dirname):
344 os.mkdir(self.dirname)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700345
Jakob Juelich24f22c22014-09-26 11:46:11 -0700346
J. Richard Barnetteea785362014-03-17 16:00:53 -0700347 def set_reportable(self):
348 """Make this job be reportable."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700349 self.set_incomplete()
Allen Lib41527d2017-06-22 17:28:00 -0700350 self.offload_count += 1
J. Richard Barnetteea785362014-03-17 16:00:53 -0700351
Jakob Juelich24f22c22014-09-26 11:46:11 -0700352
J. Richard Barnetteea785362014-03-17 16:00:53 -0700353 def set_complete(self):
354 """Make this job be completed."""
Allen Lib41527d2017-06-22 17:28:00 -0700355 self.offload_count += 1
356 if os.path.isdir(self.dirname):
357 os.rmdir(self.dirname)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700358
359
Simran Basi1e10e922015-04-16 15:09:56 -0700360 def process_gs_instructions(self):
361 """Always still offload the job directory."""
362 return True
363
364
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700365class CommandListTests(unittest.TestCase):
Allen Lib41527d2017-06-22 17:28:00 -0700366 """Tests for `_get_cmd_list()`."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700367
MK Ryue93c8572015-08-11 11:53:00 -0700368 def _command_list_assertions(self, job, use_rsync=True, multi=False):
Allen Lib41527d2017-06-22 17:28:00 -0700369 """Call `_get_cmd_list()` and check the return value.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700370
371 Check the following assertions:
372 * The command name (argv[0]) is 'gsutil'.
MK Ryue93c8572015-08-11 11:53:00 -0700373 * '-m' option (argv[1]) is on when the argument, multi, is True.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700374 * The arguments contain the 'cp' subcommand.
375 * The next-to-last argument (the source directory) is the
376 job's `queue_args[0]`.
Simran Basidd129972014-09-11 14:34:49 -0700377 * The last argument (the destination URL) is the job's
378 'queue_args[1]'.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700379
380 @param job A job with properly calculated arguments to
Allen Lib41527d2017-06-22 17:28:00 -0700381 `_get_cmd_list()`
MK Ryue93c8572015-08-11 11:53:00 -0700382 @param use_rsync True when using 'rsync'. False when using 'cp'.
383 @param multi True when using '-m' option for gsutil.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700384
385 """
Jakob Juelich24f22c22014-09-26 11:46:11 -0700386 test_bucket_uri = 'gs://a-test-bucket'
387
388 gs_offloader.USE_RSYNC_ENABLED = use_rsync
389
Allen Lib41527d2017-06-22 17:28:00 -0700390 command = gs_offloader._get_cmd_list(
MK Ryue93c8572015-08-11 11:53:00 -0700391 multi, job.queue_args[0],
392 os.path.join(test_bucket_uri, job.queue_args[1]))
Jakob Juelich24f22c22014-09-26 11:46:11 -0700393
Dan Shi365049f2017-05-28 08:00:02 +0000394 self.assertEqual(command[0], 'gsutil')
MK Ryue93c8572015-08-11 11:53:00 -0700395 if multi:
396 self.assertEqual(command[1], '-m')
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700397 self.assertEqual(command[-2], job.queue_args[0])
Jakob Juelich24f22c22014-09-26 11:46:11 -0700398
399 if use_rsync:
400 self.assertTrue('rsync' in command)
401 self.assertEqual(command[-1],
402 os.path.join(test_bucket_uri, job.queue_args[0]))
403 else:
404 self.assertTrue('cp' in command)
405 self.assertEqual(command[-1],
406 os.path.join(test_bucket_uri, job.queue_args[1]))
407
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700408
Allen Lib41527d2017-06-22 17:28:00 -0700409 def test__get_cmd_list_regular(self):
410 """Test `_get_cmd_list()` as for a regular job."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700411 job = _MockJobDirectory('118-debug')
412 self._command_list_assertions(job)
413
Jakob Juelich24f22c22014-09-26 11:46:11 -0700414
Allen Lib41527d2017-06-22 17:28:00 -0700415 def test__get_cmd_list_special(self):
416 """Test `_get_cmd_list()` as for a special job."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700417 job = _MockJobDirectory('hosts/host1/118-reset')
418 self._command_list_assertions(job)
419
420
Jakob Juelich24f22c22014-09-26 11:46:11 -0700421 def test_get_cmd_list_regular_no_rsync(self):
Allen Lib41527d2017-06-22 17:28:00 -0700422 """Test `_get_cmd_list()` as for a regular job."""
Jakob Juelich24f22c22014-09-26 11:46:11 -0700423 job = _MockJobDirectory('118-debug')
424 self._command_list_assertions(job, use_rsync=False)
425
426
427 def test_get_cmd_list_special_no_rsync(self):
Allen Lib41527d2017-06-22 17:28:00 -0700428 """Test `_get_cmd_list()` as for a special job."""
Jakob Juelich24f22c22014-09-26 11:46:11 -0700429 job = _MockJobDirectory('hosts/host1/118-reset')
430 self._command_list_assertions(job, use_rsync=False)
431
432
MK Ryue93c8572015-08-11 11:53:00 -0700433 def test_get_cmd_list_regular_multi(self):
Allen Lib41527d2017-06-22 17:28:00 -0700434 """Test `_get_cmd_list()` as for a regular job with True multi."""
MK Ryue93c8572015-08-11 11:53:00 -0700435 job = _MockJobDirectory('118-debug')
436 self._command_list_assertions(job, multi=True)
437
438
Allen Lib41527d2017-06-22 17:28:00 -0700439 def test__get_cmd_list_special_multi(self):
440 """Test `_get_cmd_list()` as for a special job with True multi."""
MK Ryue93c8572015-08-11 11:53:00 -0700441 job = _MockJobDirectory('hosts/host1/118-reset')
442 self._command_list_assertions(job, multi=True)
443
444
Michael Tang97d188c2016-06-25 11:18:42 -0700445class PubSubTest(mox.MoxTestBase):
446 """Test the test result notifcation data structure."""
447
448 def test_create_test_result_notification(self):
449 """Tests the test result notification message."""
Allen Li5ed7e632017-02-03 16:31:33 -0800450 self.mox.StubOutWithMock(utils, 'get_moblab_id')
451 self.mox.StubOutWithMock(utils,
Michael Tang328073b2016-11-01 15:33:38 -0700452 'get_default_interface_mac_address')
Allen Li5ed7e632017-02-03 16:31:33 -0800453 utils.get_default_interface_mac_address().AndReturn(
Michael Tang328073b2016-11-01 15:33:38 -0700454 '1c:dc:d1:11:01:e1')
Allen Li5ed7e632017-02-03 16:31:33 -0800455 utils.get_moblab_id().AndReturn(
Michael Tang328073b2016-11-01 15:33:38 -0700456 'c8386d92-9ad1-11e6-80f5-111111111111')
457 self.mox.ReplayAll()
Michael Tangb45c7232016-11-14 21:40:43 -0800458 msg = gs_offloader._create_test_result_notification(
459 'gs://test_bucket', '123-moblab')
Michael Tang97d188c2016-06-25 11:18:42 -0700460 self.assertEquals(base64.b64encode(
461 gs_offloader.NEW_TEST_RESULT_MESSAGE), msg['data'])
Michael Tang328073b2016-11-01 15:33:38 -0700462 self.assertEquals(
Allen Lib41527d2017-06-22 17:28:00 -0700463 gs_offloader._NOTIFICATION_VERSION,
464 msg['attributes'][gs_offloader._NOTIFICATION_ATTR_VERSION])
Michael Tang328073b2016-11-01 15:33:38 -0700465 self.assertEquals(
466 '1c:dc:d1:11:01:e1',
Allen Lib41527d2017-06-22 17:28:00 -0700467 msg['attributes'][gs_offloader._NOTIFICATION_ATTR_MOBLAB_MAC])
Michael Tang328073b2016-11-01 15:33:38 -0700468 self.assertEquals(
469 'c8386d92-9ad1-11e6-80f5-111111111111',
Allen Lib41527d2017-06-22 17:28:00 -0700470 msg['attributes'][gs_offloader._NOTIFICATION_ATTR_MOBLAB_ID])
Michael Tang328073b2016-11-01 15:33:38 -0700471 self.assertEquals(
Michael Tangb45c7232016-11-14 21:40:43 -0800472 'gs://test_bucket/123-moblab',
Allen Lib41527d2017-06-22 17:28:00 -0700473 msg['attributes'][gs_offloader._NOTIFICATION_ATTR_GCS_URI])
Michael Tang328073b2016-11-01 15:33:38 -0700474 self.mox.VerifyAll()
Michael Tang97d188c2016-06-25 11:18:42 -0700475
476
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700477class _MockJob(object):
478 """Class to mock the return value of `AFE.get_jobs()`."""
479 def __init__(self, created):
480 self.created_on = created
481
482
483class _MockHostQueueEntry(object):
484 """Class to mock the return value of `AFE.get_host_queue_entries()`."""
485 def __init__(self, finished):
486 self.finished_on = finished
487
488
489class _MockSpecialTask(object):
490 """Class to mock the return value of `AFE.get_special_tasks()`."""
491 def __init__(self, finished):
492 self.time_finished = finished
493
494
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700495class JobDirectorySubclassTests(mox.MoxTestBase):
496 """Test specific to RegularJobDirectory and SpecialJobDirectory.
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700497
498 This provides coverage for the implementation in both
499 RegularJobDirectory and SpecialJobDirectory.
500
501 """
502
503 def setUp(self):
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700504 super(JobDirectorySubclassTests, self).setUp()
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700505 self.mox.StubOutWithMock(job_directories._AFE, 'get_jobs')
506 self.mox.StubOutWithMock(job_directories._AFE,
507 'get_host_queue_entries')
508 self.mox.StubOutWithMock(job_directories._AFE,
509 'get_special_tasks')
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700510
Jakob Juelich24f22c22014-09-26 11:46:11 -0700511
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700512 def test_regular_job_fields(self):
513 """Test the constructor for `RegularJobDirectory`.
514
Allen Lib41527d2017-06-22 17:28:00 -0700515 Construct a regular job, and assert that the `dirname`
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700516 and `_id` attributes are set as expected.
517
518 """
519 resultsdir = '118-fubar'
520 job = job_directories.RegularJobDirectory(resultsdir)
Allen Lib41527d2017-06-22 17:28:00 -0700521 self.assertEqual(job.dirname, resultsdir)
Dan Shicf4d2032015-03-12 15:04:21 -0700522 self.assertEqual(job._id, 118)
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700523
Jakob Juelich24f22c22014-09-26 11:46:11 -0700524
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700525 def test_special_job_fields(self):
526 """Test the constructor for `SpecialJobDirectory`.
527
Allen Lib41527d2017-06-22 17:28:00 -0700528 Construct a special job, and assert that the `dirname`
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700529 and `_id` attributes are set as expected.
530
531 """
532 destdir = 'hosts/host1'
533 resultsdir = destdir + '/118-reset'
534 job = job_directories.SpecialJobDirectory(resultsdir)
Allen Lib41527d2017-06-22 17:28:00 -0700535 self.assertEqual(job.dirname, resultsdir)
Dan Shicf4d2032015-03-12 15:04:21 -0700536 self.assertEqual(job._id, 118)
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700537
Jakob Juelich24f22c22014-09-26 11:46:11 -0700538
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700539 def _check_finished_job(self, jobtime, hqetimes, expected):
540 """Mock and test behavior of a finished job.
541
542 Initialize the mocks for a call to
543 `get_timestamp_if_finished()`, then simulate one call.
544 Assert that the returned timestamp matches the passed
545 in expected value.
546
547 @param jobtime Time used to construct a _MockJob object.
548 @param hqetimes List of times used to construct
549 _MockHostQueueEntry objects.
550 @param expected Expected time to be returned by
551 get_timestamp_if_finished
552
553 """
554 job = job_directories.RegularJobDirectory('118-fubar')
555 job_directories._AFE.get_jobs(
556 id=job._id, finished=True).AndReturn(
557 [_MockJob(jobtime)])
558 job_directories._AFE.get_host_queue_entries(
559 finished_on__isnull=False,
560 job_id=job._id).AndReturn(
561 [_MockHostQueueEntry(t) for t in hqetimes])
562 self.mox.ReplayAll()
563 self.assertEqual(expected, job.get_timestamp_if_finished())
564 self.mox.VerifyAll()
565
566
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700567 def test_finished_regular_job(self):
568 """Test getting the timestamp for a finished regular job.
569
570 Tests the return value for
571 `RegularJobDirectory.get_timestamp_if_finished()` when
572 the AFE indicates the job is finished.
573
574 """
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700575 created_timestamp = _make_timestamp(1, True)
576 hqe_timestamp = _make_timestamp(0, True)
577 self._check_finished_job(created_timestamp,
578 [hqe_timestamp],
579 hqe_timestamp)
Simran Basifb98e462014-08-18 12:35:44 -0700580
Jakob Juelich24f22c22014-09-26 11:46:11 -0700581
Simran Basifb98e462014-08-18 12:35:44 -0700582 def test_finished_regular_job_multiple_hqes(self):
583 """Test getting the timestamp for a regular job with multiple hqes.
584
585 Tests the return value for
586 `RegularJobDirectory.get_timestamp_if_finished()` when
587 the AFE indicates the job is finished and the job has multiple host
588 queue entries.
589
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700590 Tests that the returned timestamp is the latest timestamp in
591 the list of HQEs, regardless of the returned order.
592
Simran Basifb98e462014-08-18 12:35:44 -0700593 """
Simran Basifb98e462014-08-18 12:35:44 -0700594 created_timestamp = _make_timestamp(2, True)
595 older_hqe_timestamp = _make_timestamp(1, True)
596 newer_hqe_timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700597 hqe_list = [older_hqe_timestamp,
598 newer_hqe_timestamp]
599 self._check_finished_job(created_timestamp,
600 hqe_list,
601 newer_hqe_timestamp)
602 self.mox.ResetAll()
603 hqe_list.reverse()
604 self._check_finished_job(created_timestamp,
605 hqe_list,
606 newer_hqe_timestamp)
Simran Basifb98e462014-08-18 12:35:44 -0700607
Jakob Juelich24f22c22014-09-26 11:46:11 -0700608
Simran Basifb98e462014-08-18 12:35:44 -0700609 def test_finished_regular_job_null_finished_times(self):
610 """Test getting the timestamp for an aborted regular job.
611
612 Tests the return value for
613 `RegularJobDirectory.get_timestamp_if_finished()` when
614 the AFE indicates the job is finished and the job has aborted host
615 queue entries.
616
617 """
Simran Basifb98e462014-08-18 12:35:44 -0700618 timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700619 self._check_finished_job(timestamp, [], timestamp)
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700620
Jakob Juelich24f22c22014-09-26 11:46:11 -0700621
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700622 def test_unfinished_regular_job(self):
623 """Test getting the timestamp for an unfinished regular job.
624
625 Tests the return value for
626 `RegularJobDirectory.get_timestamp_if_finished()` when
627 the AFE indicates the job is not finished.
628
629 """
630 job = job_directories.RegularJobDirectory('118-fubar')
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700631 job_directories._AFE.get_jobs(
632 id=job._id, finished=True).AndReturn([])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700633 self.mox.ReplayAll()
634 self.assertIsNone(job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700635 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700636
Jakob Juelich24f22c22014-09-26 11:46:11 -0700637
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700638 def test_finished_special_job(self):
639 """Test getting the timestamp for a finished special job.
640
641 Tests the return value for
642 `SpecialJobDirectory.get_timestamp_if_finished()` when
643 the AFE indicates the job is finished.
644
645 """
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700646 job = job_directories.SpecialJobDirectory(
647 'hosts/host1/118-reset')
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700648 timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700649 job_directories._AFE.get_special_tasks(
650 id=job._id, is_complete=True).AndReturn(
651 [_MockSpecialTask(timestamp)])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700652 self.mox.ReplayAll()
653 self.assertEqual(timestamp,
654 job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700655 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700656
Jakob Juelich24f22c22014-09-26 11:46:11 -0700657
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700658 def test_unfinished_special_job(self):
659 """Test getting the timestamp for an unfinished special job.
660
661 Tests the return value for
662 `SpecialJobDirectory.get_timestamp_if_finished()` when
663 the AFE indicates the job is not finished.
664
665 """
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700666 job = job_directories.SpecialJobDirectory(
667 'hosts/host1/118-reset')
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700668 job_directories._AFE.get_special_tasks(
669 id=job._id, is_complete=True).AndReturn([])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700670 self.mox.ReplayAll()
671 self.assertIsNone(job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700672 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700673
674
Allen Lib41527d2017-06-22 17:28:00 -0700675class _TempResultsDirTestCase(unittest.TestCase):
676 """Mixin class for tests using a temporary results directory."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700677
J. Richard Barnette08800322014-05-16 14:49:46 -0700678 REGULAR_JOBLIST = [
679 '111-fubar', '112-fubar', '113-fubar', '114-snafu']
680 HOST_LIST = ['host1', 'host2', 'host3']
681 SPECIAL_JOBLIST = [
682 'hosts/host1/333-reset', 'hosts/host1/334-reset',
683 'hosts/host2/444-reset', 'hosts/host3/555-reset']
684
Jakob Juelich24f22c22014-09-26 11:46:11 -0700685
J. Richard Barnetteea785362014-03-17 16:00:53 -0700686 def setUp(self):
Allen Lib41527d2017-06-22 17:28:00 -0700687 super(_TempResultsDirTestCase, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -0700688 self._resultsroot = tempfile.mkdtemp()
689 self._cwd = os.getcwd()
690 os.chdir(self._resultsroot)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700691
Jakob Juelich24f22c22014-09-26 11:46:11 -0700692
J. Richard Barnetteea785362014-03-17 16:00:53 -0700693 def tearDown(self):
J. Richard Barnette08800322014-05-16 14:49:46 -0700694 os.chdir(self._cwd)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700695 shutil.rmtree(self._resultsroot)
Allen Lib41527d2017-06-22 17:28:00 -0700696 super(_TempResultsDirTestCase, self).tearDown()
J. Richard Barnetteea785362014-03-17 16:00:53 -0700697
Jakob Juelich24f22c22014-09-26 11:46:11 -0700698
J. Richard Barnetteea785362014-03-17 16:00:53 -0700699 def make_job(self, jobdir):
700 """Create a job with results in `self._resultsroot`.
701
702 @param jobdir Name of the subdirectory to be created in
703 `self._resultsroot`.
704
705 """
J. Richard Barnette08800322014-05-16 14:49:46 -0700706 os.mkdir(jobdir)
707 return _MockJobDirectory(jobdir)
708
Jakob Juelich24f22c22014-09-26 11:46:11 -0700709
J. Richard Barnette08800322014-05-16 14:49:46 -0700710 def make_job_hierarchy(self):
711 """Create a sample hierarchy of job directories.
712
713 `self.REGULAR_JOBLIST` is a list of directories for regular
714 jobs to be created; `self.SPECIAL_JOBLIST` is a list of
715 directories for special jobs to be created.
716
717 """
718 for d in self.REGULAR_JOBLIST:
719 os.mkdir(d)
720 hostsdir = 'hosts'
721 os.mkdir(hostsdir)
722 for host in self.HOST_LIST:
723 os.mkdir(os.path.join(hostsdir, host))
724 for d in self.SPECIAL_JOBLIST:
725 os.mkdir(d)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700726
727
Allen Lib41527d2017-06-22 17:28:00 -0700728class _TempResultsDirTestBase(_TempResultsDirTestCase, mox.MoxTestBase):
729 """Base Mox test class for tests using a temporary results directory."""
730
731
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800732class FailedOffloadsLogTest(_TempResultsDirTestBase):
733 """Test the formatting of failed offloads log file."""
734 # Below is partial sample of a failed offload log file. This text is
735 # deliberately hard-coded and then parsed to create the test data; the idea
736 # is to make sure the actual text format will be reviewed by a human being.
737 #
738 # first offload count directory
739 # --+----1----+---- ----+ ----+----1----+----2----+----3
740 _SAMPLE_DIRECTORIES_REPORT = '''\
741 =================== ====== ==============================
742 2014-03-14 15:09:26 1 118-fubar
743 2014-03-14 15:19:23 2 117-fubar
744 2014-03-14 15:29:20 6 116-fubar
745 2014-03-14 15:39:17 24 115-fubar
746 2014-03-14 15:49:14 120 114-fubar
747 2014-03-14 15:59:11 720 113-fubar
748 2014-03-14 16:09:08 5040 112-fubar
749 2014-03-14 16:19:05 40320 111-fubar
750 '''
751
752 def setUp(self):
753 super(FailedOffloadsLogTest, self).setUp()
754 self._offloader = gs_offloader.Offloader(_get_options([]))
755 self._joblist = []
756 for line in self._SAMPLE_DIRECTORIES_REPORT.split('\n')[1 : -1]:
757 date_, time_, count, dir_ = line.split()
758 job = _MockJobDirectory(dir_)
Allen Lib41527d2017-06-22 17:28:00 -0700759 job.offload_count = int(count)
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800760 timestruct = time.strptime("%s %s" % (date_, time_),
761 gs_offloader.FAILED_OFFLOADS_TIME_FORMAT)
Allen Lib41527d2017-06-22 17:28:00 -0700762 job.first_offload_start = time.mktime(timestruct)
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800763 # enter the jobs in reverse order, to make sure we
764 # test that the output will be sorted.
765 self._joblist.insert(0, job)
766
767
768 def assert_report_well_formatted(self, report_file):
Allen Li93585382017-05-05 14:24:53 -0700769 """Assert that report file is well formatted.
770
771 @param report_file: Path to report file
772 """
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800773 with open(report_file, 'r') as f:
774 report_lines = f.read().split()
775
776 for end_of_header_index in range(len(report_lines)):
777 if report_lines[end_of_header_index].startswith('=='):
778 break
779 self.assertLess(end_of_header_index, len(report_lines),
780 'Failed to find end-of-header marker in the report')
781
782 relevant_lines = report_lines[end_of_header_index:]
783 expected_lines = self._SAMPLE_DIRECTORIES_REPORT.split()
784 self.assertListEqual(relevant_lines, expected_lines)
785
786
787 def test_failed_offload_log_format(self):
788 """Trigger an e-mail report and check its contents."""
789 log_file = os.path.join(self._resultsroot, 'failed_log')
790 report = self._offloader._log_failed_jobs_locally(self._joblist,
791 log_file=log_file)
792 self.assert_report_well_formatted(log_file)
793
794
795 def test_failed_offload_file_overwrite(self):
796 """Verify that we can saefly overwrite the log file."""
797 log_file = os.path.join(self._resultsroot, 'failed_log')
798 with open(log_file, 'w') as f:
799 f.write('boohoohoo')
800 report = self._offloader._log_failed_jobs_locally(self._joblist,
801 log_file=log_file)
802 self.assert_report_well_formatted(log_file)
803
804
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700805class OffloadDirectoryTests(_TempResultsDirTestBase):
806 """Tests for `offload_dir()`."""
807
808 def setUp(self):
809 super(OffloadDirectoryTests, self).setUp()
810 # offload_dir() logs messages; silence them.
811 self._saved_loglevel = logging.getLogger().getEffectiveLevel()
812 logging.getLogger().setLevel(logging.CRITICAL+1)
813 self._job = self.make_job(self.REGULAR_JOBLIST[0])
Allen Lib41527d2017-06-22 17:28:00 -0700814 self.mox.StubOutWithMock(gs_offloader, '_get_cmd_list')
815 alarm = mock.patch('signal.alarm', return_value=0)
816 alarm.start()
817 self.addCleanup(alarm.stop)
Ningning Xia2d981ee2016-07-06 17:59:54 -0700818 self.mox.StubOutWithMock(models.test, 'parse_job_keyval')
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700819
Jakob Juelich24f22c22014-09-26 11:46:11 -0700820
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700821 def tearDown(self):
822 logging.getLogger().setLevel(self._saved_loglevel)
823 super(OffloadDirectoryTests, self).tearDown()
824
Allen Lib41527d2017-06-22 17:28:00 -0700825 def _mock__upload_cts_testresult(self):
826 self.mox.StubOutWithMock(gs_offloader, '_upload_cts_testresult')
827 gs_offloader._upload_cts_testresult(
Ningning Xia42111242016-06-15 14:35:58 -0700828 mox.IgnoreArg(),mox.IgnoreArg()).AndReturn(None)
Jakob Juelich24f22c22014-09-26 11:46:11 -0700829
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800830 def _mock_create_marker_file(self):
831 self.mox.StubOutWithMock(__builtin__, 'open')
Allen Li9579b382017-05-05 17:07:43 -0700832 open(mox.IgnoreArg(), 'a').AndReturn(mock.MagicMock())
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800833
834
835 def _mock_offload_dir_calls(self, command, queue_args,
Allen Lib41527d2017-06-22 17:28:00 -0700836 marker_initially_exists=False):
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700837 """Mock out the calls needed by `offload_dir()`.
838
839 This covers only the calls made when there is no timeout.
840
841 @param command Command list to be returned by the mocked
Allen Lib41527d2017-06-22 17:28:00 -0700842 call to `_get_cmd_list()`.
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700843
844 """
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800845 self.mox.StubOutWithMock(os.path, 'isfile')
846 os.path.isfile(mox.IgnoreArg()).AndReturn(marker_initially_exists)
Simran Basidd129972014-09-11 14:34:49 -0700847 command.append(queue_args[0])
Allen Lib41527d2017-06-22 17:28:00 -0700848 gs_offloader._get_cmd_list(
MK Ryue93c8572015-08-11 11:53:00 -0700849 False, queue_args[0],
850 '%s%s' % (utils.DEFAULT_OFFLOAD_GSURI,
851 queue_args[1])).AndReturn(command)
Allen Lib41527d2017-06-22 17:28:00 -0700852 self._mock__upload_cts_testresult()
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700853
Jakob Juelich24f22c22014-09-26 11:46:11 -0700854
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800855 def _run_offload_dir(self, should_succeed, delete_age):
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700856 """Make one call to `offload_dir()`.
857
858 The caller ensures all mocks are set up already.
859
860 @param should_succeed True iff the call to `offload_dir()`
861 is expected to succeed and remove the
862 offloaded job directory.
863
864 """
865 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -0700866 gs_offloader.GSOffloader(
867 utils.DEFAULT_OFFLOAD_GSURI, False, delete_age).offload(
MK Ryue93c8572015-08-11 11:53:00 -0700868 self._job.queue_args[0],
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800869 self._job.queue_args[1],
870 self._job.queue_args[2])
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700871 self.mox.VerifyAll()
872 self.assertEqual(not should_succeed,
873 os.path.isdir(self._job.queue_args[0]))
874
Jakob Juelich24f22c22014-09-26 11:46:11 -0700875
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700876 def test_offload_success(self):
877 """Test that `offload_dir()` can succeed correctly."""
Simran Basidd129972014-09-11 14:34:49 -0700878 self._mock_offload_dir_calls(['test', '-d'],
879 self._job.queue_args)
Allen Lib41527d2017-06-22 17:28:00 -0700880 os.path.isfile(mox.IgnoreArg()).AndReturn(True)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800881 self._mock_create_marker_file()
882 self._run_offload_dir(True, 0)
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700883
Jakob Juelich24f22c22014-09-26 11:46:11 -0700884
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700885 def test_offload_failure(self):
886 """Test that `offload_dir()` can fail correctly."""
Simran Basidd129972014-09-11 14:34:49 -0700887 self._mock_offload_dir_calls(['test', '!', '-d'],
Allen Lib41527d2017-06-22 17:28:00 -0700888 self._job.queue_args)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800889 self._run_offload_dir(False, 0)
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700890
891
Dan Shiaffb9222015-04-15 17:05:47 -0700892 def test_sanitize_dir(self):
893 """Test that folder/file name with invalid character can be corrected.
894 """
895 results_folder = tempfile.mkdtemp()
Allen Lib41527d2017-06-22 17:28:00 -0700896 invalid_chars = '_'.join(['[', ']', '*', '?', '#'])
Dan Shiaffb9222015-04-15 17:05:47 -0700897 invalid_files = []
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800898 invalid_folder_name = 'invalid_name_folder_%s' % invalid_chars
Dan Shiaffb9222015-04-15 17:05:47 -0700899 invalid_folder = os.path.join(
900 results_folder,
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800901 invalid_folder_name)
Dan Shiaffb9222015-04-15 17:05:47 -0700902 invalid_files.append(os.path.join(
903 invalid_folder,
904 'invalid_name_file_%s' % invalid_chars))
Dan Shiaffb9222015-04-15 17:05:47 -0700905 good_folder = os.path.join(results_folder, 'valid_name_folder')
906 good_file = os.path.join(good_folder, 'valid_name_file')
907 for folder in [invalid_folder, good_folder]:
908 os.makedirs(folder)
909 for f in invalid_files + [good_file]:
910 with open(f, 'w'):
911 pass
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800912 # check that broken symlinks don't break sanitization
913 symlink = os.path.join(invalid_folder, 'broken-link')
914 os.symlink(os.path.join(results_folder, 'no-such-file'),
915 symlink)
916 fifo1 = os.path.join(results_folder, 'test_fifo1')
917 fifo2 = os.path.join(good_folder, 'test_fifo2')
918 fifo3 = os.path.join(invalid_folder, 'test_fifo3')
919 invalid_fifo4_name = 'test_fifo4_%s' % invalid_chars
920 fifo4 = os.path.join(invalid_folder, invalid_fifo4_name)
921 os.mkfifo(fifo1)
922 os.mkfifo(fifo2)
923 os.mkfifo(fifo3)
924 os.mkfifo(fifo4)
Dan Shiaffb9222015-04-15 17:05:47 -0700925 gs_offloader.sanitize_dir(results_folder)
926 for _, dirs, files in os.walk(results_folder):
927 for name in dirs + files:
Allen Lib41527d2017-06-22 17:28:00 -0700928 self.assertEqual(name, gslib.escape(name))
Dan Shiaffb9222015-04-15 17:05:47 -0700929 for c in name:
Allen Lib41527d2017-06-22 17:28:00 -0700930 self.assertFalse(c in ['[', ']', '*', '?', '#'])
Dan Shiaffb9222015-04-15 17:05:47 -0700931 self.assertTrue(os.path.exists(good_file))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800932
933 self.assertTrue(os.path.exists(fifo1))
934 self.assertFalse(is_fifo(fifo1))
935 self.assertTrue(os.path.exists(fifo2))
936 self.assertFalse(is_fifo(fifo2))
937 corrected_folder = os.path.join(
Allen Lib41527d2017-06-22 17:28:00 -0700938 results_folder, gslib.escape(invalid_folder_name))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800939 corrected_fifo3 = os.path.join(
940 corrected_folder,
941 'test_fifo3')
942 self.assertFalse(os.path.exists(fifo3))
943 self.assertTrue(os.path.exists(corrected_fifo3))
944 self.assertFalse(is_fifo(corrected_fifo3))
945 corrected_fifo4 = os.path.join(
Allen Lib41527d2017-06-22 17:28:00 -0700946 corrected_folder, gslib.escape(invalid_fifo4_name))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800947 self.assertFalse(os.path.exists(fifo4))
948 self.assertTrue(os.path.exists(corrected_fifo4))
949 self.assertFalse(is_fifo(corrected_fifo4))
950
951 corrected_symlink = os.path.join(
952 corrected_folder,
953 'broken-link')
954 self.assertFalse(os.path.lexists(symlink))
955 self.assertTrue(os.path.exists(corrected_symlink))
956 self.assertFalse(os.path.islink(corrected_symlink))
Dan Shiaffb9222015-04-15 17:05:47 -0700957 shutil.rmtree(results_folder)
958
959
Dan Shi1b4c7c32015-10-05 10:38:57 -0700960 def check_limit_file_count(self, is_test_job=True):
961 """Test that folder with too many files can be compressed.
962
963 @param is_test_job: True to check the method with test job result
964 folder. Set to False for special task folder.
965 """
966 results_folder = tempfile.mkdtemp()
967 host_folder = os.path.join(
968 results_folder,
969 'lab1-host1' if is_test_job else 'hosts/lab1-host1/1-repair')
970 debug_folder = os.path.join(host_folder, 'debug')
971 sysinfo_folder = os.path.join(host_folder, 'sysinfo')
972 for folder in [debug_folder, sysinfo_folder]:
973 os.makedirs(folder)
974 for i in range(10):
975 with open(os.path.join(folder, str(i)), 'w') as f:
976 f.write('test')
977
Allen Lib41527d2017-06-22 17:28:00 -0700978 gs_offloader._MAX_FILE_COUNT = 100
Dan Shi1b4c7c32015-10-05 10:38:57 -0700979 gs_offloader.limit_file_count(
980 results_folder if is_test_job else host_folder)
981 self.assertTrue(os.path.exists(sysinfo_folder))
982
Allen Lib41527d2017-06-22 17:28:00 -0700983 gs_offloader._MAX_FILE_COUNT = 10
Dan Shi1b4c7c32015-10-05 10:38:57 -0700984 gs_offloader.limit_file_count(
985 results_folder if is_test_job else host_folder)
986 self.assertFalse(os.path.exists(sysinfo_folder))
987 self.assertTrue(os.path.exists(sysinfo_folder + '.tgz'))
988 self.assertTrue(os.path.exists(debug_folder))
989
990 shutil.rmtree(results_folder)
991
992
993 def test_limit_file_count(self):
994 """Test that folder with too many files can be compressed.
995 """
996 self.check_limit_file_count(is_test_job=True)
997 self.check_limit_file_count(is_test_job=False)
998
Ningning Xia2d88eec2016-07-25 23:18:46 -0700999
Ningning Xia8db632f2016-08-19 11:01:35 -07001000 def test_is_valid_result(self):
1001 """Test _is_valid_result."""
Ningning Xia21922c82016-07-29 11:03:15 -07001002 release_build = 'veyron_minnie-cheets-release/R52-8248.0.0'
1003 pfq_build = 'cyan-cheets-android-pfq/R54-8623.0.0-rc1'
1004 trybot_build = 'trybot-samus-release/R54-8640.0.0-b5092'
1005 trybot_2_build = 'trybot-samus-pfq/R54-8640.0.0-b5092'
1006 release_2_build = 'test-trybot-release/R54-8640.0.0-b5092'
Ningning Xia8db632f2016-08-19 11:01:35 -07001007 self.assertTrue(gs_offloader._is_valid_result(
1008 release_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
Rohit Makasana6384c102016-10-21 17:09:47 -07001009 self.assertTrue(gs_offloader._is_valid_result(
1010 release_build, gs_offloader.CTS_RESULT_PATTERN, 'test_that_wrapper'))
Ningning Xia8db632f2016-08-19 11:01:35 -07001011 self.assertFalse(gs_offloader._is_valid_result(
1012 release_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-bvt-cq'))
1013 self.assertTrue(gs_offloader._is_valid_result(
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001014 release_build, gs_offloader.CTS_V2_RESULT_PATTERN, 'arc-gts'))
Ningning Xia8db632f2016-08-19 11:01:35 -07001015 self.assertFalse(gs_offloader._is_valid_result(
1016 None, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1017 self.assertFalse(gs_offloader._is_valid_result(
1018 release_build, gs_offloader.CTS_RESULT_PATTERN, None))
1019 self.assertFalse(gs_offloader._is_valid_result(
1020 pfq_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1021 self.assertFalse(gs_offloader._is_valid_result(
1022 trybot_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1023 self.assertFalse(gs_offloader._is_valid_result(
1024 trybot_2_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1025 self.assertTrue(gs_offloader._is_valid_result(
1026 release_2_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
Ningning Xia21922c82016-07-29 11:03:15 -07001027
1028
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001029 def create_results_folder(self):
1030 """Create CTS/GTS results folders."""
Ningning Xia42111242016-06-15 14:35:58 -07001031 results_folder = tempfile.mkdtemp()
1032 host_folder = os.path.join(results_folder, 'chromeos4-row9-rack11-host22')
1033 debug_folder = os.path.join(host_folder, 'debug')
1034 sysinfo_folder = os.path.join(host_folder, 'sysinfo')
1035 cts_result_folder = os.path.join(
1036 host_folder, 'cheets_CTS.android.dpi', 'results', 'cts-results')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001037 cts_v2_result_folder = os.path.join(host_folder,
1038 'cheets_CTS_N.CtsGraphicsTestCases', 'results', 'android-cts')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001039 gts_result_folder = os.path.join(
Ilja H. Friedelbfa63142017-01-26 00:56:29 -08001040 host_folder, 'cheets_GTS.google.admin', 'results', 'android-gts')
Ningning Xia42111242016-06-15 14:35:58 -07001041 timestamp_str = '2016.04.28_01.41.44'
Ningning Xia2d88eec2016-07-25 23:18:46 -07001042 timestamp_cts_folder = os.path.join(cts_result_folder, timestamp_str)
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001043 timestamp_cts_v2_folder = os.path.join(cts_v2_result_folder, timestamp_str)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001044 timestamp_gts_folder = os.path.join(gts_result_folder, timestamp_str)
1045
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001046 # Test results in cts_result_folder with a different time-stamp.
1047 timestamp_str_2 = '2016.04.28_10.41.44'
1048 timestamp_cts_folder_2 = os.path.join(cts_result_folder, timestamp_str_2)
1049
Ningning Xia2d88eec2016-07-25 23:18:46 -07001050 for folder in [debug_folder, sysinfo_folder, cts_result_folder,
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001051 timestamp_cts_folder, timestamp_cts_folder_2,
1052 timestamp_cts_v2_folder, timestamp_gts_folder]:
Ningning Xia42111242016-06-15 14:35:58 -07001053 os.makedirs(folder)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001054
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001055 path_pattern_pair = [(timestamp_cts_folder, gs_offloader.CTS_RESULT_PATTERN),
1056 (timestamp_cts_folder_2, gs_offloader.CTS_RESULT_PATTERN),
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001057 (timestamp_cts_v2_folder, gs_offloader.CTS_V2_RESULT_PATTERN),
1058 (timestamp_gts_folder, gs_offloader.CTS_V2_RESULT_PATTERN)]
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001059
1060 # Create timestamp.zip file_path.
Ningning Xia2d88eec2016-07-25 23:18:46 -07001061 cts_zip_file = os.path.join(cts_result_folder, timestamp_str + '.zip')
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001062 cts_zip_file_2 = os.path.join(cts_result_folder, timestamp_str_2 + '.zip')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001063 cts_v2_zip_file = os.path.join(cts_v2_result_folder, timestamp_str + '.zip')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001064 gts_zip_file = os.path.join(gts_result_folder, timestamp_str + '.zip')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001065
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001066 # Create xml file_path.
1067 cts_result_file = os.path.join(timestamp_cts_folder, 'testResult.xml')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001068 cts_result_file_2 = os.path.join(timestamp_cts_folder_2,
1069 'testResult.xml')
Ilja H. Friedelbfa63142017-01-26 00:56:29 -08001070 gts_result_file = os.path.join(timestamp_gts_folder, 'test_result.xml')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001071 cts_v2_result_file = os.path.join(timestamp_cts_v2_folder,
1072 'test_result.xml')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001073
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001074 for file_path in [cts_zip_file, cts_zip_file_2, cts_v2_zip_file,
1075 gts_zip_file, cts_result_file, cts_result_file_2,
1076 gts_result_file, cts_v2_result_file]:
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001077 with open(file_path, 'w') as f:
1078 f.write('test')
Ningning Xia42111242016-06-15 14:35:58 -07001079
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001080 return (results_folder, host_folder, path_pattern_pair)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001081
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001082
Allen Lib41527d2017-06-22 17:28:00 -07001083 def test__upload_cts_testresult(self):
1084 """Test _upload_cts_testresult."""
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001085 results_folder, host_folder, path_pattern_pair = self.create_results_folder()
1086
1087 self.mox.StubOutWithMock(gs_offloader, '_upload_files')
1088 gs_offloader._upload_files(
1089 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False).AndReturn(
1090 ['test', '-d', host_folder])
1091 gs_offloader._upload_files(
1092 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False).AndReturn(
1093 ['test', '-d', host_folder])
1094 gs_offloader._upload_files(
1095 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False).AndReturn(
1096 ['test', '-d', host_folder])
Ningning Xia2d88eec2016-07-25 23:18:46 -07001097
Ningning Xia42111242016-06-15 14:35:58 -07001098 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -07001099 gs_offloader._upload_cts_testresult(results_folder, False)
Ningning Xia42111242016-06-15 14:35:58 -07001100 self.mox.VerifyAll()
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001101 shutil.rmtree(results_folder)
1102
1103
1104 def test_upload_files(self):
1105 """Test upload_files"""
1106 results_folder, host_folder, path_pattern_pair = self.create_results_folder()
1107
1108 for path, pattern in path_pattern_pair:
1109 models.test.parse_job_keyval(mox.IgnoreArg()).AndReturn({
1110 'build': 'veyron_minnie-cheets-release/R52-8248.0.0',
Ningning Xia8db632f2016-08-19 11:01:35 -07001111 'parent_job_id': 'p_id',
1112 'suite': 'arc-cts'
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001113 })
1114
Allen Lib41527d2017-06-22 17:28:00 -07001115 gs_offloader._get_cmd_list(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001116 False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
1117 ['test', '-d', path])
Allen Lib41527d2017-06-22 17:28:00 -07001118 gs_offloader._get_cmd_list(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001119 False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
1120 ['test', '-d', path])
1121
1122 self.mox.ReplayAll()
1123 gs_offloader._upload_files(host_folder, path, pattern, False)
1124 self.mox.VerifyAll()
1125 self.mox.ResetAll()
Ningning Xia42111242016-06-15 14:35:58 -07001126
1127 shutil.rmtree(results_folder)
Dan Shi1b4c7c32015-10-05 10:38:57 -07001128
Michael Tang97d188c2016-06-25 11:18:42 -07001129
Dan Shi02dd0662017-05-23 11:24:32 -07001130 def test_get_metrics_fields(self):
1131 """Test method _get_metrics_fields."""
1132 results_folder, host_folder, _ = self.create_results_folder()
1133 models.test.parse_job_keyval(mox.IgnoreArg()).AndReturn({
1134 'build': 'veyron_minnie-cheets-release/R52-8248.0.0',
1135 'parent_job_id': 'p_id',
1136 'suite': 'arc-cts'
1137 })
1138 try:
1139 self.mox.ReplayAll()
1140 self.assertEqual({'board': 'veyron_minnie-cheets',
1141 'milestone': 'R52'},
1142 gs_offloader._get_metrics_fields(host_folder))
1143 self.mox.VerifyAll()
1144 finally:
1145 shutil.rmtree(results_folder)
1146
1147
J. Richard Barnetteea785362014-03-17 16:00:53 -07001148class JobDirectoryOffloadTests(_TempResultsDirTestBase):
1149 """Tests for `_JobDirectory.enqueue_offload()`.
1150
1151 When testing with a `days_old` parameter of 0, we use
1152 `set_finished()` instead of `set_expired()`. This causes the
1153 job's timestamp to be set in the future. This is done so as
1154 to test that when `days_old` is 0, the job is always treated
1155 as eligible for offload, regardless of the timestamp's value.
1156
1157 Testing covers the following assertions:
1158 A. Each time `enqueue_offload()` is called, a message that
1159 includes the job's directory name will be logged using
1160 `logging.debug()`, regardless of whether the job was
1161 enqueued. Nothing else is allowed to be logged.
1162 B. If the job is not eligible to be offloaded,
Allen Lib41527d2017-06-22 17:28:00 -07001163 `first_offload_start` and `offload_count` are 0.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001164 C. If the job is not eligible for offload, nothing is
1165 enqueued in `queue`.
Allen Lib41527d2017-06-22 17:28:00 -07001166 D. When the job is offloaded, `offload_count` increments
J. Richard Barnetteea785362014-03-17 16:00:53 -07001167 each time.
1168 E. When the job is offloaded, the appropriate parameters are
1169 enqueued exactly once.
Allen Lib41527d2017-06-22 17:28:00 -07001170 F. The first time a job is offloaded, `first_offload_start` is
J. Richard Barnetteea785362014-03-17 16:00:53 -07001171 set to the current time.
Allen Lib41527d2017-06-22 17:28:00 -07001172 G. `first_offload_start` only changes the first time that the
J. Richard Barnetteea785362014-03-17 16:00:53 -07001173 job is offloaded.
1174
1175 The test cases below are designed to exercise all of the
1176 meaningful state transitions at least once.
1177
1178 """
1179
1180 def setUp(self):
1181 super(JobDirectoryOffloadTests, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -07001182 self._job = self.make_job(self.REGULAR_JOBLIST[0])
J. Richard Barnetteea785362014-03-17 16:00:53 -07001183 self._queue = Queue.Queue()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001184
Jakob Juelich24f22c22014-09-26 11:46:11 -07001185
J. Richard Barnetteea785362014-03-17 16:00:53 -07001186 def _offload_unexpired_job(self, days_old):
1187 """Make calls to `enqueue_offload()` for an unexpired job.
1188
1189 This method tests assertions B and C that calling
1190 `enqueue_offload()` has no effect.
1191
1192 """
Allen Lib41527d2017-06-22 17:28:00 -07001193 self.assertEqual(self._job.offload_count, 0)
1194 self.assertEqual(self._job.first_offload_start, 0)
1195 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
1196 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001197 self.assertTrue(self._queue.empty())
Allen Lib41527d2017-06-22 17:28:00 -07001198 self.assertEqual(self._job.offload_count, 0)
1199 self.assertEqual(self._job.first_offload_start, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001200
Jakob Juelich24f22c22014-09-26 11:46:11 -07001201
J. Richard Barnetteea785362014-03-17 16:00:53 -07001202 def _offload_expired_once(self, days_old, count):
1203 """Make one call to `enqueue_offload()` for an expired job.
1204
1205 This method tests assertions D and E regarding side-effects
1206 expected when a job is offloaded.
1207
1208 """
Allen Lib41527d2017-06-22 17:28:00 -07001209 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
1210 self.assertEqual(self._job.offload_count, count)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001211 self.assertFalse(self._queue.empty())
1212 v = self._queue.get_nowait()
1213 self.assertTrue(self._queue.empty())
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -07001214 self.assertEqual(v, self._job.queue_args)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001215
Jakob Juelich24f22c22014-09-26 11:46:11 -07001216
J. Richard Barnetteea785362014-03-17 16:00:53 -07001217 def _offload_expired_job(self, days_old):
1218 """Make calls to `enqueue_offload()` for a just-expired job.
1219
1220 This method directly tests assertions F and G regarding
Allen Lib41527d2017-06-22 17:28:00 -07001221 side-effects on `first_offload_start`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001222
1223 """
1224 t0 = time.time()
1225 self._offload_expired_once(days_old, 1)
Allen Lib41527d2017-06-22 17:28:00 -07001226 t1 = self._job.first_offload_start
J. Richard Barnetteea785362014-03-17 16:00:53 -07001227 self.assertLessEqual(t1, time.time())
1228 self.assertGreaterEqual(t1, t0)
1229 self._offload_expired_once(days_old, 2)
Allen Lib41527d2017-06-22 17:28:00 -07001230 self.assertEqual(self._job.first_offload_start, t1)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001231 self._offload_expired_once(days_old, 3)
Allen Lib41527d2017-06-22 17:28:00 -07001232 self.assertEqual(self._job.first_offload_start, t1)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001233
Jakob Juelich24f22c22014-09-26 11:46:11 -07001234
J. Richard Barnetteea785362014-03-17 16:00:53 -07001235 def test_case_1_no_expiration(self):
1236 """Test a series of `enqueue_offload()` calls with `days_old` of 0.
1237
1238 This tests that offload works as expected if calls are
1239 made both before and after the job becomes expired.
1240
1241 """
1242 self._offload_unexpired_job(0)
1243 self._job.set_finished(0)
1244 self._offload_expired_job(0)
1245
Jakob Juelich24f22c22014-09-26 11:46:11 -07001246
J. Richard Barnetteea785362014-03-17 16:00:53 -07001247 def test_case_2_no_expiration(self):
1248 """Test a series of `enqueue_offload()` calls with `days_old` of 0.
1249
1250 This tests that offload works as expected if calls are made
1251 only after the job becomes expired.
1252
1253 """
1254 self._job.set_finished(0)
1255 self._offload_expired_job(0)
1256
Jakob Juelich24f22c22014-09-26 11:46:11 -07001257
J. Richard Barnetteea785362014-03-17 16:00:53 -07001258 def test_case_1_with_expiration(self):
1259 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1260
1261 This tests that offload works as expected if calls are made
1262 before the job finishes, before the job expires, and after
1263 the job expires.
1264
1265 """
1266 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1267 self._job.set_finished(_TEST_EXPIRATION_AGE)
1268 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1269 self._job.set_expired(_TEST_EXPIRATION_AGE)
1270 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1271
Jakob Juelich24f22c22014-09-26 11:46:11 -07001272
J. Richard Barnetteea785362014-03-17 16:00:53 -07001273 def test_case_2_with_expiration(self):
1274 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1275
1276 This tests that offload works as expected if calls are made
1277 between finishing and expiration, and after the job expires.
1278
1279 """
1280 self._job.set_finished(_TEST_EXPIRATION_AGE)
1281 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1282 self._job.set_expired(_TEST_EXPIRATION_AGE)
1283 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1284
Jakob Juelich24f22c22014-09-26 11:46:11 -07001285
J. Richard Barnetteea785362014-03-17 16:00:53 -07001286 def test_case_3_with_expiration(self):
1287 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1288
1289 This tests that offload works as expected if calls are made
1290 only before finishing and after expiration.
1291
1292 """
1293 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1294 self._job.set_expired(_TEST_EXPIRATION_AGE)
1295 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1296
Jakob Juelich24f22c22014-09-26 11:46:11 -07001297
J. Richard Barnetteea785362014-03-17 16:00:53 -07001298 def test_case_4_with_expiration(self):
1299 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1300
1301 This tests that offload works as expected if calls are made
1302 only after expiration.
1303
1304 """
1305 self._job.set_expired(_TEST_EXPIRATION_AGE)
1306 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1307
1308
1309class GetJobDirectoriesTests(_TempResultsDirTestBase):
1310 """Tests for `_JobDirectory.get_job_directories()`."""
1311
J. Richard Barnetteea785362014-03-17 16:00:53 -07001312 def setUp(self):
1313 super(GetJobDirectoriesTests, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -07001314 self.make_job_hierarchy()
1315 os.mkdir('not-a-job')
1316 open('not-a-dir', 'w').close()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001317
Jakob Juelich24f22c22014-09-26 11:46:11 -07001318
J. Richard Barnetteea785362014-03-17 16:00:53 -07001319 def _run_get_directories(self, cls, expected_list):
1320 """Test `get_job_directories()` for the given class.
1321
1322 Calls the method, and asserts that the returned list of
1323 directories matches the expected return value.
1324
1325 @param expected_list Expected return value from the call.
1326 """
J. Richard Barnetteea785362014-03-17 16:00:53 -07001327 dirlist = cls.get_job_directories()
1328 self.assertEqual(set(dirlist), set(expected_list))
J. Richard Barnetteea785362014-03-17 16:00:53 -07001329
Jakob Juelich24f22c22014-09-26 11:46:11 -07001330
J. Richard Barnetteea785362014-03-17 16:00:53 -07001331 def test_get_regular_jobs(self):
1332 """Test `RegularJobDirectory.get_job_directories()`."""
1333 self._run_get_directories(job_directories.RegularJobDirectory,
J. Richard Barnette08800322014-05-16 14:49:46 -07001334 self.REGULAR_JOBLIST)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001335
Jakob Juelich24f22c22014-09-26 11:46:11 -07001336
J. Richard Barnetteea785362014-03-17 16:00:53 -07001337 def test_get_special_jobs(self):
1338 """Test `SpecialJobDirectory.get_job_directories()`."""
1339 self._run_get_directories(job_directories.SpecialJobDirectory,
J. Richard Barnette08800322014-05-16 14:49:46 -07001340 self.SPECIAL_JOBLIST)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001341
1342
1343class AddJobsTests(_TempResultsDirTestBase):
1344 """Tests for `Offloader._add_new_jobs()`."""
1345
J. Richard Barnette08800322014-05-16 14:49:46 -07001346 MOREJOBS = ['115-fubar', '116-fubar', '117-fubar', '118-snafu']
J. Richard Barnetteea785362014-03-17 16:00:53 -07001347
1348 def setUp(self):
1349 super(AddJobsTests, self).setUp()
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001350 self._initial_job_names = (
1351 set(self.REGULAR_JOBLIST) | set(self.SPECIAL_JOBLIST))
J. Richard Barnette08800322014-05-16 14:49:46 -07001352 self.make_job_hierarchy()
1353 self._offloader = gs_offloader.Offloader(_get_options(['-a']))
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001354 self.mox.StubOutWithMock(logging, 'debug')
J. Richard Barnetteea785362014-03-17 16:00:53 -07001355
Jakob Juelich24f22c22014-09-26 11:46:11 -07001356
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001357 def _run_add_new_jobs(self, expected_key_set):
J. Richard Barnetteea785362014-03-17 16:00:53 -07001358 """Basic test assertions for `_add_new_jobs()`.
1359
1360 Asserts the following:
1361 * The keys in the offloader's `_open_jobs` dictionary
1362 matches the expected set of keys.
1363 * For every job in `_open_jobs`, the job has the expected
1364 directory name.
1365
1366 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001367 count = len(expected_key_set) - len(self._offloader._open_jobs)
1368 logging.debug(mox.IgnoreArg(), count)
1369 self.mox.ReplayAll()
1370 self._offloader._add_new_jobs()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001371 self.assertEqual(expected_key_set,
1372 set(self._offloader._open_jobs.keys()))
1373 for jobkey, job in self._offloader._open_jobs.items():
Allen Lib41527d2017-06-22 17:28:00 -07001374 self.assertEqual(jobkey, job.dirname)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001375 self.mox.VerifyAll()
1376 self.mox.ResetAll()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001377
Jakob Juelich24f22c22014-09-26 11:46:11 -07001378
J. Richard Barnetteea785362014-03-17 16:00:53 -07001379 def test_add_jobs_empty(self):
1380 """Test adding jobs to an empty dictionary.
1381
1382 Calls the offloader's `_add_new_jobs()`, then perform
1383 the assertions of `self._check_open_jobs()`.
1384
1385 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001386 self._run_add_new_jobs(self._initial_job_names)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001387
Jakob Juelich24f22c22014-09-26 11:46:11 -07001388
J. Richard Barnetteea785362014-03-17 16:00:53 -07001389 def test_add_jobs_non_empty(self):
1390 """Test adding jobs to a non-empty dictionary.
1391
1392 Calls the offloader's `_add_new_jobs()` twice; once from
1393 initial conditions, and then again after adding more
1394 directories. After the second call, perform the assertions
1395 of `self._check_open_jobs()`. Additionally, assert that
1396 keys added by the first call still map to their original
1397 job object after the second call.
1398
1399 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001400 self._run_add_new_jobs(self._initial_job_names)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001401 jobs_copy = self._offloader._open_jobs.copy()
J. Richard Barnette08800322014-05-16 14:49:46 -07001402 for d in self.MOREJOBS:
1403 os.mkdir(d)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001404 self._run_add_new_jobs(self._initial_job_names |
1405 set(self.MOREJOBS))
J. Richard Barnetteea785362014-03-17 16:00:53 -07001406 for key in jobs_copy.keys():
1407 self.assertIs(jobs_copy[key],
1408 self._offloader._open_jobs[key])
1409
1410
J. Richard Barnetteea785362014-03-17 16:00:53 -07001411class ReportingTests(_TempResultsDirTestBase):
Allen Lib41527d2017-06-22 17:28:00 -07001412 """Tests for `Offloader._report_failed_jobs()`."""
J. Richard Barnetteea785362014-03-17 16:00:53 -07001413
J. Richard Barnetteea785362014-03-17 16:00:53 -07001414 def setUp(self):
1415 super(ReportingTests, self).setUp()
1416 self._offloader = gs_offloader.Offloader(_get_options([]))
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001417 self.mox.StubOutWithMock(self._offloader, '_log_failed_jobs_locally')
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001418 self.mox.StubOutWithMock(logging, 'debug')
J. Richard Barnetteea785362014-03-17 16:00:53 -07001419
Jakob Juelich24f22c22014-09-26 11:46:11 -07001420
J. Richard Barnetteea785362014-03-17 16:00:53 -07001421 def _add_job(self, jobdir):
1422 """Add a job to the dictionary of unfinished jobs."""
1423 j = self.make_job(jobdir)
Allen Lib41527d2017-06-22 17:28:00 -07001424 self._offloader._open_jobs[j.dirname] = j
J. Richard Barnetteea785362014-03-17 16:00:53 -07001425 return j
1426
Jakob Juelich24f22c22014-09-26 11:46:11 -07001427
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001428 def _expect_log_message(self, new_open_jobs, with_failures):
1429 """Mock expected logging calls.
1430
Allen Lib41527d2017-06-22 17:28:00 -07001431 `_report_failed_jobs()` logs one message with the number
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001432 of jobs removed from the open job set and the number of jobs
1433 still remaining. Additionally, if there are reportable
1434 jobs, then it logs the number of jobs that haven't yet
1435 offloaded.
1436
1437 This sets up the logging calls using `new_open_jobs` to
1438 figure the job counts. If `with_failures` is true, then
1439 the log message is set up assuming that all jobs in
1440 `new_open_jobs` have offload failures.
1441
1442 @param new_open_jobs New job set for calculating counts
1443 in the messages.
1444 @param with_failures Whether the log message with a
1445 failure count is expected.
1446
1447 """
1448 count = len(self._offloader._open_jobs) - len(new_open_jobs)
1449 logging.debug(mox.IgnoreArg(), count, len(new_open_jobs))
1450 if with_failures:
1451 logging.debug(mox.IgnoreArg(), len(new_open_jobs))
1452
Jakob Juelich24f22c22014-09-26 11:46:11 -07001453
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001454 def _run_update(self, new_open_jobs):
Allen Lib41527d2017-06-22 17:28:00 -07001455 """Call `_report_failed_jobs()`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001456
1457 Initial conditions are set up by the caller. This calls
Allen Lib41527d2017-06-22 17:28:00 -07001458 `_report_failed_jobs()` once, and then checks these
J. Richard Barnetteea785362014-03-17 16:00:53 -07001459 assertions:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001460 * The offloader's new `_open_jobs` field contains only
1461 the entries in `new_open_jobs`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001462
1463 @param new_open_jobs A dictionary representing the expected
1464 new value of the offloader's
1465 `_open_jobs` field.
1466 """
1467 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -07001468 self._offloader._report_failed_jobs()
1469 self._offloader._remove_offloaded_jobs()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001470 self.assertEqual(self._offloader._open_jobs, new_open_jobs)
1471 self.mox.VerifyAll()
1472 self.mox.ResetAll()
1473
Jakob Juelich24f22c22014-09-26 11:46:11 -07001474
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001475 def _expect_failed_jobs(self, failed_jobs):
1476 """Mock expected call to log the failed jobs on local disk.
1477
1478 TODO(crbug.com/686904): The fact that we have to mock an internal
1479 function for this test is evidence that we need to pull out the local
1480 file formatter in its own object in a future CL.
1481
1482 @param failed_jobs: The list of jobs being logged as failed.
1483 """
1484 self._offloader._log_failed_jobs_locally(failed_jobs)
1485
1486
J. Richard Barnetteea785362014-03-17 16:00:53 -07001487 def test_no_jobs(self):
Allen Lib41527d2017-06-22 17:28:00 -07001488 """Test `_report_failed_jobs()` with no open jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001489
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001490 Initial conditions are an empty `_open_jobs` list.
1491 Expected result is an empty `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001492
1493 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001494 self._expect_log_message({}, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001495 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001496 self._run_update({})
J. Richard Barnetteea785362014-03-17 16:00:53 -07001497
Jakob Juelich24f22c22014-09-26 11:46:11 -07001498
J. Richard Barnetteea785362014-03-17 16:00:53 -07001499 def test_all_completed(self):
Allen Lib41527d2017-06-22 17:28:00 -07001500 """Test `_report_failed_jobs()` with only complete jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001501
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001502 Initial conditions are an `_open_jobs` list consisting of only completed
1503 jobs.
1504 Expected result is an empty `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001505
1506 """
J. Richard Barnette08800322014-05-16 14:49:46 -07001507 for d in self.REGULAR_JOBLIST:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001508 self._add_job(d).set_complete()
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001509 self._expect_log_message({}, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001510 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001511 self._run_update({})
J. Richard Barnetteea785362014-03-17 16:00:53 -07001512
Jakob Juelich24f22c22014-09-26 11:46:11 -07001513
J. Richard Barnetteea785362014-03-17 16:00:53 -07001514 def test_none_finished(self):
Allen Lib41527d2017-06-22 17:28:00 -07001515 """Test `_report_failed_jobs()` with only unfinished jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001516
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001517 Initial conditions are an `_open_jobs` list consisting of only
1518 unfinished jobs.
1519 Expected result is no change to the `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001520
1521 """
J. Richard Barnette08800322014-05-16 14:49:46 -07001522 for d in self.REGULAR_JOBLIST:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001523 self._add_job(d)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001524 new_jobs = self._offloader._open_jobs.copy()
1525 self._expect_log_message(new_jobs, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001526 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001527 self._run_update(new_jobs)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001528
1529
Allen Lib41527d2017-06-22 17:28:00 -07001530class GsOffloaderMockTests(_TempResultsDirTestCase):
1531 """Tests using mock instead of mox."""
1532
1533 def setUp(self):
1534 super(GsOffloaderMockTests, self).setUp()
1535 alarm = mock.patch('signal.alarm', return_value=0)
1536 alarm.start()
1537 self.addCleanup(alarm.stop)
1538
1539 self._saved_loglevel = logging.getLogger().getEffectiveLevel()
1540 logging.getLogger().setLevel(logging.CRITICAL + 1)
1541
1542 self._job = self.make_job(self.REGULAR_JOBLIST[0])
1543
1544
1545 def test_offload_timeout_early(self):
1546 """Test that `offload_dir()` times out correctly.
1547
1548 This test triggers timeout at the earliest possible moment,
1549 at the first call to set the timeout alarm.
1550
1551 """
1552 signal.alarm.side_effect = [0, timeout_util.TimeoutError('fubar')]
1553 with mock.patch.object(gs_offloader, '_upload_cts_testresult',
1554 autospec=True) as upload:
1555 upload.return_value = None
1556 gs_offloader.GSOffloader(
1557 utils.DEFAULT_OFFLOAD_GSURI, False, 0).offload(
1558 self._job.queue_args[0],
1559 self._job.queue_args[1],
1560 self._job.queue_args[2])
1561 self.assertTrue(os.path.isdir(self._job.queue_args[0]))
1562
1563
1564 # TODO(ayatane): This tests passes when run locally, but it fails
1565 # when run on trybot. I have no idea why, but the assert isdir
1566 # fails.
1567 #
1568 # This test is also kind of redundant since we are using the timeout
1569 # from chromite which has its own tests.
1570 @unittest.skip('This fails on trybot')
1571 def test_offload_timeout_late(self):
1572 """Test that `offload_dir()` times out correctly.
1573
1574 This test triggers timeout at the latest possible moment, at
1575 the call to clear the timeout alarm.
1576
1577 """
1578 signal.alarm.side_effect = [0, 0, timeout_util.TimeoutError('fubar')]
1579 with mock.patch.object(gs_offloader, '_upload_cts_testresult',
1580 autospec=True) as upload, \
1581 mock.patch.object(gs_offloader, '_get_cmd_list',
1582 autospec=True) as get_cmd_list:
1583 upload.return_value = None
1584 get_cmd_list.return_value = ['test', '-d', self._job.queue_args[0]]
1585 gs_offloader.GSOffloader(
1586 utils.DEFAULT_OFFLOAD_GSURI, False, 0).offload(
1587 self._job.queue_args[0],
1588 self._job.queue_args[1],
1589 self._job.queue_args[2])
1590 self.assertTrue(os.path.isdir(self._job.queue_args[0]))
1591
1592
1593
J. Richard Barnetteea785362014-03-17 16:00:53 -07001594if __name__ == '__main__':
1595 unittest.main()