blob: 57467eef1f078fa1204f8856d4f93505333d6c9f [file] [log] [blame]
showarded2afea2009-07-07 20:54:07 +00001#!/usr/bin/python
Richard Barnette7983b632016-05-09 09:02:57 -07002# pylint: disable=C0111
showarded2afea2009-07-07 20:54:07 +00003
4import unittest
5import common
6from autotest_lib.frontend import setup_django_environment
7from autotest_lib.frontend.afe import frontend_test_utils
Richard Barnette7983b632016-05-09 09:02:57 -07008from autotest_lib.frontend.afe import models
jamesren4a41e012010-07-16 22:33:48 +00009from autotest_lib.client.common_lib import global_config
Aviv Keshet3dd8beb2013-05-13 17:36:04 -070010from autotest_lib.client.common_lib import control_data
showarded2afea2009-07-07 20:54:07 +000011
showarda5288b42009-07-28 20:06:08 +000012
13class AclGroupTest(unittest.TestCase,
14 frontend_test_utils.FrontendTestMixin):
15 def setUp(self):
16 self._frontend_common_setup()
17
18
19 def tearDown(self):
20 self._frontend_common_teardown()
21
22
23 def _check_acls(self, host, acl_name_list):
24 actual_acl_names = [acl_group.name for acl_group
25 in host.aclgroup_set.all()]
26 self.assertEquals(set(actual_acl_names), set(acl_name_list))
27
28
29 def test_on_host_membership_change(self):
30 host1, host2 = self.hosts[1:3]
31 everyone_acl = models.AclGroup.objects.get(name='Everyone')
32
33 host1.aclgroup_set.clear()
34 self._check_acls(host1, [])
35 host2.aclgroup_set.add(everyone_acl)
36 self._check_acls(host2, ['Everyone', 'my_acl'])
37
38 models.AclGroup.on_host_membership_change()
39
40 self._check_acls(host1, ['Everyone'])
41 self._check_acls(host2, ['my_acl'])
42
43
showardafd97de2009-10-01 18:45:09 +000044class HostTest(unittest.TestCase,
45 frontend_test_utils.FrontendTestMixin):
46 def setUp(self):
47 self._frontend_common_setup()
48
49
50 def tearDown(self):
51 self._frontend_common_teardown()
52
53
54 def test_add_host_previous_one_time_host(self):
55 # ensure that when adding a host which was previously used as a one-time
56 # host, the status isn't reset, since this can interfere with the
57 # scheduler.
58 host = models.Host.create_one_time_host('othost')
59 self.assertEquals(host.invalid, True)
60 self.assertEquals(host.status, models.Host.Status.READY)
61
62 host.status = models.Host.Status.RUNNING
63 host.save()
64
65 host2 = models.Host.add_object(hostname='othost')
66 self.assertEquals(host2.id, host.id)
67 self.assertEquals(host2.status, models.Host.Status.RUNNING)
68
69
showarded2afea2009-07-07 20:54:07 +000070class SpecialTaskUnittest(unittest.TestCase,
71 frontend_test_utils.FrontendTestMixin):
72 def setUp(self):
73 self._frontend_common_setup()
74
75
76 def tearDown(self):
77 self._frontend_common_teardown()
78
79
showardc0ac3a72009-07-08 21:14:45 +000080 def _create_task(self):
81 return models.SpecialTask.objects.create(
jamesren76fcf192010-04-21 20:39:50 +000082 host=self.hosts[0], task=models.SpecialTask.Task.VERIFY,
83 requested_by=models.User.current_user())
showarded2afea2009-07-07 20:54:07 +000084
showardc0ac3a72009-07-08 21:14:45 +000085
86 def test_execution_path(self):
87 task = self._create_task()
showarded2afea2009-07-07 20:54:07 +000088 self.assertEquals(task.execution_path(), 'hosts/host1/1-verify')
89
90
showardc0ac3a72009-07-08 21:14:45 +000091 def test_status(self):
92 task = self._create_task()
93 self.assertEquals(task.status, 'Queued')
94
95 task.update_object(is_active=True)
96 self.assertEquals(task.status, 'Running')
97
showarde60e44e2009-11-13 20:45:38 +000098 task.update_object(is_active=False, is_complete=True, success=True)
showardc0ac3a72009-07-08 21:14:45 +000099 self.assertEquals(task.status, 'Completed')
100
showarde60e44e2009-11-13 20:45:38 +0000101 task.update_object(success=False)
102 self.assertEquals(task.status, 'Failed')
103
showardc0ac3a72009-07-08 21:14:45 +0000104
showard97446882009-07-20 22:37:28 +0000105 def test_activate(self):
106 task = self._create_task()
107 task.activate()
108 self.assertTrue(task.is_active)
109 self.assertFalse(task.is_complete)
110
111
112 def test_finish(self):
113 task = self._create_task()
114 task.activate()
showarde60e44e2009-11-13 20:45:38 +0000115 task.finish(True)
showard97446882009-07-20 22:37:28 +0000116 self.assertFalse(task.is_active)
117 self.assertTrue(task.is_complete)
showarde60e44e2009-11-13 20:45:38 +0000118 self.assertTrue(task.success)
showard97446882009-07-20 22:37:28 +0000119
120
showard9bb960b2009-11-19 01:02:11 +0000121 def test_requested_by_from_queue_entry(self):
122 job = self._create_job(hosts=[0])
123 task = models.SpecialTask.objects.create(
124 host=self.hosts[0], task=models.SpecialTask.Task.VERIFY,
125 queue_entry=job.hostqueueentry_set.all()[0])
showardfd8b89f2010-01-20 19:06:30 +0000126 self.assertEquals(task.requested_by.login, 'autotest_system')
showard9bb960b2009-11-19 01:02:11 +0000127
128
showardd1195652009-12-08 22:21:02 +0000129class HostQueueEntryUnittest(unittest.TestCase,
130 frontend_test_utils.FrontendTestMixin):
131 def setUp(self):
132 self._frontend_common_setup()
133
134
135 def tearDown(self):
136 self._frontend_common_teardown()
137
138
139 def test_execution_path(self):
140 entry = self._create_job(hosts=[1]).hostqueueentry_set.all()[0]
141 entry.execution_subdir = 'subdir'
142 entry.save()
143
showardfd8b89f2010-01-20 19:06:30 +0000144 self.assertEquals(entry.execution_path(), '1-autotest_system/subdir')
showardd1195652009-12-08 22:21:02 +0000145
146
jamesrene3656232010-03-02 00:00:30 +0000147class ModelWithInvalidTest(unittest.TestCase,
148 frontend_test_utils.FrontendTestMixin):
149 def setUp(self):
150 self._frontend_common_setup()
151
152
153 def tearDown(self):
154 self._frontend_common_teardown()
155
156
157 def test_model_with_invalid_delete(self):
158 self.assertFalse(self.hosts[0].invalid)
159 self.hosts[0].delete()
160 self.assertTrue(self.hosts[0].invalid)
161 self.assertTrue(models.Host.objects.get(id=self.hosts[0].id))
162
163
164 def test_model_with_invalid_delete_queryset(self):
165 for host in self.hosts:
166 self.assertFalse(host.invalid)
167
168 hosts = models.Host.objects.all()
169 hosts.delete()
170 self.assertEqual(hosts.count(), len(self.hosts))
171
172 for host in hosts:
173 self.assertTrue(host.invalid)
174
175
176 def test_cloned_queryset_delete(self):
177 """
178 Make sure that a cloned queryset maintains the custom delete()
179 """
180 to_delete = ('host1', 'host2')
181
182 for host in self.hosts:
183 self.assertFalse(host.invalid)
184
185 hosts = models.Host.objects.all().filter(hostname__in=to_delete)
186 hosts.delete()
187 all_hosts = models.Host.objects.all()
188 self.assertEqual(all_hosts.count(), len(self.hosts))
189
190 for host in all_hosts:
191 if host.hostname in to_delete:
192 self.assertTrue(
193 host.invalid,
194 '%s.invalid expected to be True' % host.hostname)
195 else:
196 self.assertFalse(
197 host.invalid,
198 '%s.invalid expected to be False' % host.hostname)
199
200
201 def test_normal_delete(self):
202 job = self._create_job(hosts=[1])
203 self.assertEqual(1, models.Job.objects.all().count())
204
205 job.delete()
206 self.assertEqual(0, models.Job.objects.all().count())
207
208
209 def test_normal_delete_queryset(self):
210 self._create_job(hosts=[1])
211 self._create_job(hosts=[2])
212
213 self.assertEqual(2, models.Job.objects.all().count())
214
215 models.Job.objects.all().delete()
216 self.assertEqual(0, models.Job.objects.all().count())
217
218
jamesren4a41e012010-07-16 22:33:48 +0000219class ParameterizedJobTest(unittest.TestCase,
220 frontend_test_utils.FrontendTestMixin):
221 def setUp(self):
222 self._frontend_common_setup()
223
224
225 def tearDown(self):
226 self._frontend_common_teardown()
227
228
229 def test_job(self):
230 global_config.global_config.override_config_value(
231 'AUTOTEST_WEB', 'parameterized_jobs', 'True')
232
233 test = models.Test.objects.create(
234 name='name', author='author', test_class='class',
235 test_category='category',
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700236 test_type=control_data.CONTROL_TYPE.SERVER, path='path')
jamesren4a41e012010-07-16 22:33:48 +0000237 parameterized_job = models.ParameterizedJob.objects.create(test=test)
238 job = self._create_job(hosts=[1], control_file=None,
239 parameterized_job=parameterized_job)
240
241 self.assertEqual(job, parameterized_job.job())
242
243
244class JobTest(unittest.TestCase, frontend_test_utils.FrontendTestMixin):
245 def setUp(self):
246 self._frontend_common_setup()
247
248
249 def tearDown(self):
250 self._frontend_common_teardown()
251
252
253 def test_check_parameterized_jobs_no_args(self):
254 self.assertRaises(Exception, models.Job.check_parameterized_job,
255 control_file=None, parameterized_job=None)
256
257
258 def test_check_parameterized_jobs_both_args(self):
259 self.assertRaises(Exception, models.Job.check_parameterized_job,
260 control_file=object(), parameterized_job=object())
261
262
263 def test_check_parameterized_jobs_disabled(self):
264 self.assertRaises(Exception, models.Job.check_parameterized_job,
265 control_file=None, parameterized_job=object())
266
267
268 def test_check_parameterized_jobs_enabled(self):
269 global_config.global_config.override_config_value(
270 'AUTOTEST_WEB', 'parameterized_jobs', 'True')
271 self.assertRaises(Exception, models.Job.check_parameterized_job,
272 control_file=object(), parameterized_job=None)
273
274
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700275class SerializationTest(unittest.TestCase,
276 frontend_test_utils.FrontendTestMixin):
277 def setUp(self):
Jakob Juelichf88fa932014-09-03 17:58:04 -0700278 self._frontend_common_setup(fill_data=False)
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700279
280
281 def tearDown(self):
282 self._frontend_common_teardown()
283
284
Jakob Juelichf88fa932014-09-03 17:58:04 -0700285 def _get_example_response(self):
286 return {'hosts': [{'aclgroup_set': [{'description': '',
287 'id': 1,
288 'name': 'Everyone',
289 'users': [{
290 'access_level': 100,
291 'id': 1,
292 'login': 'autotest_system',
293 'reboot_after': 0,
294 'reboot_before': 1,
295 'show_experimental': False}]}],
296 'dirty': True,
297 'hostattribute_set': [],
298 'hostname': '100.107.2.163',
299 'id': 2,
300 'invalid': False,
301 'labels': [{'id': 7,
302 'invalid': False,
303 'kernel_config': '',
304 'name': 'power:battery',
305 'only_if_needed': False,
306 'platform': False},
307 {'id': 9,
308 'invalid': False,
309 'kernel_config': '',
310 'name': 'hw_video_acc_h264',
311 'only_if_needed': False,
312 'platform': False},
313 {'id': 10,
314 'invalid': False,
315 'kernel_config': '',
316 'name': 'hw_video_acc_enc_h264',
317 'only_if_needed': False,
318 'platform': False},
319 {'id': 11,
320 'invalid': False,
321 'kernel_config': '',
322 'name': 'webcam',
323 'only_if_needed': False,
324 'platform': False},
325 {'id': 12,
326 'invalid': False,
327 'kernel_config': '',
328 'name': 'touchpad',
329 'only_if_needed': False,
330 'platform': False},
331 {'id': 13,
332 'invalid': False,
333 'kernel_config': '',
334 'name': 'spring',
335 'only_if_needed': False,
336 'platform': False},
337 {'id': 14,
338 'invalid': False,
339 'kernel_config': '',
340 'name': 'board:daisy',
341 'only_if_needed': False,
342 'platform': True},
343 {'id': 15,
344 'invalid': False,
345 'kernel_config': '',
346 'name': 'board_freq_mem:daisy_1.7GHz',
347 'only_if_needed': False,
348 'platform': False},
349 {'id': 16,
350 'invalid': False,
351 'kernel_config': '',
352 'name': 'bluetooth',
353 'only_if_needed': False,
354 'platform': False},
355 {'id': 17,
356 'invalid': False,
357 'kernel_config': '',
358 'name': 'gpu_family:mali',
359 'only_if_needed': False,
360 'platform': False},
Jakob Juelichf88fa932014-09-03 17:58:04 -0700361 {'id': 19,
362 'invalid': False,
363 'kernel_config': '',
364 'name': 'ec:cros',
365 'only_if_needed': False,
366 'platform': False},
367 {'id': 20,
368 'invalid': False,
369 'kernel_config': '',
370 'name': 'storage:mmc',
371 'only_if_needed': False,
372 'platform': False},
373 {'id': 21,
374 'invalid': False,
375 'kernel_config': '',
376 'name': 'hw_video_acc_vp8',
377 'only_if_needed': False,
378 'platform': False},
379 {'id': 22,
380 'invalid': False,
381 'kernel_config': '',
382 'name': 'video_glitch_detection',
383 'only_if_needed': False,
384 'platform': False},
385 {'id': 23,
386 'invalid': False,
387 'kernel_config': '',
388 'name': 'pool:suites',
389 'only_if_needed': False,
390 'platform': False},
391 {'id': 25,
392 'invalid': False,
393 'kernel_config': '',
394 'name': 'daisy-board-name',
395 'only_if_needed': False,
396 'platform': False}],
397 'leased': False,
Matthew Sartori68186332015-04-27 17:19:53 -0700398 'lock_reason': '',
Jakob Juelichf88fa932014-09-03 17:58:04 -0700399 'lock_time': None,
400 'locked': False,
401 'protection': 0,
402 'shard': {'hostname': '1', 'id': 1},
403 'status': 'Ready',
404 'synch_id': None}],
405 'jobs': [{'control_file': 'some control file\n\n\n',
406 'control_type': 2,
407 'created_on': '2014-09-04T13:09:35',
408 'dependency_labels': [{'id': 14,
409 'invalid': False,
410 'kernel_config': '',
411 'name': 'board:daisy',
412 'only_if_needed': False,
413 'platform': True},
414 {'id': 23,
415 'invalid': False,
416 'kernel_config': '',
417 'name': 'pool:suites',
418 'only_if_needed': False,
419 'platform': False},
420 {'id': 25,
421 'invalid': False,
422 'kernel_config': '',
423 'name': 'daisy-board-name',
424 'only_if_needed': False,
425 'platform': False}],
426 'email_list': '',
427 'hostqueueentry_set': [{'aborted': False,
428 'active': False,
429 'complete': False,
430 'deleted': False,
431 'execution_subdir': '',
432 'finished_on': None,
433 'id': 5,
434 'meta_host': {
435 'id': 14,
436 'invalid': False,
437 'kernel_config': '',
438 'name': 'board:daisy',
439 'only_if_needed': False,
440 'platform': True},
Prashanth Balasubramanian8c98ac12014-12-23 11:26:44 -0800441 'host_id': None,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700442 'started_on': None,
443 'status': 'Queued'}],
444 'id': 5,
445 'jobkeyval_set': [{'id': 10,
Fang Dengff361592015-02-02 15:27:34 -0800446 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700447 'key': 'suite',
448 'value': 'dummy'},
449 {'id': 11,
Fang Dengff361592015-02-02 15:27:34 -0800450 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700451 'key': 'build',
452 'value': 'daisy-release'},
453 {'id': 12,
Fang Dengff361592015-02-02 15:27:34 -0800454 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700455 'key': 'experimental',
456 'value': 'False'}],
457 'max_runtime_hrs': 72,
458 'max_runtime_mins': 1440,
459 'name': 'daisy-experimental',
460 'owner': 'autotest',
461 'parse_failed_repair': True,
462 'priority': 40,
463 'reboot_after': 0,
464 'reboot_before': 1,
465 'run_reset': True,
466 'run_verify': False,
467 'shard': {'hostname': '1', 'id': 1},
468 'synch_count': 1,
469 'test_retry': 0,
470 'timeout': 24,
Dan Shic9e17142015-02-19 11:50:55 -0800471 'timeout_mins': 1440,
472 'require_ssp': None},
Jakob Juelichf88fa932014-09-03 17:58:04 -0700473 {'control_file': 'some control file\n\n\n',
474 'control_type': 2,
475 'created_on': '2014-09-04T13:09:35',
476 'dependency_labels': [{'id': 14,
477 'invalid': False,
478 'kernel_config': '',
479 'name': 'board:daisy',
480 'only_if_needed': False,
481 'platform': True},
482 {'id': 23,
483 'invalid': False,
484 'kernel_config': '',
485 'name': 'pool:suites',
486 'only_if_needed': False,
487 'platform': False},
488 {'id': 25,
489 'invalid': False,
490 'kernel_config': '',
491 'name': 'daisy-board-name',
492 'only_if_needed': False,
493 'platform': False}],
494 'email_list': '',
495 'hostqueueentry_set': [{'aborted': False,
496 'active': False,
497 'complete': False,
498 'deleted': False,
499 'execution_subdir': '',
500 'finished_on': None,
501 'id': 7,
502 'meta_host': {
503 'id': 14,
504 'invalid': False,
505 'kernel_config': '',
506 'name': 'board:daisy',
507 'only_if_needed': False,
508 'platform': True},
Prashanth Balasubramanian8c98ac12014-12-23 11:26:44 -0800509 'host_id': None,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700510 'started_on': None,
511 'status': 'Queued'}],
512 'id': 7,
513 'jobkeyval_set': [{'id': 16,
Fang Dengff361592015-02-02 15:27:34 -0800514 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700515 'key': 'suite',
516 'value': 'dummy'},
517 {'id': 17,
Fang Dengff361592015-02-02 15:27:34 -0800518 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700519 'key': 'build',
520 'value': 'daisy-release'},
521 {'id': 18,
Fang Dengff361592015-02-02 15:27:34 -0800522 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700523 'key': 'experimental',
524 'value': 'False'}],
525 'max_runtime_hrs': 72,
526 'max_runtime_mins': 1440,
527 'name': 'daisy-experimental',
528 'owner': 'autotest',
529 'parse_failed_repair': True,
530 'priority': 40,
531 'reboot_after': 0,
532 'reboot_before': 1,
533 'run_reset': True,
534 'run_verify': False,
535 'shard': {'hostname': '1', 'id': 1},
536 'synch_count': 1,
537 'test_retry': 0,
538 'timeout': 24,
Dan Shic9e17142015-02-19 11:50:55 -0800539 'timeout_mins': 1440,
540 'require_ssp': None}]}
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700541
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700542
Jakob Juelichf88fa932014-09-03 17:58:04 -0700543 def test_response(self):
544 heartbeat_response = self._get_example_response()
545 hosts_serialized = heartbeat_response['hosts']
546 jobs_serialized = heartbeat_response['jobs']
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700547
Jakob Juelichf88fa932014-09-03 17:58:04 -0700548 # Persisting is automatically done inside deserialize
549 hosts = [models.Host.deserialize(host) for host in hosts_serialized]
550 jobs = [models.Job.deserialize(job) for job in jobs_serialized]
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700551
Jakob Juelichf88fa932014-09-03 17:58:04 -0700552 generated_heartbeat_response = {
553 'hosts': [host.serialize() for host in hosts],
554 'jobs': [job.serialize() for job in jobs]
555 }
Fang Dengff361592015-02-02 15:27:34 -0800556 example_response = self._get_example_response()
557 # For attribute-like objects, we don't care about its id.
558 for r in [generated_heartbeat_response, example_response]:
559 for job in r['jobs']:
560 for keyval in job['jobkeyval_set']:
561 keyval.pop('id')
562 for host in r['hosts']:
563 for attribute in host['hostattribute_set']:
564 keyval.pop('id')
565 self.assertEqual(generated_heartbeat_response, example_response)
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700566
567
Jakob Juelich116ff0f2014-09-17 18:25:16 -0700568 def test_update(self):
569 job = self._create_job(hosts=[1])
570 serialized = job.serialize(include_dependencies=False)
571 serialized['owner'] = 'some_other_owner'
572
573 job.update_from_serialized(serialized)
574 self.assertEqual(job.owner, 'some_other_owner')
575
576 serialized = job.serialize()
577 self.assertRaises(
578 ValueError,
579 job.update_from_serialized, serialized)
580
581
Jakob Juelichf865d332014-09-29 10:47:49 -0700582 def test_sync_aborted(self):
583 job = self._create_job(hosts=[1])
584 serialized = job.serialize()
585
586 serialized['hostqueueentry_set'][0]['aborted'] = True
587 serialized['hostqueueentry_set'][0]['status'] = 'Running'
588
589 models.Job.deserialize(serialized)
590
591 job = models.Job.objects.get(pk=job.id)
592 self.assertTrue(job.hostqueueentry_set.all()[0].aborted)
593 self.assertEqual(job.hostqueueentry_set.all()[0].status, 'Queued')
Jakob Juelich116ff0f2014-09-17 18:25:16 -0700594
595
showarded2afea2009-07-07 20:54:07 +0000596if __name__ == '__main__':
597 unittest.main()