blob: 148fd1221a578728360833502c27a1f0ebd12920 [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
8import datetime
9import logging
10import os
11import shutil
J. Richard Barnette2e443ef2014-05-20 12:31:35 -070012import signal
Laurence Goodbyca7726d2017-02-14 17:09:07 -080013import stat
J. Richard Barnetteea785362014-03-17 16:00:53 -070014import sys
15import tempfile
16import time
17import unittest
18
Allen Li9579b382017-05-05 17:07:43 -070019import mock
J. Richard Barnetteea785362014-03-17 16:00:53 -070020import mox
21
22import common
Allen Li5ed7e632017-02-03 16:31:33 -080023from autotest_lib.client.common_lib import global_config
Dan Shi1b4c7c32015-10-05 10:38:57 -070024from autotest_lib.client.common_lib import time_utils
25from autotest_lib.client.common_lib import utils
Michael Tange8bc9592017-07-06 10:59:32 -070026#For unittest without cloud_client.proto compiled.
27try:
28 from autotest_lib.site_utils import cloud_console_client
29except ImportError:
30 cloud_console_client = None
Prathmesh Prabhubeb9e012017-01-30 16:18:39 -080031from autotest_lib.site_utils import gs_offloader
32from autotest_lib.site_utils import job_directories
Ningning Xia2d981ee2016-07-06 17:59:54 -070033from autotest_lib.tko import models
Allen Lib41527d2017-06-22 17:28:00 -070034from autotest_lib.utils import gslib
Michael Tang0f553bd2017-06-16 17:38:45 -070035from autotest_lib.site_utils import pubsub_utils
Allen Lib41527d2017-06-22 17:28:00 -070036from chromite.lib import timeout_util
Jakob Juelich24f22c22014-09-26 11:46:11 -070037
J. Richard Barnetteea785362014-03-17 16:00:53 -070038# Test value to use for `days_old`, if nothing else is required.
39_TEST_EXPIRATION_AGE = 7
40
41# When constructing sample time values for testing expiration,
42# allow this many seconds between the expiration time and the
43# current time.
44_MARGIN_SECS = 10.0
45
46
47def _get_options(argv):
48 """Helper function to exercise command line parsing.
49
50 @param argv Value of sys.argv to be parsed.
51
52 """
53 sys.argv = ['bogus.py'] + argv
54 return gs_offloader.parse_options()
55
56
Laurence Goodbyca7726d2017-02-14 17:09:07 -080057def is_fifo(path):
Allen Li93585382017-05-05 14:24:53 -070058 """Determines whether a path is a fifo.
59
60 @param path: fifo path string.
61 """
Laurence Goodbyca7726d2017-02-14 17:09:07 -080062 return stat.S_ISFIFO(os.lstat(path).st_mode)
63
64
Simran Basidd129972014-09-11 14:34:49 -070065class OffloaderOptionsTests(mox.MoxTestBase):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -070066 """Tests for the `Offloader` constructor.
67
68 Tests that offloader instance fields are set as expected
69 for given command line options.
70
71 """
72
Allen Li7402f092018-06-26 15:42:21 -070073 _REGULAR_ONLY = {job_directories.SwarmingJobDirectory,
74 job_directories.RegularJobDirectory}
75 _SPECIAL_ONLY = {job_directories.SwarmingJobDirectory,
76 job_directories.SpecialJobDirectory}
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -070077 _BOTH = _REGULAR_ONLY | _SPECIAL_ONLY
J. Richard Barnetteea785362014-03-17 16:00:53 -070078
Jakob Juelich24f22c22014-09-26 11:46:11 -070079
Simran Basidd129972014-09-11 14:34:49 -070080 def setUp(self):
81 super(OffloaderOptionsTests, self).setUp()
82 self.mox.StubOutWithMock(utils, 'get_offload_gsuri')
Simran Basif3e305f2014-10-03 14:43:53 -070083 gs_offloader.GS_OFFLOADING_ENABLED = True
Michael Tang0df2eb42016-05-13 19:06:54 -070084 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
Simran Basidd129972014-09-11 14:34:49 -070085
Jakob Juelich24f22c22014-09-26 11:46:11 -070086
Allen Lib41527d2017-06-22 17:28:00 -070087 def _mock_get_sub_offloader(self, is_moblab, multiprocessing=False,
Michael Tang0f553bd2017-06-16 17:38:45 -070088 console_client=None, delete_age=0):
Simran Basidd129972014-09-11 14:34:49 -070089 """Mock the process of getting the offload_dir function."""
90 if is_moblab:
91 expected_gsuri = '%sresults/%s/%s/' % (
92 global_config.global_config.get_config_value(
93 'CROS', 'image_storage_server'),
94 'Fa:ke:ma:c0:12:34', 'rand0m-uu1d')
95 else:
96 expected_gsuri = utils.DEFAULT_OFFLOAD_GSURI
97 utils.get_offload_gsuri().AndReturn(expected_gsuri)
Allen Lib41527d2017-06-22 17:28:00 -070098 sub_offloader = gs_offloader.GSOffloader(expected_gsuri,
Michael Tang0f553bd2017-06-16 17:38:45 -070099 multiprocessing, delete_age, console_client)
Allen Lib41527d2017-06-22 17:28:00 -0700100 self.mox.StubOutWithMock(gs_offloader, 'GSOffloader')
Michael Tange8bc9592017-07-06 10:59:32 -0700101 if cloud_console_client:
102 self.mox.StubOutWithMock(cloud_console_client,
103 'is_cloud_notification_enabled')
Michael Tang0f553bd2017-06-16 17:38:45 -0700104 if console_client:
105 cloud_console_client.is_cloud_notification_enabled().AndReturn(True)
106 gs_offloader.GSOffloader(
107 expected_gsuri, multiprocessing, delete_age,
108 mox.IsA(cloud_console_client.PubSubBasedClient)).AndReturn(
109 sub_offloader)
110 else:
Michael Tange8bc9592017-07-06 10:59:32 -0700111 if cloud_console_client:
112 cloud_console_client.is_cloud_notification_enabled().AndReturn(
113 False)
Michael Tang0f553bd2017-06-16 17:38:45 -0700114 gs_offloader.GSOffloader(
115 expected_gsuri, multiprocessing, delete_age, None).AndReturn(
116 sub_offloader)
Simran Basidd129972014-09-11 14:34:49 -0700117 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -0700118 return sub_offloader
Simran Basidd129972014-09-11 14:34:49 -0700119
Jakob Juelich24f22c22014-09-26 11:46:11 -0700120
J. Richard Barnetteea785362014-03-17 16:00:53 -0700121 def test_process_no_options(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700122 """Test default offloader options."""
Allen Lib41527d2017-06-22 17:28:00 -0700123 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700124 offloader = gs_offloader.Offloader(_get_options([]))
125 self.assertEqual(set(offloader._jobdir_classes),
126 self._REGULAR_ONLY)
127 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700128 self.assertEqual(offloader._gs_offloader,
129 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800130 self.assertEqual(offloader._upload_age_limit, 0)
131 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700132
Jakob Juelich24f22c22014-09-26 11:46:11 -0700133
J. Richard Barnetteea785362014-03-17 16:00:53 -0700134 def test_process_all_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700135 """Test offloader handling for the --all option."""
Allen Lib41527d2017-06-22 17:28:00 -0700136 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700137 offloader = gs_offloader.Offloader(_get_options(['--all']))
138 self.assertEqual(set(offloader._jobdir_classes), self._BOTH)
139 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700140 self.assertEqual(offloader._gs_offloader,
141 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800142 self.assertEqual(offloader._upload_age_limit, 0)
143 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700144
Jakob Juelich24f22c22014-09-26 11:46:11 -0700145
J. Richard Barnetteea785362014-03-17 16:00:53 -0700146 def test_process_hosts_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700147 """Test offloader handling for the --hosts option."""
Allen Lib41527d2017-06-22 17:28:00 -0700148 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700149 offloader = gs_offloader.Offloader(
150 _get_options(['--hosts']))
151 self.assertEqual(set(offloader._jobdir_classes),
152 self._SPECIAL_ONLY)
153 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700154 self.assertEqual(offloader._gs_offloader,
155 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800156 self.assertEqual(offloader._upload_age_limit, 0)
157 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700158
Jakob Juelich24f22c22014-09-26 11:46:11 -0700159
J. Richard Barnetteea785362014-03-17 16:00:53 -0700160 def test_parallelism_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700161 """Test offloader handling for the --parallelism option."""
Allen Lib41527d2017-06-22 17:28:00 -0700162 sub_offloader = self._mock_get_sub_offloader(False)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700163 offloader = gs_offloader.Offloader(
164 _get_options(['--parallelism', '2']))
165 self.assertEqual(set(offloader._jobdir_classes),
166 self._REGULAR_ONLY)
167 self.assertEqual(offloader._processes, 2)
Allen Lib41527d2017-06-22 17:28:00 -0700168 self.assertEqual(offloader._gs_offloader,
169 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800170 self.assertEqual(offloader._upload_age_limit, 0)
171 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700172
Jakob Juelich24f22c22014-09-26 11:46:11 -0700173
J. Richard Barnetteea785362014-03-17 16:00:53 -0700174 def test_delete_only_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700175 """Test offloader handling for the --delete_only option."""
176 offloader = gs_offloader.Offloader(
177 _get_options(['--delete_only']))
178 self.assertEqual(set(offloader._jobdir_classes),
179 self._REGULAR_ONLY)
180 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700181 self.assertIsInstance(offloader._gs_offloader,
182 gs_offloader.FakeGSOffloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800183 self.assertEqual(offloader._upload_age_limit, 0)
184 self.assertEqual(offloader._delete_age_limit, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700185
Jakob Juelich24f22c22014-09-26 11:46:11 -0700186
Simran Basidf4751e2014-10-10 14:19:22 -0700187 def test_days_old_option(self):
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700188 """Test offloader handling for the --days_old option."""
Allen Lib41527d2017-06-22 17:28:00 -0700189 sub_offloader = self._mock_get_sub_offloader(False, delete_age=7)
J. Richard Barnetteef4b47d2014-05-19 07:52:08 -0700190 offloader = gs_offloader.Offloader(
191 _get_options(['--days_old', '7']))
192 self.assertEqual(set(offloader._jobdir_classes),
193 self._REGULAR_ONLY)
194 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700195 self.assertEqual(offloader._gs_offloader,
196 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800197 self.assertEqual(offloader._upload_age_limit, 7)
198 self.assertEqual(offloader._delete_age_limit, 7)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700199
Jakob Juelich24f22c22014-09-26 11:46:11 -0700200
Simran Basidd129972014-09-11 14:34:49 -0700201 def test_moblab_gsuri_generation(self):
202 """Test offloader construction for Moblab."""
Allen Lib41527d2017-06-22 17:28:00 -0700203 sub_offloader = self._mock_get_sub_offloader(True)
Simran Basidd129972014-09-11 14:34:49 -0700204 offloader = gs_offloader.Offloader(_get_options([]))
205 self.assertEqual(set(offloader._jobdir_classes),
206 self._REGULAR_ONLY)
207 self.assertEqual(offloader._processes, 1)
Allen Lib41527d2017-06-22 17:28:00 -0700208 self.assertEqual(offloader._gs_offloader,
209 sub_offloader)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800210 self.assertEqual(offloader._upload_age_limit, 0)
211 self.assertEqual(offloader._delete_age_limit, 0)
Simran Basidd129972014-09-11 14:34:49 -0700212
J. Richard Barnetteea785362014-03-17 16:00:53 -0700213
Simran Basif3e305f2014-10-03 14:43:53 -0700214 def test_globalconfig_offloading_flag(self):
215 """Test enabling of --delete_only via global_config."""
216 gs_offloader.GS_OFFLOADING_ENABLED = False
217 offloader = gs_offloader.Offloader(
218 _get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700219 self.assertIsInstance(offloader._gs_offloader,
220 gs_offloader.FakeGSOffloader)
Simran Basif3e305f2014-10-03 14:43:53 -0700221
Michael Tang0df2eb42016-05-13 19:06:54 -0700222 def test_offloader_multiprocessing_flag_set(self):
223 """Test multiprocessing is set."""
Allen Lib41527d2017-06-22 17:28:00 -0700224 sub_offloader = self._mock_get_sub_offloader(True, True)
Michael Tang0df2eb42016-05-13 19:06:54 -0700225 offloader = gs_offloader.Offloader(_get_options(['-m']))
Allen Lib41527d2017-06-22 17:28:00 -0700226 self.assertEqual(offloader._gs_offloader,
227 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700228 self.mox.VerifyAll()
229
230 def test_offloader_multiprocessing_flag_not_set_default_false(self):
231 """Test multiprocessing is set."""
232 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
Allen Lib41527d2017-06-22 17:28:00 -0700233 sub_offloader = self._mock_get_sub_offloader(True, False)
Michael Tang0df2eb42016-05-13 19:06:54 -0700234 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700235 self.assertEqual(offloader._gs_offloader,
236 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700237 self.mox.VerifyAll()
238
239 def test_offloader_multiprocessing_flag_not_set_default_true(self):
240 """Test multiprocessing is set."""
241 gs_offloader.GS_OFFLOADER_MULTIPROCESSING = True
Allen Lib41527d2017-06-22 17:28:00 -0700242 sub_offloader = self._mock_get_sub_offloader(True, True)
Michael Tang0df2eb42016-05-13 19:06:54 -0700243 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700244 self.assertEqual(offloader._gs_offloader,
245 sub_offloader)
Michael Tang0df2eb42016-05-13 19:06:54 -0700246 self.mox.VerifyAll()
247
Michael Tang97d188c2016-06-25 11:18:42 -0700248
Michael Tang0f553bd2017-06-16 17:38:45 -0700249 def test_offloader_pubsub_enabled(self):
Michael Tang97d188c2016-06-25 11:18:42 -0700250 """Test multiprocessing is set."""
Michael Tange8bc9592017-07-06 10:59:32 -0700251 if not cloud_console_client:
252 return
Michael Tang0f553bd2017-06-16 17:38:45 -0700253 self.mox.StubOutWithMock(pubsub_utils, "PubSubClient")
254 sub_offloader = self._mock_get_sub_offloader(True, False,
255 cloud_console_client.PubSubBasedClient())
256 offloader = gs_offloader.Offloader(_get_options([]))
Allen Lib41527d2017-06-22 17:28:00 -0700257 self.assertEqual(offloader._gs_offloader,
258 sub_offloader)
Michael Tang97d188c2016-06-25 11:18:42 -0700259 self.mox.VerifyAll()
260
Simran Basif3e305f2014-10-03 14:43:53 -0700261
J. Richard Barnetteea785362014-03-17 16:00:53 -0700262def _make_timestamp(age_limit, is_expired):
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800263 """Create a timestamp for use by `job_directories.is_job_expired()`.
J. Richard Barnetteea785362014-03-17 16:00:53 -0700264
265 The timestamp will meet the syntactic requirements for
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800266 timestamps used as input to `is_job_expired()`. If
J. Richard Barnetteea785362014-03-17 16:00:53 -0700267 `is_expired` is true, the timestamp will be older than
268 `age_limit` days before the current time; otherwise, the
269 date will be younger.
270
271 @param age_limit The number of days before expiration of the
272 target timestamp.
273 @param is_expired Whether the timestamp should be expired
274 relative to `age_limit`.
275
276 """
277 seconds = -_MARGIN_SECS
278 if is_expired:
279 seconds = -seconds
280 delta = datetime.timedelta(days=age_limit, seconds=seconds)
281 reference_time = datetime.datetime.now() - delta
Dan Shidfea3682014-08-10 23:38:40 -0700282 return reference_time.strftime(time_utils.TIME_FMT)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700283
284
285class JobExpirationTests(unittest.TestCase):
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800286 """Tests to exercise `job_directories.is_job_expired()`."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700287
288 def test_expired(self):
289 """Test detection of an expired job."""
290 timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, True)
291 self.assertTrue(
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800292 job_directories.is_job_expired(
J. Richard Barnetteea785362014-03-17 16:00:53 -0700293 _TEST_EXPIRATION_AGE, timestamp))
294
295
296 def test_alive(self):
297 """Test detection of a job that's not expired."""
298 # N.B. This test may fail if its run time exceeds more than
299 # about _MARGIN_SECS seconds.
300 timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, False)
301 self.assertFalse(
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800302 job_directories.is_job_expired(
J. Richard Barnetteea785362014-03-17 16:00:53 -0700303 _TEST_EXPIRATION_AGE, timestamp))
304
305
306class _MockJobDirectory(job_directories._JobDirectory):
307 """Subclass of `_JobDirectory` used as a helper for tests."""
308
309 GLOB_PATTERN = '[0-9]*-*'
310
Jakob Juelich24f22c22014-09-26 11:46:11 -0700311
J. Richard Barnetteea785362014-03-17 16:00:53 -0700312 def __init__(self, resultsdir):
313 """Create new job in initial state."""
314 super(_MockJobDirectory, self).__init__(resultsdir)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700315 self._timestamp = None
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800316 self.queue_args = [resultsdir, os.path.dirname(resultsdir), self._timestamp]
J. Richard Barnetteea785362014-03-17 16:00:53 -0700317
Jakob Juelich24f22c22014-09-26 11:46:11 -0700318
J. Richard Barnetteea785362014-03-17 16:00:53 -0700319 def get_timestamp_if_finished(self):
320 return self._timestamp
321
Jakob Juelich24f22c22014-09-26 11:46:11 -0700322
J. Richard Barnetteea785362014-03-17 16:00:53 -0700323 def set_finished(self, days_old):
324 """Make this job appear to be finished.
325
326 After calling this function, calls to `enqueue_offload()`
327 will find this job as finished, but not expired and ready
328 for offload. Note that when `days_old` is 0,
329 `enqueue_offload()` will treat a finished job as eligible
330 for offload.
331
332 @param days_old The value of the `days_old` parameter that
333 will be passed to `enqueue_offload()` for
334 testing.
335
336 """
337 self._timestamp = _make_timestamp(days_old, False)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800338 self.queue_args[2] = self._timestamp
J. Richard Barnetteea785362014-03-17 16:00:53 -0700339
Jakob Juelich24f22c22014-09-26 11:46:11 -0700340
J. Richard Barnetteea785362014-03-17 16:00:53 -0700341 def set_expired(self, days_old):
342 """Make this job eligible to be offloaded.
343
344 After calling this function, calls to `offload` will attempt
345 to offload this job.
346
347 @param days_old The value of the `days_old` parameter that
348 will be passed to `enqueue_offload()` for
349 testing.
350
351 """
352 self._timestamp = _make_timestamp(days_old, True)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800353 self.queue_args[2] = self._timestamp
J. Richard Barnetteea785362014-03-17 16:00:53 -0700354
Jakob Juelich24f22c22014-09-26 11:46:11 -0700355
J. Richard Barnetteea785362014-03-17 16:00:53 -0700356 def set_incomplete(self):
357 """Make this job appear to have failed offload just once."""
Allen Lib41527d2017-06-22 17:28:00 -0700358 self.offload_count += 1
359 self.first_offload_start = time.time()
360 if not os.path.isdir(self.dirname):
361 os.mkdir(self.dirname)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700362
Jakob Juelich24f22c22014-09-26 11:46:11 -0700363
J. Richard Barnetteea785362014-03-17 16:00:53 -0700364 def set_reportable(self):
365 """Make this job be reportable."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700366 self.set_incomplete()
Allen Lib41527d2017-06-22 17:28:00 -0700367 self.offload_count += 1
J. Richard Barnetteea785362014-03-17 16:00:53 -0700368
Jakob Juelich24f22c22014-09-26 11:46:11 -0700369
J. Richard Barnetteea785362014-03-17 16:00:53 -0700370 def set_complete(self):
371 """Make this job be completed."""
Allen Lib41527d2017-06-22 17:28:00 -0700372 self.offload_count += 1
373 if os.path.isdir(self.dirname):
374 os.rmdir(self.dirname)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700375
376
Simran Basi1e10e922015-04-16 15:09:56 -0700377 def process_gs_instructions(self):
378 """Always still offload the job directory."""
379 return True
380
381
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700382class CommandListTests(unittest.TestCase):
Allen Lib41527d2017-06-22 17:28:00 -0700383 """Tests for `_get_cmd_list()`."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700384
MK Ryue93c8572015-08-11 11:53:00 -0700385 def _command_list_assertions(self, job, use_rsync=True, multi=False):
Allen Lib41527d2017-06-22 17:28:00 -0700386 """Call `_get_cmd_list()` and check the return value.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700387
388 Check the following assertions:
389 * The command name (argv[0]) is 'gsutil'.
MK Ryue93c8572015-08-11 11:53:00 -0700390 * '-m' option (argv[1]) is on when the argument, multi, is True.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700391 * The arguments contain the 'cp' subcommand.
392 * The next-to-last argument (the source directory) is the
393 job's `queue_args[0]`.
Simran Basidd129972014-09-11 14:34:49 -0700394 * The last argument (the destination URL) is the job's
395 'queue_args[1]'.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700396
397 @param job A job with properly calculated arguments to
Allen Lib41527d2017-06-22 17:28:00 -0700398 `_get_cmd_list()`
MK Ryue93c8572015-08-11 11:53:00 -0700399 @param use_rsync True when using 'rsync'. False when using 'cp'.
400 @param multi True when using '-m' option for gsutil.
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700401
402 """
Jakob Juelich24f22c22014-09-26 11:46:11 -0700403 test_bucket_uri = 'gs://a-test-bucket'
404
405 gs_offloader.USE_RSYNC_ENABLED = use_rsync
406
Allen Lib41527d2017-06-22 17:28:00 -0700407 command = gs_offloader._get_cmd_list(
MK Ryue93c8572015-08-11 11:53:00 -0700408 multi, job.queue_args[0],
409 os.path.join(test_bucket_uri, job.queue_args[1]))
Jakob Juelich24f22c22014-09-26 11:46:11 -0700410
Dan Shi365049f2017-05-28 08:00:02 +0000411 self.assertEqual(command[0], 'gsutil')
MK Ryue93c8572015-08-11 11:53:00 -0700412 if multi:
413 self.assertEqual(command[1], '-m')
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700414 self.assertEqual(command[-2], job.queue_args[0])
Jakob Juelich24f22c22014-09-26 11:46:11 -0700415
416 if use_rsync:
417 self.assertTrue('rsync' in command)
418 self.assertEqual(command[-1],
419 os.path.join(test_bucket_uri, job.queue_args[0]))
420 else:
421 self.assertTrue('cp' in command)
422 self.assertEqual(command[-1],
423 os.path.join(test_bucket_uri, job.queue_args[1]))
424
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700425
Allen Lib41527d2017-06-22 17:28:00 -0700426 def test__get_cmd_list_regular(self):
427 """Test `_get_cmd_list()` as for a regular job."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700428 job = _MockJobDirectory('118-debug')
429 self._command_list_assertions(job)
430
Jakob Juelich24f22c22014-09-26 11:46:11 -0700431
Allen Lib41527d2017-06-22 17:28:00 -0700432 def test__get_cmd_list_special(self):
433 """Test `_get_cmd_list()` as for a special job."""
J. Richard Barnette9f4be0d2014-05-20 12:28:31 -0700434 job = _MockJobDirectory('hosts/host1/118-reset')
435 self._command_list_assertions(job)
436
437
Jakob Juelich24f22c22014-09-26 11:46:11 -0700438 def test_get_cmd_list_regular_no_rsync(self):
Allen Lib41527d2017-06-22 17:28:00 -0700439 """Test `_get_cmd_list()` as for a regular job."""
Jakob Juelich24f22c22014-09-26 11:46:11 -0700440 job = _MockJobDirectory('118-debug')
441 self._command_list_assertions(job, use_rsync=False)
442
443
444 def test_get_cmd_list_special_no_rsync(self):
Allen Lib41527d2017-06-22 17:28:00 -0700445 """Test `_get_cmd_list()` as for a special job."""
Jakob Juelich24f22c22014-09-26 11:46:11 -0700446 job = _MockJobDirectory('hosts/host1/118-reset')
447 self._command_list_assertions(job, use_rsync=False)
448
449
MK Ryue93c8572015-08-11 11:53:00 -0700450 def test_get_cmd_list_regular_multi(self):
Allen Lib41527d2017-06-22 17:28:00 -0700451 """Test `_get_cmd_list()` as for a regular job with True multi."""
MK Ryue93c8572015-08-11 11:53:00 -0700452 job = _MockJobDirectory('118-debug')
453 self._command_list_assertions(job, multi=True)
454
455
Allen Lib41527d2017-06-22 17:28:00 -0700456 def test__get_cmd_list_special_multi(self):
457 """Test `_get_cmd_list()` as for a special job with True multi."""
MK Ryue93c8572015-08-11 11:53:00 -0700458 job = _MockJobDirectory('hosts/host1/118-reset')
459 self._command_list_assertions(job, multi=True)
460
461
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700462class _MockJob(object):
463 """Class to mock the return value of `AFE.get_jobs()`."""
464 def __init__(self, created):
465 self.created_on = created
466
467
468class _MockHostQueueEntry(object):
469 """Class to mock the return value of `AFE.get_host_queue_entries()`."""
470 def __init__(self, finished):
471 self.finished_on = finished
472
473
474class _MockSpecialTask(object):
475 """Class to mock the return value of `AFE.get_special_tasks()`."""
476 def __init__(self, finished):
477 self.time_finished = finished
478
479
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700480class JobDirectorySubclassTests(mox.MoxTestBase):
481 """Test specific to RegularJobDirectory and SpecialJobDirectory.
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700482
483 This provides coverage for the implementation in both
484 RegularJobDirectory and SpecialJobDirectory.
485
486 """
487
488 def setUp(self):
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700489 super(JobDirectorySubclassTests, self).setUp()
Prathmesh Prabhua4557032018-05-22 22:47:37 -0700490 self.mox.StubOutWithMock(job_directories, '_AFE')
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700491
Jakob Juelich24f22c22014-09-26 11:46:11 -0700492
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700493 def test_regular_job_fields(self):
494 """Test the constructor for `RegularJobDirectory`.
495
Allen Lib41527d2017-06-22 17:28:00 -0700496 Construct a regular job, and assert that the `dirname`
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700497 and `_id` attributes are set as expected.
498
499 """
500 resultsdir = '118-fubar'
501 job = job_directories.RegularJobDirectory(resultsdir)
Allen Lib41527d2017-06-22 17:28:00 -0700502 self.assertEqual(job.dirname, resultsdir)
Prathmesh Prabhu28a46512018-05-11 17:40:29 -0700503 self.assertEqual(job._id, '118')
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700504
Jakob Juelich24f22c22014-09-26 11:46:11 -0700505
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700506 def test_special_job_fields(self):
507 """Test the constructor for `SpecialJobDirectory`.
508
Allen Lib41527d2017-06-22 17:28:00 -0700509 Construct a special job, and assert that the `dirname`
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700510 and `_id` attributes are set as expected.
511
512 """
513 destdir = 'hosts/host1'
514 resultsdir = destdir + '/118-reset'
515 job = job_directories.SpecialJobDirectory(resultsdir)
Allen Lib41527d2017-06-22 17:28:00 -0700516 self.assertEqual(job.dirname, resultsdir)
Prathmesh Prabhu28a46512018-05-11 17:40:29 -0700517 self.assertEqual(job._id, '118')
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700518
Jakob Juelich24f22c22014-09-26 11:46:11 -0700519
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700520 def _check_finished_job(self, jobtime, hqetimes, expected):
521 """Mock and test behavior of a finished job.
522
523 Initialize the mocks for a call to
524 `get_timestamp_if_finished()`, then simulate one call.
525 Assert that the returned timestamp matches the passed
526 in expected value.
527
528 @param jobtime Time used to construct a _MockJob object.
529 @param hqetimes List of times used to construct
530 _MockHostQueueEntry objects.
531 @param expected Expected time to be returned by
532 get_timestamp_if_finished
533
534 """
535 job = job_directories.RegularJobDirectory('118-fubar')
536 job_directories._AFE.get_jobs(
537 id=job._id, finished=True).AndReturn(
538 [_MockJob(jobtime)])
539 job_directories._AFE.get_host_queue_entries(
540 finished_on__isnull=False,
541 job_id=job._id).AndReturn(
542 [_MockHostQueueEntry(t) for t in hqetimes])
543 self.mox.ReplayAll()
544 self.assertEqual(expected, job.get_timestamp_if_finished())
545 self.mox.VerifyAll()
546
547
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700548 def test_finished_regular_job(self):
549 """Test getting the timestamp for a finished regular job.
550
551 Tests the return value for
552 `RegularJobDirectory.get_timestamp_if_finished()` when
553 the AFE indicates the job is finished.
554
555 """
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700556 created_timestamp = _make_timestamp(1, True)
557 hqe_timestamp = _make_timestamp(0, True)
558 self._check_finished_job(created_timestamp,
559 [hqe_timestamp],
560 hqe_timestamp)
Simran Basifb98e462014-08-18 12:35:44 -0700561
Jakob Juelich24f22c22014-09-26 11:46:11 -0700562
Simran Basifb98e462014-08-18 12:35:44 -0700563 def test_finished_regular_job_multiple_hqes(self):
564 """Test getting the timestamp for a regular job with multiple hqes.
565
566 Tests the return value for
567 `RegularJobDirectory.get_timestamp_if_finished()` when
568 the AFE indicates the job is finished and the job has multiple host
569 queue entries.
570
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700571 Tests that the returned timestamp is the latest timestamp in
572 the list of HQEs, regardless of the returned order.
573
Simran Basifb98e462014-08-18 12:35:44 -0700574 """
Simran Basifb98e462014-08-18 12:35:44 -0700575 created_timestamp = _make_timestamp(2, True)
576 older_hqe_timestamp = _make_timestamp(1, True)
577 newer_hqe_timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700578 hqe_list = [older_hqe_timestamp,
579 newer_hqe_timestamp]
580 self._check_finished_job(created_timestamp,
581 hqe_list,
582 newer_hqe_timestamp)
583 self.mox.ResetAll()
584 hqe_list.reverse()
585 self._check_finished_job(created_timestamp,
586 hqe_list,
587 newer_hqe_timestamp)
Simran Basifb98e462014-08-18 12:35:44 -0700588
Jakob Juelich24f22c22014-09-26 11:46:11 -0700589
Simran Basifb98e462014-08-18 12:35:44 -0700590 def test_finished_regular_job_null_finished_times(self):
591 """Test getting the timestamp for an aborted regular job.
592
593 Tests the return value for
594 `RegularJobDirectory.get_timestamp_if_finished()` when
595 the AFE indicates the job is finished and the job has aborted host
596 queue entries.
597
598 """
Simran Basifb98e462014-08-18 12:35:44 -0700599 timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700600 self._check_finished_job(timestamp, [], timestamp)
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700601
Jakob Juelich24f22c22014-09-26 11:46:11 -0700602
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700603 def test_unfinished_regular_job(self):
604 """Test getting the timestamp for an unfinished regular job.
605
606 Tests the return value for
607 `RegularJobDirectory.get_timestamp_if_finished()` when
608 the AFE indicates the job is not finished.
609
610 """
611 job = job_directories.RegularJobDirectory('118-fubar')
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700612 job_directories._AFE.get_jobs(
613 id=job._id, finished=True).AndReturn([])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700614 self.mox.ReplayAll()
615 self.assertIsNone(job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700616 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700617
Jakob Juelich24f22c22014-09-26 11:46:11 -0700618
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700619 def test_finished_special_job(self):
620 """Test getting the timestamp for a finished special job.
621
622 Tests the return value for
623 `SpecialJobDirectory.get_timestamp_if_finished()` when
624 the AFE indicates the job is finished.
625
626 """
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700627 job = job_directories.SpecialJobDirectory(
628 'hosts/host1/118-reset')
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700629 timestamp = _make_timestamp(0, True)
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700630 job_directories._AFE.get_special_tasks(
631 id=job._id, is_complete=True).AndReturn(
632 [_MockSpecialTask(timestamp)])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700633 self.mox.ReplayAll()
634 self.assertEqual(timestamp,
635 job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700636 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700637
Jakob Juelich24f22c22014-09-26 11:46:11 -0700638
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700639 def test_unfinished_special_job(self):
640 """Test getting the timestamp for an unfinished special job.
641
642 Tests the return value for
643 `SpecialJobDirectory.get_timestamp_if_finished()` when
644 the AFE indicates the job is not finished.
645
646 """
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -0700647 job = job_directories.SpecialJobDirectory(
648 'hosts/host1/118-reset')
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700649 job_directories._AFE.get_special_tasks(
650 id=job._id, is_complete=True).AndReturn([])
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700651 self.mox.ReplayAll()
652 self.assertIsNone(job.get_timestamp_if_finished())
J. Richard Barnettedd0227d2015-04-10 15:18:48 -0700653 self.mox.VerifyAll()
J. Richard Barnette3e3ed6a2014-05-19 07:59:00 -0700654
655
Allen Lib41527d2017-06-22 17:28:00 -0700656class _TempResultsDirTestCase(unittest.TestCase):
657 """Mixin class for tests using a temporary results directory."""
J. Richard Barnetteea785362014-03-17 16:00:53 -0700658
J. Richard Barnette08800322014-05-16 14:49:46 -0700659 REGULAR_JOBLIST = [
660 '111-fubar', '112-fubar', '113-fubar', '114-snafu']
661 HOST_LIST = ['host1', 'host2', 'host3']
662 SPECIAL_JOBLIST = [
663 'hosts/host1/333-reset', 'hosts/host1/334-reset',
664 'hosts/host2/444-reset', 'hosts/host3/555-reset']
665
Jakob Juelich24f22c22014-09-26 11:46:11 -0700666
J. Richard Barnetteea785362014-03-17 16:00:53 -0700667 def setUp(self):
Allen Lib41527d2017-06-22 17:28:00 -0700668 super(_TempResultsDirTestCase, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -0700669 self._resultsroot = tempfile.mkdtemp()
670 self._cwd = os.getcwd()
671 os.chdir(self._resultsroot)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700672
Jakob Juelich24f22c22014-09-26 11:46:11 -0700673
J. Richard Barnetteea785362014-03-17 16:00:53 -0700674 def tearDown(self):
J. Richard Barnette08800322014-05-16 14:49:46 -0700675 os.chdir(self._cwd)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700676 shutil.rmtree(self._resultsroot)
Allen Lib41527d2017-06-22 17:28:00 -0700677 super(_TempResultsDirTestCase, self).tearDown()
J. Richard Barnetteea785362014-03-17 16:00:53 -0700678
Jakob Juelich24f22c22014-09-26 11:46:11 -0700679
J. Richard Barnetteea785362014-03-17 16:00:53 -0700680 def make_job(self, jobdir):
681 """Create a job with results in `self._resultsroot`.
682
683 @param jobdir Name of the subdirectory to be created in
684 `self._resultsroot`.
685
686 """
J. Richard Barnette08800322014-05-16 14:49:46 -0700687 os.mkdir(jobdir)
688 return _MockJobDirectory(jobdir)
689
Jakob Juelich24f22c22014-09-26 11:46:11 -0700690
J. Richard Barnette08800322014-05-16 14:49:46 -0700691 def make_job_hierarchy(self):
692 """Create a sample hierarchy of job directories.
693
694 `self.REGULAR_JOBLIST` is a list of directories for regular
695 jobs to be created; `self.SPECIAL_JOBLIST` is a list of
696 directories for special jobs to be created.
697
698 """
699 for d in self.REGULAR_JOBLIST:
700 os.mkdir(d)
701 hostsdir = 'hosts'
702 os.mkdir(hostsdir)
703 for host in self.HOST_LIST:
704 os.mkdir(os.path.join(hostsdir, host))
705 for d in self.SPECIAL_JOBLIST:
706 os.mkdir(d)
J. Richard Barnetteea785362014-03-17 16:00:53 -0700707
708
Allen Lib41527d2017-06-22 17:28:00 -0700709class _TempResultsDirTestBase(_TempResultsDirTestCase, mox.MoxTestBase):
710 """Base Mox test class for tests using a temporary results directory."""
711
712
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800713class FailedOffloadsLogTest(_TempResultsDirTestBase):
714 """Test the formatting of failed offloads log file."""
715 # Below is partial sample of a failed offload log file. This text is
716 # deliberately hard-coded and then parsed to create the test data; the idea
717 # is to make sure the actual text format will be reviewed by a human being.
718 #
719 # first offload count directory
720 # --+----1----+---- ----+ ----+----1----+----2----+----3
721 _SAMPLE_DIRECTORIES_REPORT = '''\
722 =================== ====== ==============================
723 2014-03-14 15:09:26 1 118-fubar
724 2014-03-14 15:19:23 2 117-fubar
725 2014-03-14 15:29:20 6 116-fubar
726 2014-03-14 15:39:17 24 115-fubar
727 2014-03-14 15:49:14 120 114-fubar
728 2014-03-14 15:59:11 720 113-fubar
729 2014-03-14 16:09:08 5040 112-fubar
730 2014-03-14 16:19:05 40320 111-fubar
731 '''
732
733 def setUp(self):
734 super(FailedOffloadsLogTest, self).setUp()
735 self._offloader = gs_offloader.Offloader(_get_options([]))
736 self._joblist = []
737 for line in self._SAMPLE_DIRECTORIES_REPORT.split('\n')[1 : -1]:
738 date_, time_, count, dir_ = line.split()
739 job = _MockJobDirectory(dir_)
Allen Lib41527d2017-06-22 17:28:00 -0700740 job.offload_count = int(count)
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800741 timestruct = time.strptime("%s %s" % (date_, time_),
742 gs_offloader.FAILED_OFFLOADS_TIME_FORMAT)
Allen Lib41527d2017-06-22 17:28:00 -0700743 job.first_offload_start = time.mktime(timestruct)
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800744 # enter the jobs in reverse order, to make sure we
745 # test that the output will be sorted.
746 self._joblist.insert(0, job)
747
748
749 def assert_report_well_formatted(self, report_file):
Allen Li93585382017-05-05 14:24:53 -0700750 """Assert that report file is well formatted.
751
752 @param report_file: Path to report file
753 """
Prathmesh Prabhu80dfb1e2017-01-30 18:01:29 -0800754 with open(report_file, 'r') as f:
755 report_lines = f.read().split()
756
757 for end_of_header_index in range(len(report_lines)):
758 if report_lines[end_of_header_index].startswith('=='):
759 break
760 self.assertLess(end_of_header_index, len(report_lines),
761 'Failed to find end-of-header marker in the report')
762
763 relevant_lines = report_lines[end_of_header_index:]
764 expected_lines = self._SAMPLE_DIRECTORIES_REPORT.split()
765 self.assertListEqual(relevant_lines, expected_lines)
766
767
768 def test_failed_offload_log_format(self):
769 """Trigger an e-mail report and check its contents."""
770 log_file = os.path.join(self._resultsroot, 'failed_log')
771 report = self._offloader._log_failed_jobs_locally(self._joblist,
772 log_file=log_file)
773 self.assert_report_well_formatted(log_file)
774
775
776 def test_failed_offload_file_overwrite(self):
777 """Verify that we can saefly overwrite the log file."""
778 log_file = os.path.join(self._resultsroot, 'failed_log')
779 with open(log_file, 'w') as f:
780 f.write('boohoohoo')
781 report = self._offloader._log_failed_jobs_locally(self._joblist,
782 log_file=log_file)
783 self.assert_report_well_formatted(log_file)
784
785
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700786class OffloadDirectoryTests(_TempResultsDirTestBase):
787 """Tests for `offload_dir()`."""
788
789 def setUp(self):
790 super(OffloadDirectoryTests, self).setUp()
791 # offload_dir() logs messages; silence them.
792 self._saved_loglevel = logging.getLogger().getEffectiveLevel()
793 logging.getLogger().setLevel(logging.CRITICAL+1)
794 self._job = self.make_job(self.REGULAR_JOBLIST[0])
Allen Lib41527d2017-06-22 17:28:00 -0700795 self.mox.StubOutWithMock(gs_offloader, '_get_cmd_list')
796 alarm = mock.patch('signal.alarm', return_value=0)
797 alarm.start()
798 self.addCleanup(alarm.stop)
Ningning Xia2d981ee2016-07-06 17:59:54 -0700799 self.mox.StubOutWithMock(models.test, 'parse_job_keyval')
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700800
Jakob Juelich24f22c22014-09-26 11:46:11 -0700801
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700802 def tearDown(self):
803 logging.getLogger().setLevel(self._saved_loglevel)
804 super(OffloadDirectoryTests, self).tearDown()
805
Allen Lib41527d2017-06-22 17:28:00 -0700806 def _mock__upload_cts_testresult(self):
807 self.mox.StubOutWithMock(gs_offloader, '_upload_cts_testresult')
808 gs_offloader._upload_cts_testresult(
Ningning Xia42111242016-06-15 14:35:58 -0700809 mox.IgnoreArg(),mox.IgnoreArg()).AndReturn(None)
Jakob Juelich24f22c22014-09-26 11:46:11 -0700810
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800811 def _mock_create_marker_file(self):
812 self.mox.StubOutWithMock(__builtin__, 'open')
Allen Li9579b382017-05-05 17:07:43 -0700813 open(mox.IgnoreArg(), 'a').AndReturn(mock.MagicMock())
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800814
815
816 def _mock_offload_dir_calls(self, command, queue_args,
Allen Lib41527d2017-06-22 17:28:00 -0700817 marker_initially_exists=False):
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700818 """Mock out the calls needed by `offload_dir()`.
819
820 This covers only the calls made when there is no timeout.
821
822 @param command Command list to be returned by the mocked
Allen Lib41527d2017-06-22 17:28:00 -0700823 call to `_get_cmd_list()`.
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700824
825 """
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800826 self.mox.StubOutWithMock(os.path, 'isfile')
827 os.path.isfile(mox.IgnoreArg()).AndReturn(marker_initially_exists)
Simran Basidd129972014-09-11 14:34:49 -0700828 command.append(queue_args[0])
Allen Lib41527d2017-06-22 17:28:00 -0700829 gs_offloader._get_cmd_list(
MK Ryue93c8572015-08-11 11:53:00 -0700830 False, queue_args[0],
831 '%s%s' % (utils.DEFAULT_OFFLOAD_GSURI,
832 queue_args[1])).AndReturn(command)
Allen Lib41527d2017-06-22 17:28:00 -0700833 self._mock__upload_cts_testresult()
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700834
Jakob Juelich24f22c22014-09-26 11:46:11 -0700835
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800836 def _run_offload_dir(self, should_succeed, delete_age):
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700837 """Make one call to `offload_dir()`.
838
839 The caller ensures all mocks are set up already.
840
841 @param should_succeed True iff the call to `offload_dir()`
842 is expected to succeed and remove the
843 offloaded job directory.
844
845 """
846 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -0700847 gs_offloader.GSOffloader(
848 utils.DEFAULT_OFFLOAD_GSURI, False, delete_age).offload(
MK Ryue93c8572015-08-11 11:53:00 -0700849 self._job.queue_args[0],
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800850 self._job.queue_args[1],
851 self._job.queue_args[2])
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700852 self.mox.VerifyAll()
853 self.assertEqual(not should_succeed,
854 os.path.isdir(self._job.queue_args[0]))
855
Jakob Juelich24f22c22014-09-26 11:46:11 -0700856
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700857 def test_offload_success(self):
858 """Test that `offload_dir()` can succeed correctly."""
Simran Basidd129972014-09-11 14:34:49 -0700859 self._mock_offload_dir_calls(['test', '-d'],
860 self._job.queue_args)
Allen Lib41527d2017-06-22 17:28:00 -0700861 os.path.isfile(mox.IgnoreArg()).AndReturn(True)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800862 self._mock_create_marker_file()
863 self._run_offload_dir(True, 0)
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700864
Jakob Juelich24f22c22014-09-26 11:46:11 -0700865
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700866 def test_offload_failure(self):
867 """Test that `offload_dir()` can fail correctly."""
Simran Basidd129972014-09-11 14:34:49 -0700868 self._mock_offload_dir_calls(['test', '!', '-d'],
Allen Lib41527d2017-06-22 17:28:00 -0700869 self._job.queue_args)
Keith Haddow5ba5fb82016-11-09 11:39:36 -0800870 self._run_offload_dir(False, 0)
J. Richard Barnette2e443ef2014-05-20 12:31:35 -0700871
872
Dan Shiaffb9222015-04-15 17:05:47 -0700873 def test_sanitize_dir(self):
874 """Test that folder/file name with invalid character can be corrected.
875 """
876 results_folder = tempfile.mkdtemp()
Allen Lib41527d2017-06-22 17:28:00 -0700877 invalid_chars = '_'.join(['[', ']', '*', '?', '#'])
Dan Shiaffb9222015-04-15 17:05:47 -0700878 invalid_files = []
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800879 invalid_folder_name = 'invalid_name_folder_%s' % invalid_chars
Dan Shiaffb9222015-04-15 17:05:47 -0700880 invalid_folder = os.path.join(
881 results_folder,
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800882 invalid_folder_name)
Dan Shiaffb9222015-04-15 17:05:47 -0700883 invalid_files.append(os.path.join(
884 invalid_folder,
885 'invalid_name_file_%s' % invalid_chars))
Dan Shiaffb9222015-04-15 17:05:47 -0700886 good_folder = os.path.join(results_folder, 'valid_name_folder')
887 good_file = os.path.join(good_folder, 'valid_name_file')
888 for folder in [invalid_folder, good_folder]:
889 os.makedirs(folder)
890 for f in invalid_files + [good_file]:
891 with open(f, 'w'):
892 pass
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800893 # check that broken symlinks don't break sanitization
894 symlink = os.path.join(invalid_folder, 'broken-link')
895 os.symlink(os.path.join(results_folder, 'no-such-file'),
896 symlink)
897 fifo1 = os.path.join(results_folder, 'test_fifo1')
898 fifo2 = os.path.join(good_folder, 'test_fifo2')
899 fifo3 = os.path.join(invalid_folder, 'test_fifo3')
900 invalid_fifo4_name = 'test_fifo4_%s' % invalid_chars
901 fifo4 = os.path.join(invalid_folder, invalid_fifo4_name)
902 os.mkfifo(fifo1)
903 os.mkfifo(fifo2)
904 os.mkfifo(fifo3)
905 os.mkfifo(fifo4)
Dan Shiaffb9222015-04-15 17:05:47 -0700906 gs_offloader.sanitize_dir(results_folder)
907 for _, dirs, files in os.walk(results_folder):
908 for name in dirs + files:
Allen Lib41527d2017-06-22 17:28:00 -0700909 self.assertEqual(name, gslib.escape(name))
Dan Shiaffb9222015-04-15 17:05:47 -0700910 for c in name:
Allen Lib41527d2017-06-22 17:28:00 -0700911 self.assertFalse(c in ['[', ']', '*', '?', '#'])
Dan Shiaffb9222015-04-15 17:05:47 -0700912 self.assertTrue(os.path.exists(good_file))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800913
914 self.assertTrue(os.path.exists(fifo1))
915 self.assertFalse(is_fifo(fifo1))
916 self.assertTrue(os.path.exists(fifo2))
917 self.assertFalse(is_fifo(fifo2))
918 corrected_folder = os.path.join(
Allen Lib41527d2017-06-22 17:28:00 -0700919 results_folder, gslib.escape(invalid_folder_name))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800920 corrected_fifo3 = os.path.join(
921 corrected_folder,
922 'test_fifo3')
923 self.assertFalse(os.path.exists(fifo3))
924 self.assertTrue(os.path.exists(corrected_fifo3))
925 self.assertFalse(is_fifo(corrected_fifo3))
926 corrected_fifo4 = os.path.join(
Allen Lib41527d2017-06-22 17:28:00 -0700927 corrected_folder, gslib.escape(invalid_fifo4_name))
Laurence Goodbyca7726d2017-02-14 17:09:07 -0800928 self.assertFalse(os.path.exists(fifo4))
929 self.assertTrue(os.path.exists(corrected_fifo4))
930 self.assertFalse(is_fifo(corrected_fifo4))
931
932 corrected_symlink = os.path.join(
933 corrected_folder,
934 'broken-link')
935 self.assertFalse(os.path.lexists(symlink))
936 self.assertTrue(os.path.exists(corrected_symlink))
937 self.assertFalse(os.path.islink(corrected_symlink))
Dan Shiaffb9222015-04-15 17:05:47 -0700938 shutil.rmtree(results_folder)
939
940
Dan Shi1b4c7c32015-10-05 10:38:57 -0700941 def check_limit_file_count(self, is_test_job=True):
942 """Test that folder with too many files can be compressed.
943
944 @param is_test_job: True to check the method with test job result
945 folder. Set to False for special task folder.
946 """
947 results_folder = tempfile.mkdtemp()
948 host_folder = os.path.join(
949 results_folder,
950 'lab1-host1' if is_test_job else 'hosts/lab1-host1/1-repair')
951 debug_folder = os.path.join(host_folder, 'debug')
952 sysinfo_folder = os.path.join(host_folder, 'sysinfo')
953 for folder in [debug_folder, sysinfo_folder]:
954 os.makedirs(folder)
955 for i in range(10):
956 with open(os.path.join(folder, str(i)), 'w') as f:
957 f.write('test')
958
Allen Lib41527d2017-06-22 17:28:00 -0700959 gs_offloader._MAX_FILE_COUNT = 100
Dan Shi1b4c7c32015-10-05 10:38:57 -0700960 gs_offloader.limit_file_count(
961 results_folder if is_test_job else host_folder)
962 self.assertTrue(os.path.exists(sysinfo_folder))
963
Allen Lib41527d2017-06-22 17:28:00 -0700964 gs_offloader._MAX_FILE_COUNT = 10
Dan Shi1b4c7c32015-10-05 10:38:57 -0700965 gs_offloader.limit_file_count(
966 results_folder if is_test_job else host_folder)
967 self.assertFalse(os.path.exists(sysinfo_folder))
968 self.assertTrue(os.path.exists(sysinfo_folder + '.tgz'))
969 self.assertTrue(os.path.exists(debug_folder))
970
971 shutil.rmtree(results_folder)
972
973
974 def test_limit_file_count(self):
975 """Test that folder with too many files can be compressed.
976 """
977 self.check_limit_file_count(is_test_job=True)
978 self.check_limit_file_count(is_test_job=False)
979
Ningning Xia2d88eec2016-07-25 23:18:46 -0700980
Ningning Xia8db632f2016-08-19 11:01:35 -0700981 def test_is_valid_result(self):
982 """Test _is_valid_result."""
Ningning Xia21922c82016-07-29 11:03:15 -0700983 release_build = 'veyron_minnie-cheets-release/R52-8248.0.0'
984 pfq_build = 'cyan-cheets-android-pfq/R54-8623.0.0-rc1'
985 trybot_build = 'trybot-samus-release/R54-8640.0.0-b5092'
986 trybot_2_build = 'trybot-samus-pfq/R54-8640.0.0-b5092'
987 release_2_build = 'test-trybot-release/R54-8640.0.0-b5092'
Ningning Xia8db632f2016-08-19 11:01:35 -0700988 self.assertTrue(gs_offloader._is_valid_result(
989 release_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
Rohit Makasana6384c102016-10-21 17:09:47 -0700990 self.assertTrue(gs_offloader._is_valid_result(
991 release_build, gs_offloader.CTS_RESULT_PATTERN, 'test_that_wrapper'))
Rohit Makasana8d868c92018-06-08 11:29:50 -0700992 self.assertTrue(gs_offloader._is_valid_result(
Richard Barnette33e12892017-05-26 09:25:34 -0700993 release_build, gs_offloader.CTS_RESULT_PATTERN, 'bvt-arc'))
Rohit Makasana8d868c92018-06-08 11:29:50 -0700994 self.assertFalse(gs_offloader._is_valid_result(
995 release_build, gs_offloader.CTS_RESULT_PATTERN, 'bvt-cq'))
Ningning Xia8db632f2016-08-19 11:01:35 -0700996 self.assertTrue(gs_offloader._is_valid_result(
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -0800997 release_build, gs_offloader.CTS_V2_RESULT_PATTERN, 'arc-gts'))
Ningning Xia8db632f2016-08-19 11:01:35 -0700998 self.assertFalse(gs_offloader._is_valid_result(
999 None, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1000 self.assertFalse(gs_offloader._is_valid_result(
1001 release_build, gs_offloader.CTS_RESULT_PATTERN, None))
1002 self.assertFalse(gs_offloader._is_valid_result(
1003 pfq_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1004 self.assertFalse(gs_offloader._is_valid_result(
1005 trybot_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1006 self.assertFalse(gs_offloader._is_valid_result(
1007 trybot_2_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
1008 self.assertTrue(gs_offloader._is_valid_result(
1009 release_2_build, gs_offloader.CTS_RESULT_PATTERN, 'arc-cts'))
Ningning Xia21922c82016-07-29 11:03:15 -07001010
1011
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001012 def create_results_folder(self):
1013 """Create CTS/GTS results folders."""
Ningning Xia42111242016-06-15 14:35:58 -07001014 results_folder = tempfile.mkdtemp()
1015 host_folder = os.path.join(results_folder, 'chromeos4-row9-rack11-host22')
1016 debug_folder = os.path.join(host_folder, 'debug')
1017 sysinfo_folder = os.path.join(host_folder, 'sysinfo')
1018 cts_result_folder = os.path.join(
1019 host_folder, 'cheets_CTS.android.dpi', 'results', 'cts-results')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001020 cts_v2_result_folder = os.path.join(host_folder,
1021 'cheets_CTS_N.CtsGraphicsTestCases', 'results', 'android-cts')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001022 gts_result_folder = os.path.join(
Ilja H. Friedelbfa63142017-01-26 00:56:29 -08001023 host_folder, 'cheets_GTS.google.admin', 'results', 'android-gts')
Ningning Xia42111242016-06-15 14:35:58 -07001024 timestamp_str = '2016.04.28_01.41.44'
Ningning Xia2d88eec2016-07-25 23:18:46 -07001025 timestamp_cts_folder = os.path.join(cts_result_folder, timestamp_str)
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001026 timestamp_cts_v2_folder = os.path.join(cts_v2_result_folder, timestamp_str)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001027 timestamp_gts_folder = os.path.join(gts_result_folder, timestamp_str)
1028
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001029 # Test results in cts_result_folder with a different time-stamp.
1030 timestamp_str_2 = '2016.04.28_10.41.44'
1031 timestamp_cts_folder_2 = os.path.join(cts_result_folder, timestamp_str_2)
1032
Ningning Xia2d88eec2016-07-25 23:18:46 -07001033 for folder in [debug_folder, sysinfo_folder, cts_result_folder,
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001034 timestamp_cts_folder, timestamp_cts_folder_2,
1035 timestamp_cts_v2_folder, timestamp_gts_folder]:
Ningning Xia42111242016-06-15 14:35:58 -07001036 os.makedirs(folder)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001037
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001038 path_pattern_pair = [(timestamp_cts_folder, gs_offloader.CTS_RESULT_PATTERN),
1039 (timestamp_cts_folder_2, gs_offloader.CTS_RESULT_PATTERN),
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001040 (timestamp_cts_v2_folder, gs_offloader.CTS_V2_RESULT_PATTERN),
1041 (timestamp_gts_folder, gs_offloader.CTS_V2_RESULT_PATTERN)]
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001042
1043 # Create timestamp.zip file_path.
Ningning Xia2d88eec2016-07-25 23:18:46 -07001044 cts_zip_file = os.path.join(cts_result_folder, timestamp_str + '.zip')
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001045 cts_zip_file_2 = os.path.join(cts_result_folder, timestamp_str_2 + '.zip')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001046 cts_v2_zip_file = os.path.join(cts_v2_result_folder, timestamp_str + '.zip')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001047 gts_zip_file = os.path.join(gts_result_folder, timestamp_str + '.zip')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001048
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001049 # Create xml file_path.
1050 cts_result_file = os.path.join(timestamp_cts_folder, 'testResult.xml')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001051 cts_result_file_2 = os.path.join(timestamp_cts_folder_2,
1052 'testResult.xml')
Ilja H. Friedelbfa63142017-01-26 00:56:29 -08001053 gts_result_file = os.path.join(timestamp_gts_folder, 'test_result.xml')
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001054 cts_v2_result_file = os.path.join(timestamp_cts_v2_folder,
1055 'test_result.xml')
Ningning Xia2d88eec2016-07-25 23:18:46 -07001056
Ilja H. Friedel73cf6cd2017-03-01 12:23:00 -08001057 for file_path in [cts_zip_file, cts_zip_file_2, cts_v2_zip_file,
1058 gts_zip_file, cts_result_file, cts_result_file_2,
1059 gts_result_file, cts_v2_result_file]:
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001060 with open(file_path, 'w') as f:
1061 f.write('test')
Ningning Xia42111242016-06-15 14:35:58 -07001062
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001063 return (results_folder, host_folder, path_pattern_pair)
Ningning Xia2d88eec2016-07-25 23:18:46 -07001064
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001065
Allen Lib41527d2017-06-22 17:28:00 -07001066 def test__upload_cts_testresult(self):
1067 """Test _upload_cts_testresult."""
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001068 results_folder, host_folder, path_pattern_pair = self.create_results_folder()
1069
1070 self.mox.StubOutWithMock(gs_offloader, '_upload_files')
1071 gs_offloader._upload_files(
Rohit Makasanaea337c52018-04-11 18:03:41 -07001072 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False,
1073 mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001074 ['test', '-d', host_folder])
1075 gs_offloader._upload_files(
Rohit Makasanaea337c52018-04-11 18:03:41 -07001076 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False,
1077 mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001078 ['test', '-d', host_folder])
1079 gs_offloader._upload_files(
Rohit Makasanaea337c52018-04-11 18:03:41 -07001080 mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg(), False,
1081 mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001082 ['test', '-d', host_folder])
Ningning Xia2d88eec2016-07-25 23:18:46 -07001083
Ningning Xia42111242016-06-15 14:35:58 -07001084 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -07001085 gs_offloader._upload_cts_testresult(results_folder, False)
Ningning Xia42111242016-06-15 14:35:58 -07001086 self.mox.VerifyAll()
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001087 shutil.rmtree(results_folder)
1088
1089
1090 def test_upload_files(self):
1091 """Test upload_files"""
1092 results_folder, host_folder, path_pattern_pair = self.create_results_folder()
1093
1094 for path, pattern in path_pattern_pair:
1095 models.test.parse_job_keyval(mox.IgnoreArg()).AndReturn({
1096 'build': 'veyron_minnie-cheets-release/R52-8248.0.0',
Ningning Xia8db632f2016-08-19 11:01:35 -07001097 'parent_job_id': 'p_id',
1098 'suite': 'arc-cts'
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001099 })
1100
Allen Lib41527d2017-06-22 17:28:00 -07001101 gs_offloader._get_cmd_list(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001102 False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
1103 ['test', '-d', path])
Allen Lib41527d2017-06-22 17:28:00 -07001104 gs_offloader._get_cmd_list(
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001105 False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
1106 ['test', '-d', path])
1107
1108 self.mox.ReplayAll()
Rohit Makasanaea337c52018-04-11 18:03:41 -07001109 gs_offloader._upload_files(host_folder, path, pattern, False,
1110 'gs://a-test-bucket/',
1111 'gs://a-test-apfe-bucket/')
Ningning Xia0c27d9b2016-08-04 14:02:39 -07001112 self.mox.VerifyAll()
1113 self.mox.ResetAll()
Ningning Xia42111242016-06-15 14:35:58 -07001114
1115 shutil.rmtree(results_folder)
Dan Shi1b4c7c32015-10-05 10:38:57 -07001116
Michael Tang97d188c2016-06-25 11:18:42 -07001117
Dan Shi02dd0662017-05-23 11:24:32 -07001118 def test_get_metrics_fields(self):
1119 """Test method _get_metrics_fields."""
1120 results_folder, host_folder, _ = self.create_results_folder()
1121 models.test.parse_job_keyval(mox.IgnoreArg()).AndReturn({
1122 'build': 'veyron_minnie-cheets-release/R52-8248.0.0',
1123 'parent_job_id': 'p_id',
1124 'suite': 'arc-cts'
1125 })
1126 try:
1127 self.mox.ReplayAll()
1128 self.assertEqual({'board': 'veyron_minnie-cheets',
1129 'milestone': 'R52'},
1130 gs_offloader._get_metrics_fields(host_folder))
1131 self.mox.VerifyAll()
1132 finally:
1133 shutil.rmtree(results_folder)
1134
1135
J. Richard Barnetteea785362014-03-17 16:00:53 -07001136class JobDirectoryOffloadTests(_TempResultsDirTestBase):
1137 """Tests for `_JobDirectory.enqueue_offload()`.
1138
1139 When testing with a `days_old` parameter of 0, we use
1140 `set_finished()` instead of `set_expired()`. This causes the
1141 job's timestamp to be set in the future. This is done so as
1142 to test that when `days_old` is 0, the job is always treated
1143 as eligible for offload, regardless of the timestamp's value.
1144
1145 Testing covers the following assertions:
1146 A. Each time `enqueue_offload()` is called, a message that
1147 includes the job's directory name will be logged using
1148 `logging.debug()`, regardless of whether the job was
1149 enqueued. Nothing else is allowed to be logged.
1150 B. If the job is not eligible to be offloaded,
Allen Lib41527d2017-06-22 17:28:00 -07001151 `first_offload_start` and `offload_count` are 0.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001152 C. If the job is not eligible for offload, nothing is
1153 enqueued in `queue`.
Allen Lib41527d2017-06-22 17:28:00 -07001154 D. When the job is offloaded, `offload_count` increments
J. Richard Barnetteea785362014-03-17 16:00:53 -07001155 each time.
1156 E. When the job is offloaded, the appropriate parameters are
1157 enqueued exactly once.
Allen Lib41527d2017-06-22 17:28:00 -07001158 F. The first time a job is offloaded, `first_offload_start` is
J. Richard Barnetteea785362014-03-17 16:00:53 -07001159 set to the current time.
Allen Lib41527d2017-06-22 17:28:00 -07001160 G. `first_offload_start` only changes the first time that the
J. Richard Barnetteea785362014-03-17 16:00:53 -07001161 job is offloaded.
1162
1163 The test cases below are designed to exercise all of the
1164 meaningful state transitions at least once.
1165
1166 """
1167
1168 def setUp(self):
1169 super(JobDirectoryOffloadTests, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -07001170 self._job = self.make_job(self.REGULAR_JOBLIST[0])
J. Richard Barnetteea785362014-03-17 16:00:53 -07001171 self._queue = Queue.Queue()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001172
Jakob Juelich24f22c22014-09-26 11:46:11 -07001173
J. Richard Barnetteea785362014-03-17 16:00:53 -07001174 def _offload_unexpired_job(self, days_old):
1175 """Make calls to `enqueue_offload()` for an unexpired job.
1176
1177 This method tests assertions B and C that calling
1178 `enqueue_offload()` has no effect.
1179
1180 """
Allen Lib41527d2017-06-22 17:28:00 -07001181 self.assertEqual(self._job.offload_count, 0)
1182 self.assertEqual(self._job.first_offload_start, 0)
1183 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
1184 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001185 self.assertTrue(self._queue.empty())
Allen Lib41527d2017-06-22 17:28:00 -07001186 self.assertEqual(self._job.offload_count, 0)
1187 self.assertEqual(self._job.first_offload_start, 0)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001188
Jakob Juelich24f22c22014-09-26 11:46:11 -07001189
J. Richard Barnetteea785362014-03-17 16:00:53 -07001190 def _offload_expired_once(self, days_old, count):
1191 """Make one call to `enqueue_offload()` for an expired job.
1192
1193 This method tests assertions D and E regarding side-effects
1194 expected when a job is offloaded.
1195
1196 """
Allen Lib41527d2017-06-22 17:28:00 -07001197 gs_offloader._enqueue_offload(self._job, self._queue, days_old)
1198 self.assertEqual(self._job.offload_count, count)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001199 self.assertFalse(self._queue.empty())
1200 v = self._queue.get_nowait()
1201 self.assertTrue(self._queue.empty())
J. Richard Barnette2c72ddd2014-05-20 12:17:37 -07001202 self.assertEqual(v, self._job.queue_args)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001203
Jakob Juelich24f22c22014-09-26 11:46:11 -07001204
J. Richard Barnetteea785362014-03-17 16:00:53 -07001205 def _offload_expired_job(self, days_old):
1206 """Make calls to `enqueue_offload()` for a just-expired job.
1207
1208 This method directly tests assertions F and G regarding
Allen Lib41527d2017-06-22 17:28:00 -07001209 side-effects on `first_offload_start`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001210
1211 """
1212 t0 = time.time()
1213 self._offload_expired_once(days_old, 1)
Allen Lib41527d2017-06-22 17:28:00 -07001214 t1 = self._job.first_offload_start
J. Richard Barnetteea785362014-03-17 16:00:53 -07001215 self.assertLessEqual(t1, time.time())
1216 self.assertGreaterEqual(t1, t0)
1217 self._offload_expired_once(days_old, 2)
Allen Lib41527d2017-06-22 17:28:00 -07001218 self.assertEqual(self._job.first_offload_start, t1)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001219 self._offload_expired_once(days_old, 3)
Allen Lib41527d2017-06-22 17:28:00 -07001220 self.assertEqual(self._job.first_offload_start, t1)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001221
Jakob Juelich24f22c22014-09-26 11:46:11 -07001222
J. Richard Barnetteea785362014-03-17 16:00:53 -07001223 def test_case_1_no_expiration(self):
1224 """Test a series of `enqueue_offload()` calls with `days_old` of 0.
1225
1226 This tests that offload works as expected if calls are
1227 made both before and after the job becomes expired.
1228
1229 """
1230 self._offload_unexpired_job(0)
1231 self._job.set_finished(0)
1232 self._offload_expired_job(0)
1233
Jakob Juelich24f22c22014-09-26 11:46:11 -07001234
J. Richard Barnetteea785362014-03-17 16:00:53 -07001235 def test_case_2_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 made
1239 only after the job becomes expired.
1240
1241 """
1242 self._job.set_finished(0)
1243 self._offload_expired_job(0)
1244
Jakob Juelich24f22c22014-09-26 11:46:11 -07001245
J. Richard Barnetteea785362014-03-17 16:00:53 -07001246 def test_case_1_with_expiration(self):
1247 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1248
1249 This tests that offload works as expected if calls are made
1250 before the job finishes, before the job expires, and after
1251 the job expires.
1252
1253 """
1254 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1255 self._job.set_finished(_TEST_EXPIRATION_AGE)
1256 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1257 self._job.set_expired(_TEST_EXPIRATION_AGE)
1258 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1259
Jakob Juelich24f22c22014-09-26 11:46:11 -07001260
J. Richard Barnetteea785362014-03-17 16:00:53 -07001261 def test_case_2_with_expiration(self):
1262 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1263
1264 This tests that offload works as expected if calls are made
1265 between finishing and expiration, and after the job expires.
1266
1267 """
1268 self._job.set_finished(_TEST_EXPIRATION_AGE)
1269 self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1270 self._job.set_expired(_TEST_EXPIRATION_AGE)
1271 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1272
Jakob Juelich24f22c22014-09-26 11:46:11 -07001273
J. Richard Barnetteea785362014-03-17 16:00:53 -07001274 def test_case_3_with_expiration(self):
1275 """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1276
1277 This tests that offload works as expected if calls are made
1278 only before finishing and after expiration.
1279
1280 """
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_4_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 after expiration.
1291
1292 """
1293 self._job.set_expired(_TEST_EXPIRATION_AGE)
1294 self._offload_expired_job(_TEST_EXPIRATION_AGE)
1295
1296
1297class GetJobDirectoriesTests(_TempResultsDirTestBase):
1298 """Tests for `_JobDirectory.get_job_directories()`."""
1299
J. Richard Barnetteea785362014-03-17 16:00:53 -07001300 def setUp(self):
1301 super(GetJobDirectoriesTests, self).setUp()
J. Richard Barnette08800322014-05-16 14:49:46 -07001302 self.make_job_hierarchy()
1303 os.mkdir('not-a-job')
1304 open('not-a-dir', 'w').close()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001305
Jakob Juelich24f22c22014-09-26 11:46:11 -07001306
J. Richard Barnetteea785362014-03-17 16:00:53 -07001307 def _run_get_directories(self, cls, expected_list):
1308 """Test `get_job_directories()` for the given class.
1309
1310 Calls the method, and asserts that the returned list of
1311 directories matches the expected return value.
1312
1313 @param expected_list Expected return value from the call.
1314 """
J. Richard Barnetteea785362014-03-17 16:00:53 -07001315 dirlist = cls.get_job_directories()
1316 self.assertEqual(set(dirlist), set(expected_list))
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 test_get_regular_jobs(self):
1320 """Test `RegularJobDirectory.get_job_directories()`."""
1321 self._run_get_directories(job_directories.RegularJobDirectory,
J. Richard Barnette08800322014-05-16 14:49:46 -07001322 self.REGULAR_JOBLIST)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001323
Jakob Juelich24f22c22014-09-26 11:46:11 -07001324
J. Richard Barnetteea785362014-03-17 16:00:53 -07001325 def test_get_special_jobs(self):
1326 """Test `SpecialJobDirectory.get_job_directories()`."""
1327 self._run_get_directories(job_directories.SpecialJobDirectory,
J. Richard Barnette08800322014-05-16 14:49:46 -07001328 self.SPECIAL_JOBLIST)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001329
1330
1331class AddJobsTests(_TempResultsDirTestBase):
1332 """Tests for `Offloader._add_new_jobs()`."""
1333
J. Richard Barnette08800322014-05-16 14:49:46 -07001334 MOREJOBS = ['115-fubar', '116-fubar', '117-fubar', '118-snafu']
J. Richard Barnetteea785362014-03-17 16:00:53 -07001335
1336 def setUp(self):
1337 super(AddJobsTests, self).setUp()
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001338 self._initial_job_names = (
1339 set(self.REGULAR_JOBLIST) | set(self.SPECIAL_JOBLIST))
J. Richard Barnette08800322014-05-16 14:49:46 -07001340 self.make_job_hierarchy()
1341 self._offloader = gs_offloader.Offloader(_get_options(['-a']))
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001342 self.mox.StubOutWithMock(logging, 'debug')
J. Richard Barnetteea785362014-03-17 16:00:53 -07001343
Jakob Juelich24f22c22014-09-26 11:46:11 -07001344
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001345 def _run_add_new_jobs(self, expected_key_set):
J. Richard Barnetteea785362014-03-17 16:00:53 -07001346 """Basic test assertions for `_add_new_jobs()`.
1347
1348 Asserts the following:
1349 * The keys in the offloader's `_open_jobs` dictionary
1350 matches the expected set of keys.
1351 * For every job in `_open_jobs`, the job has the expected
1352 directory name.
1353
1354 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001355 count = len(expected_key_set) - len(self._offloader._open_jobs)
1356 logging.debug(mox.IgnoreArg(), count)
1357 self.mox.ReplayAll()
1358 self._offloader._add_new_jobs()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001359 self.assertEqual(expected_key_set,
1360 set(self._offloader._open_jobs.keys()))
1361 for jobkey, job in self._offloader._open_jobs.items():
Allen Lib41527d2017-06-22 17:28:00 -07001362 self.assertEqual(jobkey, job.dirname)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001363 self.mox.VerifyAll()
1364 self.mox.ResetAll()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001365
Jakob Juelich24f22c22014-09-26 11:46:11 -07001366
J. Richard Barnetteea785362014-03-17 16:00:53 -07001367 def test_add_jobs_empty(self):
1368 """Test adding jobs to an empty dictionary.
1369
1370 Calls the offloader's `_add_new_jobs()`, then perform
1371 the assertions of `self._check_open_jobs()`.
1372
1373 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001374 self._run_add_new_jobs(self._initial_job_names)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001375
Jakob Juelich24f22c22014-09-26 11:46:11 -07001376
J. Richard Barnetteea785362014-03-17 16:00:53 -07001377 def test_add_jobs_non_empty(self):
1378 """Test adding jobs to a non-empty dictionary.
1379
1380 Calls the offloader's `_add_new_jobs()` twice; once from
1381 initial conditions, and then again after adding more
1382 directories. After the second call, perform the assertions
1383 of `self._check_open_jobs()`. Additionally, assert that
1384 keys added by the first call still map to their original
1385 job object after the second call.
1386
1387 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001388 self._run_add_new_jobs(self._initial_job_names)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001389 jobs_copy = self._offloader._open_jobs.copy()
J. Richard Barnette08800322014-05-16 14:49:46 -07001390 for d in self.MOREJOBS:
1391 os.mkdir(d)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001392 self._run_add_new_jobs(self._initial_job_names |
1393 set(self.MOREJOBS))
J. Richard Barnetteea785362014-03-17 16:00:53 -07001394 for key in jobs_copy.keys():
1395 self.assertIs(jobs_copy[key],
1396 self._offloader._open_jobs[key])
1397
1398
J. Richard Barnetteea785362014-03-17 16:00:53 -07001399class ReportingTests(_TempResultsDirTestBase):
Allen Lib41527d2017-06-22 17:28:00 -07001400 """Tests for `Offloader._report_failed_jobs()`."""
J. Richard Barnetteea785362014-03-17 16:00:53 -07001401
J. Richard Barnetteea785362014-03-17 16:00:53 -07001402 def setUp(self):
1403 super(ReportingTests, self).setUp()
1404 self._offloader = gs_offloader.Offloader(_get_options([]))
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001405 self.mox.StubOutWithMock(self._offloader, '_log_failed_jobs_locally')
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001406 self.mox.StubOutWithMock(logging, 'debug')
J. Richard Barnetteea785362014-03-17 16:00:53 -07001407
Jakob Juelich24f22c22014-09-26 11:46:11 -07001408
J. Richard Barnetteea785362014-03-17 16:00:53 -07001409 def _add_job(self, jobdir):
1410 """Add a job to the dictionary of unfinished jobs."""
1411 j = self.make_job(jobdir)
Allen Lib41527d2017-06-22 17:28:00 -07001412 self._offloader._open_jobs[j.dirname] = j
J. Richard Barnetteea785362014-03-17 16:00:53 -07001413 return j
1414
Jakob Juelich24f22c22014-09-26 11:46:11 -07001415
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001416 def _expect_log_message(self, new_open_jobs, with_failures):
1417 """Mock expected logging calls.
1418
Allen Lib41527d2017-06-22 17:28:00 -07001419 `_report_failed_jobs()` logs one message with the number
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001420 of jobs removed from the open job set and the number of jobs
1421 still remaining. Additionally, if there are reportable
1422 jobs, then it logs the number of jobs that haven't yet
1423 offloaded.
1424
1425 This sets up the logging calls using `new_open_jobs` to
1426 figure the job counts. If `with_failures` is true, then
1427 the log message is set up assuming that all jobs in
1428 `new_open_jobs` have offload failures.
1429
1430 @param new_open_jobs New job set for calculating counts
1431 in the messages.
1432 @param with_failures Whether the log message with a
1433 failure count is expected.
1434
1435 """
1436 count = len(self._offloader._open_jobs) - len(new_open_jobs)
1437 logging.debug(mox.IgnoreArg(), count, len(new_open_jobs))
1438 if with_failures:
1439 logging.debug(mox.IgnoreArg(), len(new_open_jobs))
1440
Jakob Juelich24f22c22014-09-26 11:46:11 -07001441
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001442 def _run_update(self, new_open_jobs):
Allen Lib41527d2017-06-22 17:28:00 -07001443 """Call `_report_failed_jobs()`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001444
1445 Initial conditions are set up by the caller. This calls
Allen Lib41527d2017-06-22 17:28:00 -07001446 `_report_failed_jobs()` once, and then checks these
J. Richard Barnetteea785362014-03-17 16:00:53 -07001447 assertions:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001448 * The offloader's new `_open_jobs` field contains only
1449 the entries in `new_open_jobs`.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001450
1451 @param new_open_jobs A dictionary representing the expected
1452 new value of the offloader's
1453 `_open_jobs` field.
1454 """
1455 self.mox.ReplayAll()
Allen Lib41527d2017-06-22 17:28:00 -07001456 self._offloader._report_failed_jobs()
1457 self._offloader._remove_offloaded_jobs()
J. Richard Barnetteea785362014-03-17 16:00:53 -07001458 self.assertEqual(self._offloader._open_jobs, new_open_jobs)
1459 self.mox.VerifyAll()
1460 self.mox.ResetAll()
1461
Jakob Juelich24f22c22014-09-26 11:46:11 -07001462
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001463 def _expect_failed_jobs(self, failed_jobs):
1464 """Mock expected call to log the failed jobs on local disk.
1465
1466 TODO(crbug.com/686904): The fact that we have to mock an internal
1467 function for this test is evidence that we need to pull out the local
1468 file formatter in its own object in a future CL.
1469
1470 @param failed_jobs: The list of jobs being logged as failed.
1471 """
1472 self._offloader._log_failed_jobs_locally(failed_jobs)
1473
1474
J. Richard Barnetteea785362014-03-17 16:00:53 -07001475 def test_no_jobs(self):
Allen Lib41527d2017-06-22 17:28:00 -07001476 """Test `_report_failed_jobs()` with no open jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001477
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001478 Initial conditions are an empty `_open_jobs` list.
1479 Expected result is an empty `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001480
1481 """
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001482 self._expect_log_message({}, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001483 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001484 self._run_update({})
J. Richard Barnetteea785362014-03-17 16:00:53 -07001485
Jakob Juelich24f22c22014-09-26 11:46:11 -07001486
J. Richard Barnetteea785362014-03-17 16:00:53 -07001487 def test_all_completed(self):
Allen Lib41527d2017-06-22 17:28:00 -07001488 """Test `_report_failed_jobs()` with only complete jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001489
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001490 Initial conditions are an `_open_jobs` list consisting of only completed
1491 jobs.
1492 Expected result is an empty `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001493
1494 """
J. Richard Barnette08800322014-05-16 14:49:46 -07001495 for d in self.REGULAR_JOBLIST:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001496 self._add_job(d).set_complete()
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001497 self._expect_log_message({}, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001498 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001499 self._run_update({})
J. Richard Barnetteea785362014-03-17 16:00:53 -07001500
Jakob Juelich24f22c22014-09-26 11:46:11 -07001501
J. Richard Barnetteea785362014-03-17 16:00:53 -07001502 def test_none_finished(self):
Allen Lib41527d2017-06-22 17:28:00 -07001503 """Test `_report_failed_jobs()` with only unfinished jobs.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001504
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001505 Initial conditions are an `_open_jobs` list consisting of only
1506 unfinished jobs.
1507 Expected result is no change to the `_open_jobs` list.
J. Richard Barnetteea785362014-03-17 16:00:53 -07001508
1509 """
J. Richard Barnette08800322014-05-16 14:49:46 -07001510 for d in self.REGULAR_JOBLIST:
J. Richard Barnetteea785362014-03-17 16:00:53 -07001511 self._add_job(d)
J. Richard Barnette22dd7482014-06-23 12:25:02 -07001512 new_jobs = self._offloader._open_jobs.copy()
1513 self._expect_log_message(new_jobs, False)
Prathmesh Prabhu16f9e5c2017-01-30 17:54:40 -08001514 self._expect_failed_jobs([])
Prathmesh Prabhu33e3e1a2017-01-30 18:03:34 -08001515 self._run_update(new_jobs)
J. Richard Barnetteea785362014-03-17 16:00:53 -07001516
1517
Allen Lib41527d2017-06-22 17:28:00 -07001518class GsOffloaderMockTests(_TempResultsDirTestCase):
1519 """Tests using mock instead of mox."""
1520
1521 def setUp(self):
1522 super(GsOffloaderMockTests, self).setUp()
1523 alarm = mock.patch('signal.alarm', return_value=0)
1524 alarm.start()
1525 self.addCleanup(alarm.stop)
1526
1527 self._saved_loglevel = logging.getLogger().getEffectiveLevel()
1528 logging.getLogger().setLevel(logging.CRITICAL + 1)
1529
1530 self._job = self.make_job(self.REGULAR_JOBLIST[0])
1531
1532
1533 def test_offload_timeout_early(self):
1534 """Test that `offload_dir()` times out correctly.
1535
1536 This test triggers timeout at the earliest possible moment,
1537 at the first call to set the timeout alarm.
1538
1539 """
1540 signal.alarm.side_effect = [0, timeout_util.TimeoutError('fubar')]
1541 with mock.patch.object(gs_offloader, '_upload_cts_testresult',
1542 autospec=True) as upload:
1543 upload.return_value = None
1544 gs_offloader.GSOffloader(
1545 utils.DEFAULT_OFFLOAD_GSURI, False, 0).offload(
1546 self._job.queue_args[0],
1547 self._job.queue_args[1],
1548 self._job.queue_args[2])
1549 self.assertTrue(os.path.isdir(self._job.queue_args[0]))
1550
1551
1552 # TODO(ayatane): This tests passes when run locally, but it fails
1553 # when run on trybot. I have no idea why, but the assert isdir
1554 # fails.
1555 #
1556 # This test is also kind of redundant since we are using the timeout
1557 # from chromite which has its own tests.
1558 @unittest.skip('This fails on trybot')
1559 def test_offload_timeout_late(self):
1560 """Test that `offload_dir()` times out correctly.
1561
1562 This test triggers timeout at the latest possible moment, at
1563 the call to clear the timeout alarm.
1564
1565 """
1566 signal.alarm.side_effect = [0, 0, timeout_util.TimeoutError('fubar')]
1567 with mock.patch.object(gs_offloader, '_upload_cts_testresult',
1568 autospec=True) as upload, \
1569 mock.patch.object(gs_offloader, '_get_cmd_list',
1570 autospec=True) as get_cmd_list:
1571 upload.return_value = None
1572 get_cmd_list.return_value = ['test', '-d', self._job.queue_args[0]]
1573 gs_offloader.GSOffloader(
1574 utils.DEFAULT_OFFLOAD_GSURI, False, 0).offload(
1575 self._job.queue_args[0],
1576 self._job.queue_args[1],
1577 self._job.queue_args[2])
1578 self.assertTrue(os.path.isdir(self._job.queue_args[0]))
1579
1580
1581
J. Richard Barnetteea785362014-03-17 16:00:53 -07001582if __name__ == '__main__':
1583 unittest.main()