blob: aa16660e83c63d23855ea2c7fedcbecead12ff58 [file] [log] [blame]
jamesrenc44ae992010-02-19 00:12:54 +00001#!/usr/bin/python
Dan Shi76af8022013-10-19 01:59:49 -07002#pylint: disable-msg=C0111
jamesrenc44ae992010-02-19 00:12:54 +00003
4import datetime
5import common
6from autotest_lib.frontend import setup_django_environment
7from autotest_lib.frontend.afe import frontend_test_utils
Fang Deng51599032014-06-23 17:24:27 -07008from autotest_lib.client.common_lib import host_queue_entry_states
jamesrenc44ae992010-02-19 00:12:54 +00009from autotest_lib.client.common_lib.test_utils import mock
10from autotest_lib.client.common_lib.test_utils import unittest
11from autotest_lib.database import database_connection
jamesrendd855242010-03-02 22:23:44 +000012from autotest_lib.frontend.afe import models, model_attributes
Dan Shi76af8022013-10-19 01:59:49 -070013from autotest_lib.scheduler import monitor_db
Prashanth B4ec98672014-05-15 10:44:54 -070014from autotest_lib.scheduler import scheduler_lib
jamesrenc44ae992010-02-19 00:12:54 +000015from autotest_lib.scheduler import scheduler_models
16
17_DEBUG = False
18
19
20class BaseSchedulerModelsTest(unittest.TestCase,
21 frontend_test_utils.FrontendTestMixin):
22 _config_section = 'AUTOTEST_WEB'
23
24 def _do_query(self, sql):
25 self._database.execute(sql)
26
27
28 def _set_monitor_stubs(self):
29 # Clear the instance cache as this is a brand new database.
30 scheduler_models.DBObject._clear_instance_cache()
31
32 self._database = (
33 database_connection.TranslatingDatabase.get_test_database(
Prashanth B4ec98672014-05-15 10:44:54 -070034 translators=scheduler_lib._DB_TRANSLATORS))
jamesrenc44ae992010-02-19 00:12:54 +000035 self._database.connect(db_type='django')
36 self._database.debug = _DEBUG
37
38 self.god.stub_with(scheduler_models, '_db', self._database)
39
40
41 def setUp(self):
42 self._frontend_common_setup()
43 self._set_monitor_stubs()
44
45
46 def tearDown(self):
47 self._database.disconnect()
48 self._frontend_common_teardown()
49
50
51 def _update_hqe(self, set, where=''):
52 query = 'UPDATE afe_host_queue_entries SET ' + set
53 if where:
54 query += ' WHERE ' + where
55 self._do_query(query)
56
57
58class DelayedCallTaskTest(unittest.TestCase):
59 def setUp(self):
60 self.god = mock.mock_god()
61
62
63 def tearDown(self):
64 self.god.unstub_all()
65
66
67 def test_delayed_call(self):
68 test_time = self.god.create_mock_function('time')
69 test_time.expect_call().and_return(33)
70 test_time.expect_call().and_return(34.01)
71 test_time.expect_call().and_return(34.99)
72 test_time.expect_call().and_return(35.01)
73 def test_callback():
74 test_callback.calls += 1
75 test_callback.calls = 0
76 delay_task = scheduler_models.DelayedCallTask(
77 delay_seconds=2, callback=test_callback,
78 now_func=test_time) # time 33
79 self.assertEqual(35, delay_task.end_time)
80 delay_task.poll() # activates the task and polls it once, time 34.01
81 self.assertEqual(0, test_callback.calls, "callback called early")
82 delay_task.poll() # time 34.99
83 self.assertEqual(0, test_callback.calls, "callback called early")
84 delay_task.poll() # time 35.01
85 self.assertEqual(1, test_callback.calls)
86 self.assert_(delay_task.is_done())
87 self.assert_(delay_task.success)
88 self.assert_(not delay_task.aborted)
89 self.god.check_playback()
90
91
92 def test_delayed_call_abort(self):
93 delay_task = scheduler_models.DelayedCallTask(
94 delay_seconds=987654, callback=lambda : None)
95 delay_task.abort()
96 self.assert_(delay_task.aborted)
97 self.assert_(delay_task.is_done())
98 self.assert_(not delay_task.success)
99 self.god.check_playback()
100
101
102class DBObjectTest(BaseSchedulerModelsTest):
103 def test_compare_fields_in_row(self):
104 host = scheduler_models.Host(id=1)
105 fields = list(host._fields)
106 row_data = [getattr(host, fieldname) for fieldname in fields]
107 self.assertEqual({}, host._compare_fields_in_row(row_data))
108 row_data[fields.index('hostname')] = 'spam'
109 self.assertEqual({'hostname': ('host1', 'spam')},
110 host._compare_fields_in_row(row_data))
111 row_data[fields.index('id')] = 23
112 self.assertEqual({'hostname': ('host1', 'spam'), 'id': (1, 23)},
113 host._compare_fields_in_row(row_data))
114
115
116 def test_compare_fields_in_row_datetime_ignores_microseconds(self):
117 datetime_with_us = datetime.datetime(2009, 10, 07, 12, 34, 56, 7890)
118 datetime_without_us = datetime.datetime(2009, 10, 07, 12, 34, 56, 0)
119 class TestTable(scheduler_models.DBObject):
120 _table_name = 'test_table'
121 _fields = ('id', 'test_datetime')
122 tt = TestTable(row=[1, datetime_without_us])
123 self.assertEqual({}, tt._compare_fields_in_row([1, datetime_with_us]))
124
125
126 def test_always_query(self):
127 host_a = scheduler_models.Host(id=2)
128 self.assertEqual(host_a.hostname, 'host2')
129 self._do_query('UPDATE afe_hosts SET hostname="host2-updated" '
130 'WHERE id=2')
131 host_b = scheduler_models.Host(id=2, always_query=True)
132 self.assert_(host_a is host_b, 'Cached instance not returned.')
133 self.assertEqual(host_a.hostname, 'host2-updated',
134 'Database was not re-queried')
135
136 # If either of these are called, a query was made when it shouldn't be.
137 host_a._compare_fields_in_row = lambda _: self.fail('eek! a query!')
138 host_a._update_fields_from_row = host_a._compare_fields_in_row
139 host_c = scheduler_models.Host(id=2, always_query=False)
140 self.assert_(host_a is host_c, 'Cached instance not returned')
141
142
143 def test_delete(self):
144 host = scheduler_models.Host(id=3)
145 host.delete()
146 host = self.assertRaises(scheduler_models.DBError, scheduler_models.Host, id=3,
147 always_query=False)
148 host = self.assertRaises(scheduler_models.DBError, scheduler_models.Host, id=3,
149 always_query=True)
150
151 def test_save(self):
152 # Dummy Job to avoid creating a one in the HostQueueEntry __init__.
153 class MockJob(object):
154 def __init__(self, id):
155 pass
156 def tag(self):
157 return 'MockJob'
158 self.god.stub_with(scheduler_models, 'Job', MockJob)
159 hqe = scheduler_models.HostQueueEntry(
160 new_record=True,
Fang Deng51599032014-06-23 17:24:27 -0700161 row=[0, 1, 2, 'Queued', None, 0, 0, 0, '.', None, False, None,
162 None])
jamesrenc44ae992010-02-19 00:12:54 +0000163 hqe.save()
164 new_id = hqe.id
165 # Force a re-query and verify that the correct data was stored.
166 scheduler_models.DBObject._clear_instance_cache()
167 hqe = scheduler_models.HostQueueEntry(id=new_id)
168 self.assertEqual(hqe.id, new_id)
169 self.assertEqual(hqe.job_id, 1)
170 self.assertEqual(hqe.host_id, 2)
171 self.assertEqual(hqe.status, 'Queued')
172 self.assertEqual(hqe.meta_host, None)
173 self.assertEqual(hqe.active, False)
174 self.assertEqual(hqe.complete, False)
175 self.assertEqual(hqe.deleted, False)
176 self.assertEqual(hqe.execution_subdir, '.')
177 self.assertEqual(hqe.atomic_group_id, None)
178 self.assertEqual(hqe.started_on, None)
Fang Deng51599032014-06-23 17:24:27 -0700179 self.assertEqual(hqe.finished_on, None)
jamesrenc44ae992010-02-19 00:12:54 +0000180
181
182class HostTest(BaseSchedulerModelsTest):
183 def test_cmp_for_sort(self):
184 expected_order = [
185 'alice', 'Host1', 'host2', 'host3', 'host09', 'HOST010',
186 'host10', 'host11', 'yolkfolk']
187 hostname_idx = list(scheduler_models.Host._fields).index('hostname')
188 row = [None] * len(scheduler_models.Host._fields)
189 hosts = []
190 for hostname in expected_order:
191 row[hostname_idx] = hostname
192 hosts.append(scheduler_models.Host(row=row, new_record=True))
193
194 host1 = hosts[expected_order.index('Host1')]
195 host010 = hosts[expected_order.index('HOST010')]
196 host10 = hosts[expected_order.index('host10')]
197 host3 = hosts[expected_order.index('host3')]
198 alice = hosts[expected_order.index('alice')]
199 self.assertEqual(0, scheduler_models.Host.cmp_for_sort(host10, host10))
200 self.assertEqual(1, scheduler_models.Host.cmp_for_sort(host10, host010))
201 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host010, host10))
202 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host1, host10))
203 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host1, host010))
204 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host3, host10))
205 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host3, host010))
206 self.assertEqual(1, scheduler_models.Host.cmp_for_sort(host3, host1))
207 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(host1, host3))
208 self.assertEqual(-1, scheduler_models.Host.cmp_for_sort(alice, host3))
209 self.assertEqual(1, scheduler_models.Host.cmp_for_sort(host3, alice))
210 self.assertEqual(0, scheduler_models.Host.cmp_for_sort(alice, alice))
211
212 hosts.sort(cmp=scheduler_models.Host.cmp_for_sort)
213 self.assertEqual(expected_order, [h.hostname for h in hosts])
214
215 hosts.reverse()
216 hosts.sort(cmp=scheduler_models.Host.cmp_for_sort)
217 self.assertEqual(expected_order, [h.hostname for h in hosts])
218
219
220class HostQueueEntryTest(BaseSchedulerModelsTest):
221 def _create_hqe(self, dependency_labels=(), **create_job_kwargs):
222 job = self._create_job(**create_job_kwargs)
223 for label in dependency_labels:
224 job.dependency_labels.add(label)
225 hqes = list(scheduler_models.HostQueueEntry.fetch(where='job_id=%d' % job.id))
226 self.assertEqual(1, len(hqes))
227 return hqes[0]
228
229
230 def _check_hqe_labels(self, hqe, expected_labels):
231 expected_labels = set(expected_labels)
232 label_names = set(label.name for label in hqe.get_labels())
233 self.assertEqual(expected_labels, label_names)
234
235
236 def test_get_labels_empty(self):
237 hqe = self._create_hqe(hosts=[1])
238 labels = list(hqe.get_labels())
239 self.assertEqual([], labels)
240
241
242 def test_get_labels_metahost(self):
243 hqe = self._create_hqe(metahosts=[2])
244 self._check_hqe_labels(hqe, ['label2'])
245
246
247 def test_get_labels_dependancies(self):
248 hqe = self._create_hqe(dependency_labels=(self.label3, self.label4),
249 metahosts=[1])
250 self._check_hqe_labels(hqe, ['label1', 'label3', 'label4'])
251
252
Dan Shi76af8022013-10-19 01:59:49 -0700253 def setup_abort_test(self, agent_finished=True):
254 """Setup the variables for testing abort method.
255
256 @param agent_finished: True to mock agent is finished before aborting
257 the hqe.
258 @return hqe, dispatcher: Mock object of hqe and dispatcher to be used
259 to test abort method.
260 """
261 hqe = self._create_hqe(hosts=[1])
262 hqe.aborted = True
263 hqe.complete = False
264 hqe.status = models.HostQueueEntry.Status.STARTING
265
266 dispatcher = self.god.create_mock_class(monitor_db.BaseDispatcher,
267 'BaseDispatcher')
268 agent = self.god.create_mock_class(monitor_db.Agent, 'Agent')
269 dispatcher.get_agents_for_entry.expect_call(hqe).and_return([agent])
270 agent.is_done.expect_call().and_return(agent_finished)
271 return hqe, dispatcher
272
273
274 def test_abort_fail_with_unfinished_agent(self):
275 """abort should fail if the hqe still has agent not finished.
276 """
277 hqe, dispatcher = self.setup_abort_test(agent_finished=False)
Fang Deng51599032014-06-23 17:24:27 -0700278 self.assertIsNone(hqe.finished_on)
Dan Shi76af8022013-10-19 01:59:49 -0700279 with self.assertRaises(AssertionError):
280 hqe.abort(dispatcher)
281 self.god.check_playback()
Fang Deng51599032014-06-23 17:24:27 -0700282 # abort failed, finished_on should not be set
283 self.assertIsNone(hqe.finished_on)
Dan Shi76af8022013-10-19 01:59:49 -0700284
285
286 def test_abort_success(self):
287 """abort should succeed if all agents for the hqe are finished.
288 """
289 hqe, dispatcher = self.setup_abort_test(agent_finished=True)
Fang Deng51599032014-06-23 17:24:27 -0700290 self.assertIsNone(hqe.finished_on)
Dan Shi76af8022013-10-19 01:59:49 -0700291 hqe.abort(dispatcher)
292 self.god.check_playback()
Fang Deng51599032014-06-23 17:24:27 -0700293 self.assertIsNotNone(hqe.finished_on)
294
295
296 def test_set_finished_on(self):
297 """Test that finished_on is set when hqe completes."""
298 for status in host_queue_entry_states.Status.values:
299 hqe = self._create_hqe(hosts=[1])
300 self.assertIsNone(hqe.finished_on)
301 hqe.set_status(status)
302 if status in host_queue_entry_states.COMPLETE_STATUSES:
303 self.assertIsNotNone(hqe.finished_on)
304 else:
305 self.assertIsNone(hqe.finished_on)
Dan Shi76af8022013-10-19 01:59:49 -0700306
307
jamesrenc44ae992010-02-19 00:12:54 +0000308class JobTest(BaseSchedulerModelsTest):
309 def setUp(self):
310 super(JobTest, self).setUp()
311
312 def _mock_create(**kwargs):
313 task = models.SpecialTask(**kwargs)
314 task.save()
Alex Miller16e4d6c2013-06-27 14:04:13 -0700315 self._tasks.append(task)
jamesrenc44ae992010-02-19 00:12:54 +0000316 self.god.stub_with(models.SpecialTask.objects, 'create', _mock_create)
317
318
Dan Shi07e09af2013-04-12 09:31:29 -0700319 def _test_pre_job_tasks_helper(self,
320 reboot_before=model_attributes.RebootBefore.ALWAYS):
jamesrenc44ae992010-02-19 00:12:54 +0000321 """
322 Calls HQE._do_schedule_pre_job_tasks() and returns the created special
323 task
324 """
Alex Miller16e4d6c2013-06-27 14:04:13 -0700325 self._tasks = []
jamesrenc44ae992010-02-19 00:12:54 +0000326 queue_entry = scheduler_models.HostQueueEntry.fetch('id = 1')[0]
Dan Shi07e09af2013-04-12 09:31:29 -0700327 queue_entry.job.reboot_before = reboot_before
jamesrenc44ae992010-02-19 00:12:54 +0000328 queue_entry._do_schedule_pre_job_tasks()
Alex Miller16e4d6c2013-06-27 14:04:13 -0700329 return self._tasks
jamesrenc44ae992010-02-19 00:12:54 +0000330
331
332 def test_job_request_abort(self):
333 django_job = self._create_job(hosts=[5, 6], atomic_group=1)
334 job = scheduler_models.Job(django_job.id)
335 job.request_abort()
336 django_hqes = list(models.HostQueueEntry.objects.filter(job=job.id))
337 for hqe in django_hqes:
338 self.assertTrue(hqe.aborted)
339
340
341 def test__atomic_and_has_started__on_atomic(self):
342 self._create_job(hosts=[5, 6], atomic_group=1)
343 job = scheduler_models.Job.fetch('id = 1')[0]
344 self.assertFalse(job._atomic_and_has_started())
345
346 self._update_hqe("status='Pending'")
347 self.assertFalse(job._atomic_and_has_started())
348 self._update_hqe("status='Verifying'")
349 self.assertFalse(job._atomic_and_has_started())
350 self.assertFalse(job._atomic_and_has_started())
351 self._update_hqe("status='Failed'")
352 self.assertFalse(job._atomic_and_has_started())
353 self._update_hqe("status='Stopped'")
354 self.assertFalse(job._atomic_and_has_started())
355
356 self._update_hqe("status='Starting'")
357 self.assertTrue(job._atomic_and_has_started())
358 self._update_hqe("status='Completed'")
359 self.assertTrue(job._atomic_and_has_started())
360 self._update_hqe("status='Aborted'")
361
362
363 def test__atomic_and_has_started__not_atomic(self):
364 self._create_job(hosts=[1, 2])
365 job = scheduler_models.Job.fetch('id = 1')[0]
366 self.assertFalse(job._atomic_and_has_started())
367 self._update_hqe("status='Starting'")
368 self.assertFalse(job._atomic_and_has_started())
369
370
Alex Miller16e4d6c2013-06-27 14:04:13 -0700371 def _check_special_tasks(self, tasks, task_types):
372 self.assertEquals(len(tasks), len(task_types))
373 for task, (task_type, queue_entry_id) in zip(tasks, task_types):
374 self.assertEquals(task.task, task_type)
375 self.assertEquals(task.host.id, 1)
376 if queue_entry_id:
377 self.assertEquals(task.queue_entry.id, queue_entry_id)
jamesrenc44ae992010-02-19 00:12:54 +0000378
379
380 def test_run_asynchronous(self):
381 self._create_job(hosts=[1, 2])
382
Alex Miller16e4d6c2013-06-27 14:04:13 -0700383 tasks = self._test_pre_job_tasks_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000384
Dan Shi07e09af2013-04-12 09:31:29 -0700385 self._check_special_tasks(tasks, [(models.SpecialTask.Task.RESET, 1)])
jamesrenc44ae992010-02-19 00:12:54 +0000386
387
388 def test_run_asynchronous_skip_verify(self):
389 job = self._create_job(hosts=[1, 2])
390 job.run_verify = False
391 job.save()
392
Alex Miller16e4d6c2013-06-27 14:04:13 -0700393 tasks = self._test_pre_job_tasks_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000394
Dan Shi07e09af2013-04-12 09:31:29 -0700395 self._check_special_tasks(tasks, [(models.SpecialTask.Task.RESET, 1)])
jamesrenc44ae992010-02-19 00:12:54 +0000396
397
398 def test_run_synchronous_verify(self):
399 self._create_job(hosts=[1, 2], synchronous=True)
400
Alex Miller16e4d6c2013-06-27 14:04:13 -0700401 tasks = self._test_pre_job_tasks_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000402
Dan Shi07e09af2013-04-12 09:31:29 -0700403 self._check_special_tasks(tasks, [(models.SpecialTask.Task.RESET, 1)])
jamesrenc44ae992010-02-19 00:12:54 +0000404
405
406 def test_run_synchronous_skip_verify(self):
407 job = self._create_job(hosts=[1, 2], synchronous=True)
408 job.run_verify = False
409 job.save()
410
Alex Miller16e4d6c2013-06-27 14:04:13 -0700411 tasks = self._test_pre_job_tasks_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000412
Dan Shi07e09af2013-04-12 09:31:29 -0700413 self._check_special_tasks(tasks, [(models.SpecialTask.Task.RESET, 1)])
414
415
416 def test_run_asynchronous_do_not_reset(self):
417 job = self._create_job(hosts=[1, 2])
418 job.run_reset = False
419 job.run_verify = False
420 job.save()
421
422 tasks = self._test_pre_job_tasks_helper()
423
Alex Miller16e4d6c2013-06-27 14:04:13 -0700424 self.assertEquals(tasks, [])
jamesrenc44ae992010-02-19 00:12:54 +0000425
426
Dan Shi07e09af2013-04-12 09:31:29 -0700427 def test_run_synchronous_do_not_reset_no_RebootBefore(self):
428 job = self._create_job(hosts=[1, 2], synchronous=True)
429 job.reboot_before = model_attributes.RebootBefore.NEVER
430 job.save()
431
432 tasks = self._test_pre_job_tasks_helper(
433 reboot_before=model_attributes.RebootBefore.NEVER)
434
Alex Miller6ee996f2013-02-28 13:53:52 -0800435 self._check_special_tasks(tasks, [(models.SpecialTask.Task.VERIFY, 1)])
Dan Shi07e09af2013-04-12 09:31:29 -0700436
437
438 def test_run_asynchronous_do_not_reset(self):
439 job = self._create_job(hosts=[1, 2], synchronous=False)
440 job.reboot_before = model_attributes.RebootBefore.NEVER
441 job.save()
442
443 tasks = self._test_pre_job_tasks_helper(
444 reboot_before=model_attributes.RebootBefore.NEVER)
445
Alex Miller6ee996f2013-02-28 13:53:52 -0800446 self._check_special_tasks(tasks, [(models.SpecialTask.Task.VERIFY, 1)])
Dan Shi07e09af2013-04-12 09:31:29 -0700447
448
jamesrenc44ae992010-02-19 00:12:54 +0000449 def test_run_atomic_group_already_started(self):
450 self._create_job(hosts=[5, 6], atomic_group=1, synchronous=True)
451 self._update_hqe("status='Starting', execution_subdir=''")
452
453 job = scheduler_models.Job.fetch('id = 1')[0]
454 queue_entry = scheduler_models.HostQueueEntry.fetch('id = 1')[0]
455 assert queue_entry.job is job
456 self.assertEqual(None, job.run(queue_entry))
457
458 self.god.check_playback()
459
460
461 def test_reboot_before_always(self):
462 job = self._create_job(hosts=[1])
jamesrendd855242010-03-02 22:23:44 +0000463 job.reboot_before = model_attributes.RebootBefore.ALWAYS
jamesrenc44ae992010-02-19 00:12:54 +0000464 job.save()
465
Alex Miller16e4d6c2013-06-27 14:04:13 -0700466 tasks = self._test_pre_job_tasks_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000467
Alex Miller16e4d6c2013-06-27 14:04:13 -0700468 self._check_special_tasks(tasks, [
Dan Shi07e09af2013-04-12 09:31:29 -0700469 (models.SpecialTask.Task.RESET, None)
Alex Miller16e4d6c2013-06-27 14:04:13 -0700470 ])
jamesrenc44ae992010-02-19 00:12:54 +0000471
472
Dan Shi07e09af2013-04-12 09:31:29 -0700473 def _test_reboot_before_if_dirty_helper(self):
jamesrenc44ae992010-02-19 00:12:54 +0000474 job = self._create_job(hosts=[1])
jamesrendd855242010-03-02 22:23:44 +0000475 job.reboot_before = model_attributes.RebootBefore.IF_DIRTY
jamesrenc44ae992010-02-19 00:12:54 +0000476 job.save()
477
Alex Miller16e4d6c2013-06-27 14:04:13 -0700478 tasks = self._test_pre_job_tasks_helper()
Dan Shi07e09af2013-04-12 09:31:29 -0700479 task_types = [(models.SpecialTask.Task.RESET, None)]
Alex Miller16e4d6c2013-06-27 14:04:13 -0700480
481 self._check_special_tasks(tasks, task_types)
jamesrenc44ae992010-02-19 00:12:54 +0000482
483
484 def test_reboot_before_if_dirty(self):
485 models.Host.smart_get(1).update_object(dirty=True)
Dan Shi07e09af2013-04-12 09:31:29 -0700486 self._test_reboot_before_if_dirty_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000487
488
489 def test_reboot_before_not_dirty(self):
490 models.Host.smart_get(1).update_object(dirty=False)
Dan Shi07e09af2013-04-12 09:31:29 -0700491 self._test_reboot_before_if_dirty_helper()
jamesrenc44ae992010-02-19 00:12:54 +0000492
493
494 def test_next_group_name(self):
495 django_job = self._create_job(metahosts=[1])
496 job = scheduler_models.Job(id=django_job.id)
497 self.assertEqual('group0', job._next_group_name())
498
499 for hqe in django_job.hostqueueentry_set.filter():
500 hqe.execution_subdir = 'my_rack.group0'
501 hqe.save()
502 self.assertEqual('my_rack.group1', job._next_group_name('my/rack'))
503
504
505if __name__ == '__main__':
506 unittest.main()