gs_offloader_unittest.py revision 4211124209fdb4469462b6e1b39433cc52b76d02
1ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# Copyright 2013 The Chromium OS Authors. All rights reserved.
2ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# Use of this source code is governed by a BSD-style license that can be
3ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# found in the LICENSE file.
4ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
5ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport Queue
6ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport datetime
7ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport logging
8ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport os
9ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport shutil
102e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnetteimport signal
11ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport sys
12ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport tempfile
13ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport time
14ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport unittest
15ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
16ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport mox
17ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
18ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport common
19ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport gs_offloader
20ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteimport job_directories
21ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
22dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basifrom autotest_lib.client.common_lib import global_config
231b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shifrom autotest_lib.client.common_lib import time_utils
241b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shifrom autotest_lib.client.common_lib import utils
25ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnettefrom autotest_lib.scheduler import email_manager
26ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
2724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
28ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# Test value to use for `days_old`, if nothing else is required.
29ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette_TEST_EXPIRATION_AGE = 7
30ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
31ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# When constructing sample time values for testing expiration,
32ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# allow this many seconds between the expiration time and the
33ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# current time.
34ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette_MARGIN_SECS = 10.0
35ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
36ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
37ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnettedef _get_options(argv):
38ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Helper function to exercise command line parsing.
39ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
40ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    @param argv Value of sys.argv to be parsed.
41ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
42ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """
43ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    sys.argv = ['bogus.py'] + argv
44ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    return gs_offloader.parse_options()
45ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
46ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
47dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basiclass OffloaderOptionsTests(mox.MoxTestBase):
48ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    """Tests for the `Offloader` constructor.
49ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette
50ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    Tests that offloader instance fields are set as expected
51ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    for given command line options.
52ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette
53ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    """
54ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette
55ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    _REGULAR_ONLY = set([job_directories.RegularJobDirectory])
56ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    _SPECIAL_ONLY = set([job_directories.SpecialJobDirectory])
57ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette    _BOTH = _REGULAR_ONLY | _SPECIAL_ONLY
58ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
5924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
60dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi    def setUp(self):
61dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        super(OffloaderOptionsTests, self).setUp()
62dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.mox.StubOutWithMock(utils, 'get_offload_gsuri')
63f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi        gs_offloader.GS_OFFLOADING_ENABLED = True
640df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
65dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi
6624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
670df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang    def _mock_get_offload_func(self, is_moblab, multiprocessing=False):
68dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        """Mock the process of getting the offload_dir function."""
69dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        if is_moblab:
70dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi            expected_gsuri = '%sresults/%s/%s/' % (
71dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                    global_config.global_config.get_config_value(
72dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                            'CROS', 'image_storage_server'),
73dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                    'Fa:ke:ma:c0:12:34', 'rand0m-uu1d')
74dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        else:
75dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi            expected_gsuri = utils.DEFAULT_OFFLOAD_GSURI
76dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        utils.get_offload_gsuri().AndReturn(expected_gsuri)
770df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offload_func = gs_offloader.get_offload_dir_func(
780df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang                expected_gsuri, multiprocessing)
79dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.mox.StubOutWithMock(gs_offloader, 'get_offload_dir_func')
800df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        gs_offloader.get_offload_dir_func(expected_gsuri, multiprocessing).AndReturn(
81dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                offload_func)
82dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.mox.ReplayAll()
83dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        return offload_func
84dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi
8524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
86ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_process_no_options(self):
87ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test default offloader options."""
88dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(False)
89ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(_get_options([]))
90ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes),
91ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         self._REGULAR_ONLY)
92ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 1)
93ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
94dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
95ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 0)
96ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
9724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
98ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_process_all_option(self):
99ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test offloader handling for the --all option."""
100dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(False)
101ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(_get_options(['--all']))
102ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes), self._BOTH)
103ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 1)
104ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
105dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
106ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 0)
107ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
10824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
109ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_process_hosts_option(self):
110ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test offloader handling for the --hosts option."""
111dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(False)
112ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(
113ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                _get_options(['--hosts']))
114ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes),
115ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         self._SPECIAL_ONLY)
116ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 1)
117ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
118dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
119ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 0)
120ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
12124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
122ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_parallelism_option(self):
123ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test offloader handling for the --parallelism option."""
124dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(False)
125ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(
126ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                _get_options(['--parallelism', '2']))
127ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes),
128ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         self._REGULAR_ONLY)
129ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 2)
130ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
131dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
132ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 0)
133ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
13424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
135ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_delete_only_option(self):
136ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test offloader handling for the --delete_only option."""
137ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(
138ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                _get_options(['--delete_only']))
139ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes),
140ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         self._REGULAR_ONLY)
141ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 1)
142ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
143ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         gs_offloader.delete_files)
144ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 0)
145ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
14624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
147df4751eaab3405bc4f564d033681d093958f0c10Simran Basi    def test_days_old_option(self):
148ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        """Test offloader handling for the --days_old option."""
149dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(False)
150ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        offloader = gs_offloader.Offloader(
151ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                _get_options(['--days_old', '7']))
152ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(set(offloader._jobdir_classes),
153ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette                         self._REGULAR_ONLY)
154ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._processes, 1)
155ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._offload_func,
156dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
157ef4b47dedcb759b46fd1e415172a688f1448df54J. Richard Barnette        self.assertEqual(offloader._age_limit, 7)
158ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
15924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
160dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi    def test_moblab_gsuri_generation(self):
161dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        """Test offloader construction for Moblab."""
162dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offload_func = self._mock_get_offload_func(True)
163dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        offloader = gs_offloader.Offloader(_get_options([]))
164dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.assertEqual(set(offloader._jobdir_classes),
165dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         self._REGULAR_ONLY)
166dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.assertEqual(offloader._processes, 1)
167dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.assertEqual(offloader._offload_func,
168dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                         offload_func)
169dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self.assertEqual(offloader._age_limit, 0)
170dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi
171ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
172f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi    def test_globalconfig_offloading_flag(self):
173f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi        """Test enabling of --delete_only via global_config."""
174f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi        gs_offloader.GS_OFFLOADING_ENABLED = False
175f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi        offloader = gs_offloader.Offloader(
176f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi                _get_options([]))
177f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi        self.assertEqual(offloader._offload_func,
178f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi                         gs_offloader.delete_files)
179f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi
1800df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang    def test_offloader_multiprocessing_flag_set(self):
1810df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        """Test multiprocessing is set."""
1820df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offload_func = self._mock_get_offload_func(True, True)
1830df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offloader = gs_offloader.Offloader(_get_options(['-m']))
1840df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.assertEqual(offloader._offload_func,
1850df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang                         offload_func)
1860df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.mox.VerifyAll()
1870df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang
1880df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang    def test_offloader_multiprocessing_flag_not_set_default_false(self):
1890df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        """Test multiprocessing is set."""
1900df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        gs_offloader.GS_OFFLOADER_MULTIPROCESSING = False
1910df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offload_func = self._mock_get_offload_func(True, False)
1920df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offloader = gs_offloader.Offloader(_get_options([]))
1930df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.assertEqual(offloader._offload_func,
1940df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang                         offload_func)
1950df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.mox.VerifyAll()
1960df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang
1970df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang    def test_offloader_multiprocessing_flag_not_set_default_true(self):
1980df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        """Test multiprocessing is set."""
1990df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        gs_offloader.GS_OFFLOADER_MULTIPROCESSING = True
2000df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offload_func = self._mock_get_offload_func(True, True)
2010df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        offloader = gs_offloader.Offloader(_get_options([]))
2020df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.assertEqual(offloader._offload_func,
2030df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang                         offload_func)
2040df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang        self.mox.VerifyAll()
2050df2eb4e1e8638a1a165e8f2dc3b9230f85acf06Michael Tang
206f3e305f2c1342d8dd271256c2594ae54072c514bSimran Basi
207ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnettedef _make_timestamp(age_limit, is_expired):
208ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Create a timestamp for use by `job_directories._is_job_expired()`.
209ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
210ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    The timestamp will meet the syntactic requirements for
211ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    timestamps used as input to `_is_job_expired()`.  If
212ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    `is_expired` is true, the timestamp will be older than
213ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    `age_limit` days before the current time; otherwise, the
214ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    date will be younger.
215ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
216ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    @param age_limit    The number of days before expiration of the
217ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        target timestamp.
218ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    @param is_expired   Whether the timestamp should be expired
219ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        relative to `age_limit`.
220ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
221ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """
222ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    seconds = -_MARGIN_SECS
223ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    if is_expired:
224ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        seconds = -seconds
225ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    delta = datetime.timedelta(days=age_limit, seconds=seconds)
226ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    reference_time = datetime.datetime.now() - delta
227dfea368e5c830b1d7950ced5ee7b191e3b141ca3Dan Shi    return reference_time.strftime(time_utils.TIME_FMT)
228ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
229ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
230ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass JobExpirationTests(unittest.TestCase):
231ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests to exercise `job_directories._is_job_expired()`."""
232ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
233ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_expired(self):
234ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test detection of an expired job."""
235ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, True)
236ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertTrue(
237ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            job_directories._is_job_expired(
238ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                _TEST_EXPIRATION_AGE, timestamp))
239ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
240ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
241ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_alive(self):
242ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test detection of a job that's not expired."""
243ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # N.B.  This test may fail if its run time exceeds more than
244ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # about _MARGIN_SECS seconds.
245ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        timestamp = _make_timestamp(_TEST_EXPIRATION_AGE, False)
246ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(
247ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            job_directories._is_job_expired(
248ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                _TEST_EXPIRATION_AGE, timestamp))
249ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
250ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
251ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass _MockJobDirectory(job_directories._JobDirectory):
252ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Subclass of `_JobDirectory` used as a helper for tests."""
253ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
254ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    GLOB_PATTERN = '[0-9]*-*'
255ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
25624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
257ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def __init__(self, resultsdir):
258ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Create new job in initial state."""
259ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(_MockJobDirectory, self).__init__(resultsdir)
260ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._timestamp = None
2612c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        self.queue_args = [resultsdir, os.path.dirname(resultsdir)]
262ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
26324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
264ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def get_timestamp_if_finished(self):
265ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        return self._timestamp
266ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
26724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
268ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def set_finished(self, days_old):
269ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make this job appear to be finished.
270ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
271ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        After calling this function, calls to `enqueue_offload()`
272ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        will find this job as finished, but not expired and ready
273ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        for offload.  Note that when `days_old` is 0,
274ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `enqueue_offload()` will treat a finished job as eligible
275ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        for offload.
276ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
277ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param days_old The value of the `days_old` parameter that
278ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        will be passed to `enqueue_offload()` for
279ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        testing.
280ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
281ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
282ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._timestamp = _make_timestamp(days_old, False)
283ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
28424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
285ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def set_expired(self, days_old):
286ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make this job eligible to be offloaded.
287ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
288ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        After calling this function, calls to `offload` will attempt
289ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        to offload this job.
290ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
291ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param days_old The value of the `days_old` parameter that
292ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        will be passed to `enqueue_offload()` for
293ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                        testing.
294ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
295ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
296ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._timestamp = _make_timestamp(days_old, True)
297ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
29824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
299ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def set_incomplete(self):
300ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make this job appear to have failed offload just once."""
301ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_count += 1
30222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._first_offload_start = time.time()
303ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        if not os.path.isdir(self._dirname):
304ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            os.mkdir(self._dirname)
305ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
30624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
307ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def set_reportable(self):
308ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make this job be reportable."""
309ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.set_incomplete()
31022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._offload_count += 1
311ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
31224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
313ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def set_complete(self):
314ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make this job be completed."""
315ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_count += 1
316ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        if os.path.isdir(self._dirname):
317ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            os.rmdir(self._dirname)
318ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
319ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
3201e10e92049f4b2724ea43186083e995e418f9802Simran Basi    def process_gs_instructions(self):
3211e10e92049f4b2724ea43186083e995e418f9802Simran Basi        """Always still offload the job directory."""
3221e10e92049f4b2724ea43186083e995e418f9802Simran Basi        return True
3231e10e92049f4b2724ea43186083e995e418f9802Simran Basi
3241e10e92049f4b2724ea43186083e995e418f9802Simran Basi
3259f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnetteclass CommandListTests(unittest.TestCase):
3269f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette    """Tests for `get_cmd_list()`."""
3279f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
328e93c85778aa8b22aa88482c43092133d59434147MK Ryu    def _command_list_assertions(self, job, use_rsync=True, multi=False):
3299f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        """Call `get_cmd_list()` and check the return value.
3309f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
3319f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        Check the following assertions:
3329f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette          * The command name (argv[0]) is 'gsutil'.
333e93c85778aa8b22aa88482c43092133d59434147MK Ryu          * '-m' option (argv[1]) is on when the argument, multi, is True.
3349f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette          * The arguments contain the 'cp' subcommand.
3359f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette          * The next-to-last argument (the source directory) is the
3369f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette            job's `queue_args[0]`.
337dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi          * The last argument (the destination URL) is the job's
338dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi            'queue_args[1]'.
3399f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
3409f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        @param job A job with properly calculated arguments to
3419f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette                   `get_cmd_list()`
342e93c85778aa8b22aa88482c43092133d59434147MK Ryu        @param use_rsync True when using 'rsync'. False when using 'cp'.
343e93c85778aa8b22aa88482c43092133d59434147MK Ryu        @param multi True when using '-m' option for gsutil.
3449f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
3459f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        """
34624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        test_bucket_uri = 'gs://a-test-bucket'
34724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
34824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        gs_offloader.USE_RSYNC_ENABLED = use_rsync
34924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
35024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        command = gs_offloader.get_cmd_list(
351e93c85778aa8b22aa88482c43092133d59434147MK Ryu                multi, job.queue_args[0],
352e93c85778aa8b22aa88482c43092133d59434147MK Ryu                os.path.join(test_bucket_uri, job.queue_args[1]))
35324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
3549f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        self.assertEqual(command[0], 'gsutil')
355e93c85778aa8b22aa88482c43092133d59434147MK Ryu        if multi:
356e93c85778aa8b22aa88482c43092133d59434147MK Ryu            self.assertEqual(command[1], '-m')
3579f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        self.assertEqual(command[-2], job.queue_args[0])
35824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
35924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        if use_rsync:
36024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich            self.assertTrue('rsync' in command)
36124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich            self.assertEqual(command[-1],
36224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich                             os.path.join(test_bucket_uri, job.queue_args[0]))
36324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        else:
36424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich            self.assertTrue('cp' in command)
36524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich            self.assertEqual(command[-1],
36624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich                             os.path.join(test_bucket_uri, job.queue_args[1]))
36724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
3689f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
3699f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette    def test_get_cmd_list_regular(self):
3709f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        """Test `get_cmd_list()` as for a regular job."""
3719f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        job = _MockJobDirectory('118-debug')
3729f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        self._command_list_assertions(job)
3739f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
37424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
3759f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette    def test_get_cmd_list_special(self):
3769f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        """Test `get_cmd_list()` as for a special job."""
3779f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        job = _MockJobDirectory('hosts/host1/118-reset')
3789f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette        self._command_list_assertions(job)
3799f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
3809f4be0d66119211b3ece24bb985f1412d1f61322J. Richard Barnette
38124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich    def test_get_cmd_list_regular_no_rsync(self):
38224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        """Test `get_cmd_list()` as for a regular job."""
38324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        job = _MockJobDirectory('118-debug')
38424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        self._command_list_assertions(job, use_rsync=False)
38524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
38624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
38724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich    def test_get_cmd_list_special_no_rsync(self):
38824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        """Test `get_cmd_list()` as for a special job."""
38924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        job = _MockJobDirectory('hosts/host1/118-reset')
39024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich        self._command_list_assertions(job, use_rsync=False)
39124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
39224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
393e93c85778aa8b22aa88482c43092133d59434147MK Ryu    def test_get_cmd_list_regular_multi(self):
394e93c85778aa8b22aa88482c43092133d59434147MK Ryu        """Test `get_cmd_list()` as for a regular job with True multi."""
395e93c85778aa8b22aa88482c43092133d59434147MK Ryu        job = _MockJobDirectory('118-debug')
396e93c85778aa8b22aa88482c43092133d59434147MK Ryu        self._command_list_assertions(job, multi=True)
397e93c85778aa8b22aa88482c43092133d59434147MK Ryu
398e93c85778aa8b22aa88482c43092133d59434147MK Ryu
399e93c85778aa8b22aa88482c43092133d59434147MK Ryu    def test_get_cmd_list_special_multi(self):
400e93c85778aa8b22aa88482c43092133d59434147MK Ryu        """Test `get_cmd_list()` as for a special job with True multi."""
401e93c85778aa8b22aa88482c43092133d59434147MK Ryu        job = _MockJobDirectory('hosts/host1/118-reset')
402e93c85778aa8b22aa88482c43092133d59434147MK Ryu        self._command_list_assertions(job, multi=True)
403e93c85778aa8b22aa88482c43092133d59434147MK Ryu
404e93c85778aa8b22aa88482c43092133d59434147MK Ryu
405ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# Below is partial sample of e-mail notification text.  This text is
406ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# deliberately hard-coded and then parsed to create the test data;
407ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# the idea is to make sure the actual text format will be reviewed
408ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# by a human being.
409ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette#
410ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# first offload      count  directory
411ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette# --+----1----+----  ----+  ----+----1----+----2----+----3
412ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette_SAMPLE_DIRECTORIES_REPORT = '''\
413ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette=================== ======  ==============================
414ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:09:26      1  118-fubar
415ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:19:23      2  117-fubar
416ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:29:20      6  116-fubar
417ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:39:17     24  115-fubar
418ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:49:14    120  114-fubar
419ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 15:59:11    720  113-fubar
420ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 16:09:08   5040  112-fubar
421ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette2014-03-14 16:19:05  40320  111-fubar
422ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette'''
423ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
424ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
425ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass EmailTemplateTests(mox.MoxTestBase):
426ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Test the formatting of e-mail notifications."""
427ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
428ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
429ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(EmailTemplateTests, self).setUp()
430ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.StubOutWithMock(email_manager.manager,
431ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                                 'send_email')
432ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._joblist = []
433ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        for line in _SAMPLE_DIRECTORIES_REPORT.split('\n')[1 : -1]:
434ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            date_, time_, count, dir_ = line.split()
435ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            job = _MockJobDirectory(dir_)
436ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            job._offload_count = int(count)
437dfea368e5c830b1d7950ced5ee7b191e3b141ca3Dan Shi            timestruct = time.strptime("%s %s" % (date_, time_),
438dfea368e5c830b1d7950ced5ee7b191e3b141ca3Dan Shi                                       gs_offloader.ERROR_EMAIL_TIME_FORMAT)
439ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            job._first_offload_start = time.mktime(timestruct)
440ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            # enter the jobs in reverse order, to make sure we
441ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            # test that the output will be sorted.
442ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._joblist.insert(0, job)
443ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
44424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
445ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_email_template(self):
446ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Trigger an e-mail report and check its contents."""
447ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # The last line of the report is a separator that we
448ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # repeat in the first line of our expected result data.
449ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # So, we remove that separator from the end of the of
450ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # the e-mail report message.
451ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        #
452ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # The last element in the list returned by split('\n')
453ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # will be an empty string, so to remove the separator,
454ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # we remove the next-to-last entry in the list.
455ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        report_lines = gs_offloader.ERROR_EMAIL_REPORT_FORMAT.split('\n')
456ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        expected_message = ('\n'.join(report_lines[: -2] +
457ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                                      report_lines[-1 :]) +
458ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                            _SAMPLE_DIRECTORIES_REPORT)
459ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        email_manager.manager.send_email(
460ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            mox.IgnoreArg(), mox.IgnoreArg(), expected_message)
461ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.ReplayAll()
462ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        gs_offloader.report_offload_failures(self._joblist)
463ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
464ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
465686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng    def test_email_url(self):
466686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng        """Check that the expected helper url is in the email header."""
467686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng        self.assertIn(gs_offloader.ERROR_EMAIL_HELPER_URL,
468686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng                      gs_offloader.ERROR_EMAIL_REPORT_FORMAT)
469686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng
470686ae8c339d31988e07bde0ab5d7b3731c0570f1Kevin Cheng
471dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnetteclass _MockJob(object):
472dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    """Class to mock the return value of `AFE.get_jobs()`."""
473dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    def __init__(self, created):
474dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.created_on = created
475dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
476dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
477dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnetteclass _MockHostQueueEntry(object):
478dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    """Class to mock the return value of `AFE.get_host_queue_entries()`."""
479dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    def __init__(self, finished):
480dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.finished_on = finished
481dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
482dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
483dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnetteclass _MockSpecialTask(object):
484dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    """Class to mock the return value of `AFE.get_special_tasks()`."""
485dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    def __init__(self, finished):
486dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.time_finished = finished
487dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
488dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
4892c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnetteclass JobDirectorySubclassTests(mox.MoxTestBase):
4902c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette    """Test specific to RegularJobDirectory and SpecialJobDirectory.
4913e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
4923e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    This provides coverage for the implementation in both
4933e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    RegularJobDirectory and SpecialJobDirectory.
4943e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
4953e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    """
4963e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
4973e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    def setUp(self):
4982c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        super(JobDirectorySubclassTests, self).setUp()
499dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.StubOutWithMock(job_directories._AFE, 'get_jobs')
500dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.StubOutWithMock(job_directories._AFE,
501dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 'get_host_queue_entries')
502dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.StubOutWithMock(job_directories._AFE,
503dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 'get_special_tasks')
5043e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
50524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
5062c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette    def test_regular_job_fields(self):
5072c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        """Test the constructor for `RegularJobDirectory`.
5082c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
5092c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        Construct a regular job, and assert that the `_dirname`
5102c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        and `_id` attributes are set as expected.
5112c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
5122c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        """
5132c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        resultsdir = '118-fubar'
5142c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        job = job_directories.RegularJobDirectory(resultsdir)
5152c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        self.assertEqual(job._dirname, resultsdir)
516cf4d2032ea4bf5af680383f36308d581876bbbb0Dan Shi        self.assertEqual(job._id, 118)
5172c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
51824f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
5192c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette    def test_special_job_fields(self):
5202c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        """Test the constructor for `SpecialJobDirectory`.
5212c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
5222c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        Construct a special job, and assert that the `_dirname`
5232c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        and `_id` attributes are set as expected.
5242c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
5252c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        """
5262c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        destdir = 'hosts/host1'
5272c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        resultsdir = destdir + '/118-reset'
5282c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        job = job_directories.SpecialJobDirectory(resultsdir)
5292c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        self.assertEqual(job._dirname, resultsdir)
530cf4d2032ea4bf5af680383f36308d581876bbbb0Dan Shi        self.assertEqual(job._id, 118)
5312c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette
53224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
533dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette    def _check_finished_job(self, jobtime, hqetimes, expected):
534dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        """Mock and test behavior of a finished job.
535dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
536dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        Initialize the mocks for a call to
537dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        `get_timestamp_if_finished()`, then simulate one call.
538dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        Assert that the returned timestamp matches the passed
539dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        in expected value.
540dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
541dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        @param jobtime Time used to construct a _MockJob object.
542dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        @param hqetimes List of times used to construct
543dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                        _MockHostQueueEntry objects.
544dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        @param expected Expected time to be returned by
545dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                        get_timestamp_if_finished
546dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
547dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        """
548dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job = job_directories.RegularJobDirectory('118-fubar')
549dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job_directories._AFE.get_jobs(
550dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                id=job._id, finished=True).AndReturn(
551dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                        [_MockJob(jobtime)])
552dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job_directories._AFE.get_host_queue_entries(
553dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                finished_on__isnull=False,
554dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                job_id=job._id).AndReturn(
555dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                        [_MockHostQueueEntry(t) for t in hqetimes])
556dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.ReplayAll()
557dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.assertEqual(expected, job.get_timestamp_if_finished())
558dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.VerifyAll()
559dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
560dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
5613e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    def test_finished_regular_job(self):
5623e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """Test getting the timestamp for a finished regular job.
5633e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
5643e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        Tests the return value for
5653e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        `RegularJobDirectory.get_timestamp_if_finished()` when
5663e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        the AFE indicates the job is finished.
5673e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
5683e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """
569dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        created_timestamp = _make_timestamp(1, True)
570dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        hqe_timestamp = _make_timestamp(0, True)
571dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self._check_finished_job(created_timestamp,
572dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 [hqe_timestamp],
573dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 hqe_timestamp)
574fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
57524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
576fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi    def test_finished_regular_job_multiple_hqes(self):
577fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        """Test getting the timestamp for a regular job with multiple hqes.
578fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
579fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        Tests the return value for
580fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        `RegularJobDirectory.get_timestamp_if_finished()` when
581fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        the AFE indicates the job is finished and the job has multiple host
582fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        queue entries.
583fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
584dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        Tests that the returned timestamp is the latest timestamp in
585dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        the list of HQEs, regardless of the returned order.
586dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette
587fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        """
588fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        created_timestamp = _make_timestamp(2, True)
589fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        older_hqe_timestamp = _make_timestamp(1, True)
590fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        newer_hqe_timestamp = _make_timestamp(0, True)
591dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        hqe_list = [older_hqe_timestamp,
592dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                    newer_hqe_timestamp]
593dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self._check_finished_job(created_timestamp,
594dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 hqe_list,
595dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 newer_hqe_timestamp)
596dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.ResetAll()
597dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        hqe_list.reverse()
598dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self._check_finished_job(created_timestamp,
599dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 hqe_list,
600dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                                 newer_hqe_timestamp)
601fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
60224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
603fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi    def test_finished_regular_job_null_finished_times(self):
604fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        """Test getting the timestamp for an aborted regular job.
605fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
606fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        Tests the return value for
607fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        `RegularJobDirectory.get_timestamp_if_finished()` when
608fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        the AFE indicates the job is finished and the job has aborted host
609fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        queue entries.
610fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi
611fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        """
612fb98e46b33c3f683173b980e027523dfb91f2759Simran Basi        timestamp = _make_timestamp(0, True)
613dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self._check_finished_job(timestamp, [], timestamp)
6143e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
61524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
6163e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    def test_unfinished_regular_job(self):
6173e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """Test getting the timestamp for an unfinished regular job.
6183e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6193e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        Tests the return value for
6203e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        `RegularJobDirectory.get_timestamp_if_finished()` when
6213e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        the AFE indicates the job is not finished.
6223e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6233e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """
6243e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        job = job_directories.RegularJobDirectory('118-fubar')
625dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job_directories._AFE.get_jobs(
626dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                id=job._id, finished=True).AndReturn([])
6273e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.mox.ReplayAll()
6283e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.assertIsNone(job.get_timestamp_if_finished())
629dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.VerifyAll()
6303e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
63124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
6323e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    def test_finished_special_job(self):
6333e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """Test getting the timestamp for a finished special job.
6343e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6353e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        Tests the return value for
6363e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        `SpecialJobDirectory.get_timestamp_if_finished()` when
6373e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        the AFE indicates the job is finished.
6383e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6393e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """
6402c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        job = job_directories.SpecialJobDirectory(
6412c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette                'hosts/host1/118-reset')
6423e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        timestamp = _make_timestamp(0, True)
643dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job_directories._AFE.get_special_tasks(
644dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                id=job._id, is_complete=True).AndReturn(
645dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                    [_MockSpecialTask(timestamp)])
6463e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.mox.ReplayAll()
6473e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.assertEqual(timestamp,
6483e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette                         job.get_timestamp_if_finished())
649dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.VerifyAll()
6503e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
65124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
6523e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette    def test_unfinished_special_job(self):
6533e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """Test getting the timestamp for an unfinished special job.
6543e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6553e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        Tests the return value for
6563e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        `SpecialJobDirectory.get_timestamp_if_finished()` when
6573e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        the AFE indicates the job is not finished.
6583e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6593e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        """
6602c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        job = job_directories.SpecialJobDirectory(
6612c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette                'hosts/host1/118-reset')
662dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        job_directories._AFE.get_special_tasks(
663dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette                id=job._id, is_complete=True).AndReturn([])
6643e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.mox.ReplayAll()
6653e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette        self.assertIsNone(job.get_timestamp_if_finished())
666dd0227d5503b9c0ea63837eec26f87c4e4958e4aJ. Richard Barnette        self.mox.VerifyAll()
6673e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
6683e3ed6a9627a156a2240d607565e7c6f78151f28J. Richard Barnette
669ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass _TempResultsDirTestBase(mox.MoxTestBase):
670ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Base class for tests using a temporary results directory."""
671ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
6720880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette    REGULAR_JOBLIST = [
6730880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        '111-fubar', '112-fubar', '113-fubar', '114-snafu']
6740880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette    HOST_LIST = ['host1', 'host2', 'host3']
6750880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette    SPECIAL_JOBLIST = [
6760880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        'hosts/host1/333-reset', 'hosts/host1/334-reset',
6770880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        'hosts/host2/444-reset', 'hosts/host3/555-reset']
6780880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette
67924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
680ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
681ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(_TempResultsDirTestBase, self).setUp()
6820880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self._resultsroot = tempfile.mkdtemp()
6830880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self._cwd = os.getcwd()
6840880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        os.chdir(self._resultsroot)
685ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
68624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
687ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def tearDown(self):
6880880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        os.chdir(self._cwd)
689ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        shutil.rmtree(self._resultsroot)
690ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(_TempResultsDirTestBase, self).tearDown()
691ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
69224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
693ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def make_job(self, jobdir):
694ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Create a job with results in `self._resultsroot`.
695ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
696ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param jobdir Name of the subdirectory to be created in
697ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                      `self._resultsroot`.
698ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
699ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
7000880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        os.mkdir(jobdir)
7010880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        return _MockJobDirectory(jobdir)
7020880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette
70324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7040880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette    def make_job_hierarchy(self):
7050880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        """Create a sample hierarchy of job directories.
7060880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette
7070880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        `self.REGULAR_JOBLIST` is a list of directories for regular
7080880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        jobs to be created; `self.SPECIAL_JOBLIST` is a list of
7090880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        directories for special jobs to be created.
7100880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette
7110880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        """
7120880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
7130880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette            os.mkdir(d)
7140880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        hostsdir = 'hosts'
7150880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        os.mkdir(hostsdir)
7160880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for host in self.HOST_LIST:
7170880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette            os.mkdir(os.path.join(hostsdir, host))
7180880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.SPECIAL_JOBLIST:
7190880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette            os.mkdir(d)
720ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
721ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
7222e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnetteclass OffloadDirectoryTests(_TempResultsDirTestBase):
7232e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    """Tests for `offload_dir()`."""
7242e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7252e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def setUp(self):
7262e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        super(OffloadDirectoryTests, self).setUp()
7272e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        # offload_dir() logs messages; silence them.
7282e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._saved_loglevel = logging.getLogger().getEffectiveLevel()
7292e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        logging.getLogger().setLevel(logging.CRITICAL+1)
7302e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._job = self.make_job(self.REGULAR_JOBLIST[0])
7312e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self.mox.StubOutWithMock(gs_offloader, 'get_cmd_list')
7322e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self.mox.StubOutWithMock(signal, 'alarm')
7332e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
73424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7352e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def tearDown(self):
7362e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        logging.getLogger().setLevel(self._saved_loglevel)
7372e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        super(OffloadDirectoryTests, self).tearDown()
7382e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7394211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia    def _mock_upload_testresult_files(self):
7404211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self.mox.StubOutWithMock(gs_offloader, 'upload_testresult_files')
7414211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        gs_offloader.upload_testresult_files(
7424211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia                mox.IgnoreArg(),mox.IgnoreArg()).AndReturn(None)
74324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
744dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi    def _mock_offload_dir_calls(self, command, queue_args):
7452e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Mock out the calls needed by `offload_dir()`.
7462e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7472e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        This covers only the calls made when there is no timeout.
7482e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7492e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        @param command Command list to be returned by the mocked
7502e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                       call to `get_cmd_list()`.
7512e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7522e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """
7532e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(gs_offloader.OFFLOAD_TIMEOUT_SECS)
754dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        command.append(queue_args[0])
7552e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        gs_offloader.get_cmd_list(
756e93c85778aa8b22aa88482c43092133d59434147MK Ryu                False, queue_args[0],
757e93c85778aa8b22aa88482c43092133d59434147MK Ryu                '%s%s' % (utils.DEFAULT_OFFLOAD_GSURI,
758e93c85778aa8b22aa88482c43092133d59434147MK Ryu                          queue_args[1])).AndReturn(command)
7594211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self._mock_upload_testresult_files()
7602e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(0)
7612e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(0)
7622e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
76324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7642e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def _run_offload_dir(self, should_succeed):
7652e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Make one call to `offload_dir()`.
7662e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7672e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        The caller ensures all mocks are set up already.
7682e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7692e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        @param should_succeed True iff the call to `offload_dir()`
7702e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                              is expected to succeed and remove the
7712e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                              offloaded job directory.
7722e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
7732e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """
7742e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self.mox.ReplayAll()
775dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        gs_offloader.get_offload_dir_func(
776e93c85778aa8b22aa88482c43092133d59434147MK Ryu                utils.DEFAULT_OFFLOAD_GSURI, False)(
777e93c85778aa8b22aa88482c43092133d59434147MK Ryu                        self._job.queue_args[0],
778e93c85778aa8b22aa88482c43092133d59434147MK Ryu                        self._job.queue_args[1])
7792e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self.mox.VerifyAll()
7802e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self.assertEqual(not should_succeed,
7812e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                         os.path.isdir(self._job.queue_args[0]))
7822e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
78324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7842e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def test_offload_success(self):
7852e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Test that `offload_dir()` can succeed correctly."""
786dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self._mock_offload_dir_calls(['test', '-d'],
787dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                                     self._job.queue_args)
7882e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._run_offload_dir(True)
7892e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
79024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7912e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def test_offload_failure(self):
7922e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Test that `offload_dir()` can fail correctly."""
793dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi        self._mock_offload_dir_calls(['test', '!', '-d'],
794dd129979e8227c960f4c7a3d2a1665007f8a424eSimran Basi                                     self._job.queue_args)
7952e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._run_offload_dir(False)
7962e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
79724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
7982e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def test_offload_timeout_early(self):
7992e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Test that `offload_dir()` times out correctly.
8002e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
8012e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        This test triggers timeout at the earliest possible moment,
8022e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        at the first call to set the timeout alarm.
8032e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
8042e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """
8054211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self._mock_upload_testresult_files()
8062e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(gs_offloader.OFFLOAD_TIMEOUT_SECS).AndRaise(
8072e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                        gs_offloader.TimeoutException('fubar'))
8082e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(0)
8092e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._run_offload_dir(False)
8102e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
81124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
8122e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette    def test_offload_timeout_late(self):
8132e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """Test that `offload_dir()` times out correctly.
8142e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
8152e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        This test triggers timeout at the latest possible moment, at
8162e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        the call to clear the timeout alarm.
8172e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
8182e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        """
8192e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(gs_offloader.OFFLOAD_TIMEOUT_SECS)
8202e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        gs_offloader.get_cmd_list(
821e93c85778aa8b22aa88482c43092133d59434147MK Ryu                False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
8222e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                        ['test', '-d', self._job.queue_args[0]])
8234211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self._mock_upload_testresult_files()
8242e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(0).AndRaise(
8252e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette                gs_offloader.TimeoutException('fubar'))
8262e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        signal.alarm(0)
8272e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette        self._run_offload_dir(False)
8282e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
8292e443efce8dc34f6db6ab566a4c8a552fd8fff2dJ. Richard Barnette
830affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi    def test_sanitize_dir(self):
831affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        """Test that folder/file name with invalid character can be corrected.
832affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        """
833affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        results_folder = tempfile.mkdtemp()
834affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        invalid_chars = '_'.join(gs_offloader.INVALID_GS_CHARS)
835affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        invalid_files = []
836affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        invalid_folder = os.path.join(
837affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                results_folder,
838affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                'invalid_name_folder_%s' % invalid_chars)
839affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        invalid_files.append(os.path.join(
840affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                invalid_folder,
841affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                'invalid_name_file_%s' % invalid_chars))
842affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        for r in gs_offloader.INVALID_GS_CHAR_RANGE:
843affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi            for c in range(r[0], r[1]+1):
844affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                # NULL cannot be in file name.
845affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                if c != 0:
846affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                    invalid_files.append(os.path.join(
847affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                            invalid_folder,
848affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                            'invalid_name_file_%s' % chr(c)))
849affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        good_folder =  os.path.join(results_folder, 'valid_name_folder')
850affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        good_file = os.path.join(good_folder, 'valid_name_file')
851affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        for folder in [invalid_folder, good_folder]:
852affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi            os.makedirs(folder)
853affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        for f in invalid_files + [good_file]:
854affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi            with open(f, 'w'):
855affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                pass
856affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        gs_offloader.sanitize_dir(results_folder)
857affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        for _, dirs, files in os.walk(results_folder):
858affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi            for name in dirs + files:
859affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                self.assertEqual(name, gs_offloader.get_sanitized_name(name))
860affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                for c in name:
861affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                    self.assertFalse(c in gs_offloader.INVALID_GS_CHARS)
862affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                    for r in gs_offloader.INVALID_GS_CHAR_RANGE:
863affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi                        self.assertFalse(ord(c) >= r[0] and ord(c) <= r[1])
864affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        self.assertTrue(os.path.exists(good_file))
865affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi        shutil.rmtree(results_folder)
866affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi
867affb922d30a3f5e528103c0314d5f0586b7a90dcDan Shi
8681b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi    def check_limit_file_count(self, is_test_job=True):
8691b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        """Test that folder with too many files can be compressed.
8701b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
8711b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        @param is_test_job: True to check the method with test job result
8721b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                            folder. Set to False for special task folder.
8731b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        """
8741b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        results_folder = tempfile.mkdtemp()
8751b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        host_folder = os.path.join(
8761b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                results_folder,
8771b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                'lab1-host1' if is_test_job else 'hosts/lab1-host1/1-repair')
8781b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        debug_folder = os.path.join(host_folder, 'debug')
8791b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        sysinfo_folder = os.path.join(host_folder, 'sysinfo')
8801b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        for folder in [debug_folder, sysinfo_folder]:
8811b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi            os.makedirs(folder)
8821b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi            for i in range(10):
8831b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                with open(os.path.join(folder, str(i)), 'w') as f:
8841b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                    f.write('test')
8851b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
8861b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        gs_offloader.MAX_FILE_COUNT = 100
8871b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        gs_offloader.limit_file_count(
8881b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                results_folder if is_test_job else host_folder)
8891b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.assertTrue(os.path.exists(sysinfo_folder))
8901b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
8911b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        gs_offloader.MAX_FILE_COUNT = 10
8921b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        gs_offloader.limit_file_count(
8931b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi                results_folder if is_test_job else host_folder)
8941b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.assertFalse(os.path.exists(sysinfo_folder))
8951b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.assertTrue(os.path.exists(sysinfo_folder + '.tgz'))
8961b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.assertTrue(os.path.exists(debug_folder))
8971b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
8981b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        shutil.rmtree(results_folder)
8991b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
9001b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
9011b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi    def test_limit_file_count(self):
9021b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        """Test that folder with too many files can be compressed.
9031b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        """
9041b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.check_limit_file_count(is_test_job=True)
9051b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi        self.check_limit_file_count(is_test_job=False)
9061b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
9074211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia    def test_upload_testresult_files(self):
9084211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        """Test upload_testresult_files"""
9094211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        results_folder = tempfile.mkdtemp()
9104211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        host_folder = os.path.join(results_folder, 'chromeos4-row9-rack11-host22')
9114211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        debug_folder = os.path.join(host_folder, 'debug')
9124211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        sysinfo_folder = os.path.join(host_folder, 'sysinfo')
9134211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        cts_result_folder = os.path.join(
9144211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia                host_folder, 'cheets_CTS.android.dpi', 'results', 'cts-results')
9154211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        timestamp_str = '2016.04.28_01.41.44'
9164211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        timestamp_folder = os.path.join(cts_result_folder, timestamp_str)
9174211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        for folder in [debug_folder, sysinfo_folder, cts_result_folder, timestamp_folder]:
9184211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia            os.makedirs(folder)
9194211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        zip_file = os.path.join(cts_result_folder, timestamp_str + '.zip')
9204211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        with open(zip_file, 'w') as f:
9214211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia            f.write('test')
9224211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia
9234211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        test_result_file = os.path.join(timestamp_folder, 'testResult.xml')
9244211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        with open(test_result_file, 'w') as f:
9254211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia            f.write('test')
9264211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia
9274211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        gs_offloader.get_cmd_list(
9284211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia            False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
9294211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia                    ['test', '-d', cts_result_folder])
9304211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        gs_offloader.get_cmd_list(
9314211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia            False, mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
9324211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia                    ['test', '-d', cts_result_folder])
9334211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia
9344211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self.mox.ReplayAll()
9354211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        gs_offloader.upload_testresult_files(results_folder, False)
9364211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self.mox.VerifyAll()
9374211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self.assertTrue(os.path.exists(zip_file))
9384211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        self.assertFalse(os.path.exists(
9394211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia                os.path.join(timestamp_folder,'testResult.xml.gz')))
9404211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia
9414211124209fdb4469462b6e1b39433cc52b76d02Ningning Xia        shutil.rmtree(results_folder)
9421b4c7c396d5043b24d6bf65c069a85371bb00e5cDan Shi
943ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass JobDirectoryOffloadTests(_TempResultsDirTestBase):
944ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests for `_JobDirectory.enqueue_offload()`.
945ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
946ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    When testing with a `days_old` parameter of 0, we use
947ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    `set_finished()` instead of `set_expired()`.  This causes the
948ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    job's timestamp to be set in the future.  This is done so as
949ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    to test that when `days_old` is 0, the job is always treated
950ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    as eligible for offload, regardless of the timestamp's value.
951ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
952ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    Testing covers the following assertions:
953ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette     A. Each time `enqueue_offload()` is called, a message that
954ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        includes the job's directory name will be logged using
955ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `logging.debug()`, regardless of whether the job was
956ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        enqueued.  Nothing else is allowed to be logged.
957ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette     B. If the job is not eligible to be offloaded,
95822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        `get_failure_time()` and `get_failure_count()` are 0.
959ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette     C. If the job is not eligible for offload, nothing is
960ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        enqueued in `queue`.
96122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette     D. When the job is offloaded, `get_failure_count()` increments
962ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        each time.
963ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette     E. When the job is offloaded, the appropriate parameters are
964ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        enqueued exactly once.
96522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette     F. The first time a job is offloaded, `get_failure_time()` is
966ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        set to the current time.
96722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette     G. `get_failure_time()` only changes the first time that the
968ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        job is offloaded.
969ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
970ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    The test cases below are designed to exercise all of the
971ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    meaningful state transitions at least once.
972ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
973ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """
974ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
975ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
976ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(JobDirectoryOffloadTests, self).setUp()
9770880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self._job = self.make_job(self.REGULAR_JOBLIST[0])
978ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._queue = Queue.Queue()
979ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
98024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
981ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _offload_unexpired_job(self, days_old):
982ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make calls to `enqueue_offload()` for an unexpired job.
983ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
984ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This method tests assertions B and C that calling
985ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `enqueue_offload()` has no effect.
986ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
987ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
98822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_count(), 0)
98922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_time(), 0)
99022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._job.enqueue_offload(self._queue, days_old)
99122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._job.enqueue_offload(self._queue, days_old)
992ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertTrue(self._queue.empty())
99322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_count(), 0)
99422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_time(), 0)
99522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertFalse(self._job.is_reportable())
996ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
99724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
998ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _offload_expired_once(self, days_old, count):
999ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make one call to `enqueue_offload()` for an expired job.
1000ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1001ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This method tests assertions D and E regarding side-effects
1002ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        expected when a job is offloaded.
1003ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1004ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
100522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._job.enqueue_offload(self._queue, days_old)
100622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_count(), count)
1007ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(self._queue.empty())
1008ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        v = self._queue.get_nowait()
1009ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertTrue(self._queue.empty())
10102c72dddb1d05ed43b23ebe847601d7f160a9753aJ. Richard Barnette        self.assertEqual(v, self._job.queue_args)
1011ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
101224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1013ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _offload_expired_job(self, days_old):
1014ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Make calls to `enqueue_offload()` for a just-expired job.
1015ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1016ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This method directly tests assertions F and G regarding
101722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        side-effects on `get_failure_time()`.
1018ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1019ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1020ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        t0 = time.time()
1021ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_once(days_old, 1)
102222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertFalse(self._job.is_reportable())
102322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        t1 = self._job.get_failure_time()
1024ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertLessEqual(t1, time.time())
1025ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertGreaterEqual(t1, t0)
1026ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_once(days_old, 2)
102722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertTrue(self._job.is_reportable())
102822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_time(), t1)
1029ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_once(days_old, 3)
103022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertTrue(self._job.is_reportable())
103122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.assertEqual(self._job.get_failure_time(), t1)
1032ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
103324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1034ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_1_no_expiration(self):
1035ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` of 0.
1036ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1037ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are
1038ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        made both before and after the job becomes expired.
1039ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1040ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1041ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_unexpired_job(0)
1042ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_finished(0)
1043ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(0)
1044ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
104524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1046ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_2_no_expiration(self):
1047ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` of 0.
1048ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1049ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are made
1050ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only after the job becomes expired.
1051ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1052ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1053ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_finished(0)
1054ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(0)
1055ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
105624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1057ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_1_with_expiration(self):
1058ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1059ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1060ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are made
1061ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        before the job finishes, before the job expires, and after
1062ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        the job expires.
1063ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1064ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1065ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1066ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_finished(_TEST_EXPIRATION_AGE)
1067ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1068ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_expired(_TEST_EXPIRATION_AGE)
1069ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(_TEST_EXPIRATION_AGE)
1070ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
107124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1072ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_2_with_expiration(self):
1073ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1074ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1075ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are made
1076ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        between finishing and expiration, and after the job expires.
1077ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1078ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1079ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_finished(_TEST_EXPIRATION_AGE)
1080ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1081ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_expired(_TEST_EXPIRATION_AGE)
1082ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(_TEST_EXPIRATION_AGE)
1083ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
108424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1085ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_3_with_expiration(self):
1086ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1087ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1088ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are made
1089ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only before finishing and after expiration.
1090ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1091ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1092ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_unexpired_job(_TEST_EXPIRATION_AGE)
1093ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_expired(_TEST_EXPIRATION_AGE)
1094ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(_TEST_EXPIRATION_AGE)
1095ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
109624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1097ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_case_4_with_expiration(self):
1098ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test a series of `enqueue_offload()` calls with `days_old` non-zero.
1099ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1100ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        This tests that offload works as expected if calls are made
1101ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only after expiration.
1102ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1103ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1104ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._job.set_expired(_TEST_EXPIRATION_AGE)
1105ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offload_expired_job(_TEST_EXPIRATION_AGE)
1106ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1107ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1108ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass GetJobDirectoriesTests(_TempResultsDirTestBase):
1109ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests for `_JobDirectory.get_job_directories()`."""
1110ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1111ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
1112ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(GetJobDirectoriesTests, self).setUp()
11130880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self.make_job_hierarchy()
11140880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        os.mkdir('not-a-job')
11150880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        open('not-a-dir', 'w').close()
1116ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
111724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1118ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _run_get_directories(self, cls, expected_list):
1119ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `get_job_directories()` for the given class.
1120ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1121ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Calls the method, and asserts that the returned list of
1122ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        directories matches the expected return value.
1123ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1124ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param expected_list Expected return value from the call.
1125ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1126ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        dirlist = cls.get_job_directories()
1127ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertEqual(set(dirlist), set(expected_list))
1128ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
112924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1130ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_get_regular_jobs(self):
1131ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `RegularJobDirectory.get_job_directories()`."""
1132ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._run_get_directories(job_directories.RegularJobDirectory,
11330880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette                                  self.REGULAR_JOBLIST)
1134ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
113524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1136ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_get_special_jobs(self):
1137ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `SpecialJobDirectory.get_job_directories()`."""
1138ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._run_get_directories(job_directories.SpecialJobDirectory,
11390880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette                                  self.SPECIAL_JOBLIST)
1140ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1141ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1142ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass AddJobsTests(_TempResultsDirTestBase):
1143ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests for `Offloader._add_new_jobs()`."""
1144ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
11450880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette    MOREJOBS = ['115-fubar', '116-fubar', '117-fubar', '118-snafu']
1146ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1147ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
1148ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(AddJobsTests, self).setUp()
114922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._initial_job_names = (
115022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette            set(self.REGULAR_JOBLIST) | set(self.SPECIAL_JOBLIST))
11510880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self.make_job_hierarchy()
11520880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        self._offloader = gs_offloader.Offloader(_get_options(['-a']))
115322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.mox.StubOutWithMock(logging, 'debug')
1154ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
115524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
115622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette    def _run_add_new_jobs(self, expected_key_set):
1157ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Basic test assertions for `_add_new_jobs()`.
1158ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1159ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Asserts the following:
1160ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The keys in the offloader's `_open_jobs` dictionary
1161ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            matches the expected set of keys.
1162ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * For every job in `_open_jobs`, the job has the expected
1163ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            directory name.
1164ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1165ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
116622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        count = len(expected_key_set) - len(self._offloader._open_jobs)
116722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        logging.debug(mox.IgnoreArg(), count)
116822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.mox.ReplayAll()
116922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._offloader._add_new_jobs()
1170ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertEqual(expected_key_set,
1171ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                         set(self._offloader._open_jobs.keys()))
1172ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        for jobkey, job in self._offloader._open_jobs.items():
1173ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self.assertEqual(jobkey, job._dirname)
117422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.mox.VerifyAll()
117522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.mox.ResetAll()
1176ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
117724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1178ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_add_jobs_empty(self):
1179ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test adding jobs to an empty dictionary.
1180ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1181ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Calls the offloader's `_add_new_jobs()`, then perform
1182ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        the assertions of `self._check_open_jobs()`.
1183ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1184ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
118522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_add_new_jobs(self._initial_job_names)
1186ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
118724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1188ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_add_jobs_non_empty(self):
1189ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test adding jobs to a non-empty dictionary.
1190ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1191ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Calls the offloader's `_add_new_jobs()` twice; once from
1192ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        initial conditions, and then again after adding more
1193ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        directories.  After the second call, perform the assertions
1194ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        of `self._check_open_jobs()`.  Additionally, assert that
1195ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        keys added by the first call still map to their original
1196ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        job object after the second call.
1197ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1198ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
119922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_add_new_jobs(self._initial_job_names)
1200ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        jobs_copy = self._offloader._open_jobs.copy()
12010880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.MOREJOBS:
12020880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette            os.mkdir(d)
120322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_add_new_jobs(self._initial_job_names |
120422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette                                 set(self.MOREJOBS))
1205ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        for key in jobs_copy.keys():
1206ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self.assertIs(jobs_copy[key],
1207ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                          self._offloader._open_jobs[key])
1208ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1209ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1210ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass JobStateTests(_TempResultsDirTestBase):
1211ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests for job state predicates.
1212ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1213ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    This tests for the expected results from the
1214ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    `is_offloaded()` and `is_reportable()` predicate
1215ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    methods.
1216ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1217ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """
1218ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1219ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_unfinished_job(self):
1220ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test that an unfinished job reports the correct state.
1221ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1222ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job is "unfinished" if it isn't marked complete in the
1223ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        database.  A job in this state is neither "complete" nor
1224ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        "reportable".
1225ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1226ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
12270880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        job = self.make_job(self.REGULAR_JOBLIST[0])
1228ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_offloaded())
1229ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_reportable())
1230ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
123124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1232ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_incomplete_job(self):
1233ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test that an incomplete job reports the correct state.
1234ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1235ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job is "incomplete" if exactly one attempt has been made
1236ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        to offload the job, but its results directory still exists.
1237ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job in this state is neither "complete" nor "reportable".
1238ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1239ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
12400880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        job = self.make_job(self.REGULAR_JOBLIST[0])
1241ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        job.set_incomplete()
1242ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_offloaded())
1243ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_reportable())
1244ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
124524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1246ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_reportable_job(self):
1247ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test that a reportable job reports the correct state.
1248ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1249ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job is "reportable" if more than one attempt has been made
1250ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        to offload the job, and its results directory still exists.
1251ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job in this state is "reportable", but not "complete".
1252ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1253ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
12540880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        job = self.make_job(self.REGULAR_JOBLIST[0])
1255ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        job.set_reportable()
1256ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_offloaded())
1257ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertTrue(job.is_reportable())
1258ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
125924f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1260ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_completed_job(self):
1261ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test that a completed job reports the correct state.
1262ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1263ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job is "completed" if at least one attempt has been made
1264ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        to offload the job, and its results directory still exists.
1265ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        A job in this state is "complete", and not "reportable".
1266ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1267ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
12680880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        job = self.make_job(self.REGULAR_JOBLIST[0])
1269ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        job.set_complete()
1270ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertTrue(job.is_offloaded())
1271ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertFalse(job.is_reportable())
1272ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1273ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1274ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteclass ReportingTests(_TempResultsDirTestBase):
1275ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    """Tests for `Offloader._update_offload_results()`."""
1276ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1277ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def setUp(self):
1278ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        super(ReportingTests, self).setUp()
1279ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offloader = gs_offloader.Offloader(_get_options([]))
1280ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.StubOutWithMock(email_manager.manager,
1281ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                                 'send_email')
128222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self.mox.StubOutWithMock(logging, 'debug')
1283ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
128424f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1285ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _add_job(self, jobdir):
1286ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Add a job to the dictionary of unfinished jobs."""
1287ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        j = self.make_job(jobdir)
1288ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offloader._open_jobs[j._dirname] = j
1289ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        return j
1290ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
129124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
129222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette    def _expect_log_message(self, new_open_jobs, with_failures):
129322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        """Mock expected logging calls.
129422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
129522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        `_update_offload_results()` logs one message with the number
129622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        of jobs removed from the open job set and the number of jobs
129722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        still remaining.  Additionally, if there are reportable
129822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        jobs, then it logs the number of jobs that haven't yet
129922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        offloaded.
130022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
130122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        This sets up the logging calls using `new_open_jobs` to
130222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        figure the job counts.  If `with_failures` is true, then
130322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        the log message is set up assuming that all jobs in
130422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        `new_open_jobs` have offload failures.
130522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
130622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        @param new_open_jobs New job set for calculating counts
130722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette                             in the messages.
130822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        @param with_failures Whether the log message with a
130922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette                             failure count is expected.
131022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
131122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        """
131222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        count = len(self._offloader._open_jobs) - len(new_open_jobs)
131322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        logging.debug(mox.IgnoreArg(), count, len(new_open_jobs))
131422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        if with_failures:
131522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette            logging.debug(mox.IgnoreArg(), len(new_open_jobs))
131622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
131724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1318ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _run_update_no_report(self, new_open_jobs):
1319ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Call `_update_offload_results()` expecting no report.
1320ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1321ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are set up by the caller.  This calls
1322ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_update_offload_results()` once, and then checks these
1323ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        assertions:
1324ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The offloader's `_next_report_time` field is unchanged.
1325ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The offloader's new `_open_jobs` field contains only
1326ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            the entries in `new_open_jobs`.
1327ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The email_manager's `send_email` stub wasn't called.
1328ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1329ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param new_open_jobs A dictionary representing the expected
1330ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                             new value of the offloader's
1331ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                             `_open_jobs` field.
1332ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1333ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.ReplayAll()
1334ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        next_report_time = self._offloader._next_report_time
1335ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offloader._update_offload_results()
1336ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertEqual(next_report_time,
1337ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                         self._offloader._next_report_time)
1338ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertEqual(self._offloader._open_jobs, new_open_jobs)
1339ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.VerifyAll()
1340ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.ResetAll()
1341ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
134224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1343ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def _run_update_with_report(self, new_open_jobs):
1344ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Call `_update_offload_results()` expecting an e-mail report.
1345ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1346ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are set up by the caller.  This calls
1347ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_update_offload_results()` once, and then checks these
1348ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        assertions:
1349ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The offloader's `_next_report_time` field is updated
1350ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            to an appropriate new time.
1351ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The offloader's new `_open_jobs` field contains only
1352ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            the entries in `new_open_jobs`.
1353ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette          * The email_manager's `send_email` stub was called.
1354ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1355ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        @param new_open_jobs A dictionary representing the expected
1356ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                             new value of the offloader's
1357ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette                             `_open_jobs` field.
1358ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
135922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        logging.debug(mox.IgnoreArg())
1360ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        email_manager.manager.send_email(
1361ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg())
1362ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.ReplayAll()
1363ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        t0 = time.time() + gs_offloader.REPORT_INTERVAL_SECS
1364ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offloader._update_offload_results()
1365ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        t1 = time.time() + gs_offloader.REPORT_INTERVAL_SECS
1366ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        next_report_time = self._offloader._next_report_time
1367ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertGreaterEqual(next_report_time, t0)
1368ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertLessEqual(next_report_time, t1)
1369ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.assertEqual(self._offloader._open_jobs, new_open_jobs)
1370ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.VerifyAll()
1371ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self.mox.ResetAll()
1372ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
137324f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1374ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_no_jobs(self):
1375ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` with no open jobs.
1376ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1377ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an empty `_open_jobs` list and
1378ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_next_report_time` in the past.  Expected result is no
1379ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        e-mail report, and an empty `_open_jobs` list.
1380ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1381ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
138222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message({}, False)
1383ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._run_update_no_report({})
1384ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
138524f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1386ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_all_completed(self):
1387ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` with only complete jobs.
1388ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1389ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
1390ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only completed jobs and `_next_report_time` in the past.
1391ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Expected result is no e-mail report, and an empty
1392ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_open_jobs` list.
1393ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1394ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
13950880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
1396ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._add_job(d).set_complete()
139722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message({}, False)
1398ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._run_update_no_report({})
1399ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
140024f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1401ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_none_finished(self):
1402ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` with only unfinished jobs.
1403ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1404ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
1405ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only unfinished jobs and `_next_report_time` in the past.
1406ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Expected result is no e-mail report, and no change to the
1407ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_open_jobs` list.
1408ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1409ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
14100880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
1411ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._add_job(d)
141222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        new_jobs = self._offloader._open_jobs.copy()
141322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message(new_jobs, False)
141422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_update_no_report(new_jobs)
1415ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
141624f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1417ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_none_reportable(self):
1418ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` with only incomplete jobs.
1419ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1420ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
1421ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only incomplete jobs and `_next_report_time` in the past.
1422ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Expected result is no e-mail report, and no change to the
1423ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        `_open_jobs` list.
1424ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1425ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
14260880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
1427ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._add_job(d).set_incomplete()
142822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        new_jobs = self._offloader._open_jobs.copy()
142922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message(new_jobs, False)
143022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_update_no_report(new_jobs)
1431ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
143224f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1433ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_report_not_ready(self):
1434ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` e-mail throttling.
1435ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1436ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
1437ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only reportable jobs but with `_next_report_time` in
1438ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        the future.  Expected result is no e-mail report, and no
1439ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        change to the `_open_jobs` list.
1440ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1441ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
1442ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # N.B.  This test may fail if its run time exceeds more than
1443ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        # about _MARGIN_SECS seconds.
14440880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
1445ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._add_job(d).set_reportable()
1446ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        self._offloader._next_report_time += _MARGIN_SECS
144722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        new_jobs = self._offloader._open_jobs.copy()
144822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message(new_jobs, True)
144922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_update_no_report(new_jobs)
1450ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
145124f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
1452ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    def test_reportable(self):
1453ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """Test `_update_offload_results()` with reportable jobs.
1454ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1455ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
1456ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        only reportable jobs and with `_next_report_time` in
1457ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        the past.  Expected result is an e-mail report, and no
1458ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        change to the `_open_jobs` list.
1459ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1460ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette        """
14610880032b48fbcf11d50f33526f6817a78c2f17bfJ. Richard Barnette        for d in self.REGULAR_JOBLIST:
1462ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette            self._add_job(d).set_reportable()
146322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        new_jobs = self._offloader._open_jobs.copy()
146422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message(new_jobs, True)
146522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_update_with_report(new_jobs)
146622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
146724f22c2fda0fac684286b168f642c7326a20fac7Jakob Juelich
146822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette    def test_reportable_mixed(self):
146922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        """Test `_update_offload_results()` with a mixture of jobs.
147022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
147122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        Initial conditions are an `_open_jobs` list consisting of
147222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        one reportable jobs and the remainder of the jobs
147322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        incomplete.  The value of `_next_report_time` is in the
147422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        past.  Expected result is an e-mail report that includes
147522dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        both the reportable and the incomplete jobs, and no change
147622dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        to the `_open_jobs` list.
147722dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette
147822dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        """
147922dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._add_job(self.REGULAR_JOBLIST[0]).set_reportable()
148022dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        for d in self.REGULAR_JOBLIST[1:]:
148122dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette            self._add_job(d).set_incomplete()
148222dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        new_jobs = self._offloader._open_jobs.copy()
148322dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._expect_log_message(new_jobs, True)
148422dd7487fba60c457747b478ab0822df3a6e8c64J. Richard Barnette        self._run_update_with_report(new_jobs)
1485ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1486ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette
1487ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnetteif __name__ == '__main__':
1488ea785366f46ec4ed7a75d382e152a77aa51069d7J. Richard Barnette    unittest.main()
1489