blob: c404fdedf4ec6e6a6853155ea5592cbde5f55517 [file] [log] [blame]
showarded2afea2009-07-07 20:54:07 +00001#!/usr/bin/python
2
Shuqian Zhao54a5b672016-05-11 22:12:17 +00003import datetime
showarded2afea2009-07-07 20:54:07 +00004import unittest
5import common
6from autotest_lib.frontend import setup_django_environment
7from autotest_lib.frontend.afe import frontend_test_utils
Shuqian Zhao54a5b672016-05-11 22:12:17 +00008from autotest_lib.frontend.afe import models, model_attributes, model_logic
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
Shuqian Zhao40e182b2016-10-11 11:55:11 -070070 def test_check_no_board(self):
71 host = models.Host.create_one_time_host('othost')
72 # First check with host with no board label.
73 self.assertEqual(host.check_no_board([host]), None)
74
75 # Second check with host with board label
76 label = models.Label.add_object(name='board:test')
77 label.host_set.add(host)
78 self.assertRaises(model_logic.ValidationError,
79 host.check_no_board, [host])
80
81
showarded2afea2009-07-07 20:54:07 +000082class SpecialTaskUnittest(unittest.TestCase,
83 frontend_test_utils.FrontendTestMixin):
84 def setUp(self):
85 self._frontend_common_setup()
86
87
88 def tearDown(self):
89 self._frontend_common_teardown()
90
91
showardc0ac3a72009-07-08 21:14:45 +000092 def _create_task(self):
93 return models.SpecialTask.objects.create(
jamesren76fcf192010-04-21 20:39:50 +000094 host=self.hosts[0], task=models.SpecialTask.Task.VERIFY,
95 requested_by=models.User.current_user())
showarded2afea2009-07-07 20:54:07 +000096
showardc0ac3a72009-07-08 21:14:45 +000097
98 def test_execution_path(self):
99 task = self._create_task()
showarded2afea2009-07-07 20:54:07 +0000100 self.assertEquals(task.execution_path(), 'hosts/host1/1-verify')
101
102
showardc0ac3a72009-07-08 21:14:45 +0000103 def test_status(self):
104 task = self._create_task()
105 self.assertEquals(task.status, 'Queued')
106
107 task.update_object(is_active=True)
108 self.assertEquals(task.status, 'Running')
109
showarde60e44e2009-11-13 20:45:38 +0000110 task.update_object(is_active=False, is_complete=True, success=True)
showardc0ac3a72009-07-08 21:14:45 +0000111 self.assertEquals(task.status, 'Completed')
112
showarde60e44e2009-11-13 20:45:38 +0000113 task.update_object(success=False)
114 self.assertEquals(task.status, 'Failed')
115
showardc0ac3a72009-07-08 21:14:45 +0000116
showard97446882009-07-20 22:37:28 +0000117 def test_activate(self):
118 task = self._create_task()
119 task.activate()
120 self.assertTrue(task.is_active)
121 self.assertFalse(task.is_complete)
122
123
124 def test_finish(self):
125 task = self._create_task()
126 task.activate()
showarde60e44e2009-11-13 20:45:38 +0000127 task.finish(True)
showard97446882009-07-20 22:37:28 +0000128 self.assertFalse(task.is_active)
129 self.assertTrue(task.is_complete)
showarde60e44e2009-11-13 20:45:38 +0000130 self.assertTrue(task.success)
showard97446882009-07-20 22:37:28 +0000131
132
showard9bb960b2009-11-19 01:02:11 +0000133 def test_requested_by_from_queue_entry(self):
134 job = self._create_job(hosts=[0])
135 task = models.SpecialTask.objects.create(
136 host=self.hosts[0], task=models.SpecialTask.Task.VERIFY,
137 queue_entry=job.hostqueueentry_set.all()[0])
showardfd8b89f2010-01-20 19:06:30 +0000138 self.assertEquals(task.requested_by.login, 'autotest_system')
showard9bb960b2009-11-19 01:02:11 +0000139
140
showardd1195652009-12-08 22:21:02 +0000141class HostQueueEntryUnittest(unittest.TestCase,
142 frontend_test_utils.FrontendTestMixin):
143 def setUp(self):
144 self._frontend_common_setup()
145
146
147 def tearDown(self):
148 self._frontend_common_teardown()
149
150
151 def test_execution_path(self):
152 entry = self._create_job(hosts=[1]).hostqueueentry_set.all()[0]
153 entry.execution_subdir = 'subdir'
154 entry.save()
155
showardfd8b89f2010-01-20 19:06:30 +0000156 self.assertEquals(entry.execution_path(), '1-autotest_system/subdir')
showardd1195652009-12-08 22:21:02 +0000157
158
jamesrene3656232010-03-02 00:00:30 +0000159class ModelWithInvalidTest(unittest.TestCase,
160 frontend_test_utils.FrontendTestMixin):
161 def setUp(self):
162 self._frontend_common_setup()
163
164
165 def tearDown(self):
166 self._frontend_common_teardown()
167
168
169 def test_model_with_invalid_delete(self):
170 self.assertFalse(self.hosts[0].invalid)
171 self.hosts[0].delete()
172 self.assertTrue(self.hosts[0].invalid)
173 self.assertTrue(models.Host.objects.get(id=self.hosts[0].id))
174
175
176 def test_model_with_invalid_delete_queryset(self):
177 for host in self.hosts:
178 self.assertFalse(host.invalid)
179
180 hosts = models.Host.objects.all()
181 hosts.delete()
182 self.assertEqual(hosts.count(), len(self.hosts))
183
184 for host in hosts:
185 self.assertTrue(host.invalid)
186
187
188 def test_cloned_queryset_delete(self):
189 """
190 Make sure that a cloned queryset maintains the custom delete()
191 """
192 to_delete = ('host1', 'host2')
193
194 for host in self.hosts:
195 self.assertFalse(host.invalid)
196
197 hosts = models.Host.objects.all().filter(hostname__in=to_delete)
198 hosts.delete()
199 all_hosts = models.Host.objects.all()
200 self.assertEqual(all_hosts.count(), len(self.hosts))
201
202 for host in all_hosts:
203 if host.hostname in to_delete:
204 self.assertTrue(
205 host.invalid,
206 '%s.invalid expected to be True' % host.hostname)
207 else:
208 self.assertFalse(
209 host.invalid,
210 '%s.invalid expected to be False' % host.hostname)
211
212
213 def test_normal_delete(self):
214 job = self._create_job(hosts=[1])
215 self.assertEqual(1, models.Job.objects.all().count())
216
217 job.delete()
218 self.assertEqual(0, models.Job.objects.all().count())
219
220
221 def test_normal_delete_queryset(self):
222 self._create_job(hosts=[1])
223 self._create_job(hosts=[2])
224
225 self.assertEqual(2, models.Job.objects.all().count())
226
227 models.Job.objects.all().delete()
228 self.assertEqual(0, models.Job.objects.all().count())
229
230
Shuqian Zhao54a5b672016-05-11 22:12:17 +0000231class KernelTest(unittest.TestCase, frontend_test_utils.FrontendTestMixin):
232 def setUp(self):
233 self._frontend_common_setup()
234
235
236 def tearDown(self):
237 self._frontend_common_teardown()
238
239
240 def test_create_kernels_none(self):
241 self.assertEqual(None, models.Kernel.create_kernels(None))
242
243
244 def test_create_kernels(self):
245 self.god.stub_function(models.Kernel, '_create')
246
247 num_kernels = 3
248 kernel_list = [object() for _ in range(num_kernels)]
249 result = [object() for _ in range(num_kernels)]
250
251 for kernel, response in zip(kernel_list, result):
252 models.Kernel._create.expect_call(kernel).and_return(response)
253 self.assertEqual(result, models.Kernel.create_kernels(kernel_list))
254 self.god.check_playback()
255
256
257 def test_create(self):
258 kernel = models.Kernel._create({'version': 'version'})
259 self.assertEqual(kernel.version, 'version')
260 self.assertEqual(kernel.cmdline, '')
261 self.assertEqual(kernel, models.Kernel._create({'version': 'version'}))
262
263
jamesren4a41e012010-07-16 22:33:48 +0000264class ParameterizedJobTest(unittest.TestCase,
265 frontend_test_utils.FrontendTestMixin):
266 def setUp(self):
267 self._frontend_common_setup()
268
269
270 def tearDown(self):
271 self._frontend_common_teardown()
272
273
274 def test_job(self):
275 global_config.global_config.override_config_value(
276 'AUTOTEST_WEB', 'parameterized_jobs', 'True')
277
278 test = models.Test.objects.create(
279 name='name', author='author', test_class='class',
280 test_category='category',
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700281 test_type=control_data.CONTROL_TYPE.SERVER, path='path')
jamesren4a41e012010-07-16 22:33:48 +0000282 parameterized_job = models.ParameterizedJob.objects.create(test=test)
283 job = self._create_job(hosts=[1], control_file=None,
284 parameterized_job=parameterized_job)
285
286 self.assertEqual(job, parameterized_job.job())
287
288
289class JobTest(unittest.TestCase, frontend_test_utils.FrontendTestMixin):
290 def setUp(self):
291 self._frontend_common_setup()
292
293
294 def tearDown(self):
295 self._frontend_common_teardown()
296
297
298 def test_check_parameterized_jobs_no_args(self):
299 self.assertRaises(Exception, models.Job.check_parameterized_job,
300 control_file=None, parameterized_job=None)
301
302
303 def test_check_parameterized_jobs_both_args(self):
304 self.assertRaises(Exception, models.Job.check_parameterized_job,
305 control_file=object(), parameterized_job=object())
306
307
308 def test_check_parameterized_jobs_disabled(self):
309 self.assertRaises(Exception, models.Job.check_parameterized_job,
310 control_file=None, parameterized_job=object())
311
312
313 def test_check_parameterized_jobs_enabled(self):
314 global_config.global_config.override_config_value(
315 'AUTOTEST_WEB', 'parameterized_jobs', 'True')
316 self.assertRaises(Exception, models.Job.check_parameterized_job,
317 control_file=object(), parameterized_job=None)
318
319
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700320class SerializationTest(unittest.TestCase,
321 frontend_test_utils.FrontendTestMixin):
322 def setUp(self):
Jakob Juelichf88fa932014-09-03 17:58:04 -0700323 self._frontend_common_setup(fill_data=False)
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700324
325
326 def tearDown(self):
327 self._frontend_common_teardown()
328
329
Jakob Juelichf88fa932014-09-03 17:58:04 -0700330 def _get_example_response(self):
331 return {'hosts': [{'aclgroup_set': [{'description': '',
332 'id': 1,
333 'name': 'Everyone',
334 'users': [{
335 'access_level': 100,
336 'id': 1,
337 'login': 'autotest_system',
338 'reboot_after': 0,
339 'reboot_before': 1,
340 'show_experimental': False}]}],
341 'dirty': True,
342 'hostattribute_set': [],
343 'hostname': '100.107.2.163',
344 'id': 2,
345 'invalid': False,
346 'labels': [{'id': 7,
347 'invalid': False,
348 'kernel_config': '',
349 'name': 'power:battery',
350 'only_if_needed': False,
351 'platform': False},
352 {'id': 9,
353 'invalid': False,
354 'kernel_config': '',
355 'name': 'hw_video_acc_h264',
356 'only_if_needed': False,
357 'platform': False},
358 {'id': 10,
359 'invalid': False,
360 'kernel_config': '',
361 'name': 'hw_video_acc_enc_h264',
362 'only_if_needed': False,
363 'platform': False},
364 {'id': 11,
365 'invalid': False,
366 'kernel_config': '',
367 'name': 'webcam',
368 'only_if_needed': False,
369 'platform': False},
370 {'id': 12,
371 'invalid': False,
372 'kernel_config': '',
373 'name': 'touchpad',
374 'only_if_needed': False,
375 'platform': False},
376 {'id': 13,
377 'invalid': False,
378 'kernel_config': '',
379 'name': 'spring',
380 'only_if_needed': False,
381 'platform': False},
382 {'id': 14,
383 'invalid': False,
384 'kernel_config': '',
385 'name': 'board:daisy',
386 'only_if_needed': False,
387 'platform': True},
388 {'id': 15,
389 'invalid': False,
390 'kernel_config': '',
391 'name': 'board_freq_mem:daisy_1.7GHz',
392 'only_if_needed': False,
393 'platform': False},
394 {'id': 16,
395 'invalid': False,
396 'kernel_config': '',
397 'name': 'bluetooth',
398 'only_if_needed': False,
399 'platform': False},
400 {'id': 17,
401 'invalid': False,
402 'kernel_config': '',
403 'name': 'gpu_family:mali',
404 'only_if_needed': False,
405 'platform': False},
Jakob Juelichf88fa932014-09-03 17:58:04 -0700406 {'id': 19,
407 'invalid': False,
408 'kernel_config': '',
409 'name': 'ec:cros',
410 'only_if_needed': False,
411 'platform': False},
412 {'id': 20,
413 'invalid': False,
414 'kernel_config': '',
415 'name': 'storage:mmc',
416 'only_if_needed': False,
417 'platform': False},
418 {'id': 21,
419 'invalid': False,
420 'kernel_config': '',
421 'name': 'hw_video_acc_vp8',
422 'only_if_needed': False,
423 'platform': False},
424 {'id': 22,
425 'invalid': False,
426 'kernel_config': '',
427 'name': 'video_glitch_detection',
428 'only_if_needed': False,
429 'platform': False},
430 {'id': 23,
431 'invalid': False,
432 'kernel_config': '',
433 'name': 'pool:suites',
434 'only_if_needed': False,
435 'platform': False},
436 {'id': 25,
437 'invalid': False,
438 'kernel_config': '',
439 'name': 'daisy-board-name',
440 'only_if_needed': False,
441 'platform': False}],
442 'leased': False,
Matthew Sartori68186332015-04-27 17:19:53 -0700443 'lock_reason': '',
Jakob Juelichf88fa932014-09-03 17:58:04 -0700444 'lock_time': None,
445 'locked': False,
446 'protection': 0,
447 'shard': {'hostname': '1', 'id': 1},
448 'status': 'Ready',
449 'synch_id': None}],
450 'jobs': [{'control_file': 'some control file\n\n\n',
451 'control_type': 2,
452 'created_on': '2014-09-04T13:09:35',
453 'dependency_labels': [{'id': 14,
454 'invalid': False,
455 'kernel_config': '',
456 'name': 'board:daisy',
457 'only_if_needed': False,
458 'platform': True},
459 {'id': 23,
460 'invalid': False,
461 'kernel_config': '',
462 'name': 'pool:suites',
463 'only_if_needed': False,
464 'platform': False},
465 {'id': 25,
466 'invalid': False,
467 'kernel_config': '',
468 'name': 'daisy-board-name',
469 'only_if_needed': False,
470 'platform': False}],
471 'email_list': '',
472 'hostqueueentry_set': [{'aborted': False,
473 'active': False,
474 'complete': False,
475 'deleted': False,
476 'execution_subdir': '',
477 'finished_on': None,
478 'id': 5,
479 'meta_host': {
480 'id': 14,
481 'invalid': False,
482 'kernel_config': '',
483 'name': 'board:daisy',
484 'only_if_needed': False,
485 'platform': True},
Prashanth Balasubramanian8c98ac12014-12-23 11:26:44 -0800486 'host_id': None,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700487 'started_on': None,
488 'status': 'Queued'}],
489 'id': 5,
490 'jobkeyval_set': [{'id': 10,
Fang Dengff361592015-02-02 15:27:34 -0800491 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700492 'key': 'suite',
493 'value': 'dummy'},
494 {'id': 11,
Fang Dengff361592015-02-02 15:27:34 -0800495 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700496 'key': 'build',
497 'value': 'daisy-release'},
498 {'id': 12,
Fang Dengff361592015-02-02 15:27:34 -0800499 'job_id': 5,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700500 'key': 'experimental',
501 'value': 'False'}],
502 'max_runtime_hrs': 72,
503 'max_runtime_mins': 1440,
504 'name': 'daisy-experimental',
505 'owner': 'autotest',
506 'parse_failed_repair': True,
507 'priority': 40,
508 'reboot_after': 0,
509 'reboot_before': 1,
510 'run_reset': True,
511 'run_verify': False,
512 'shard': {'hostname': '1', 'id': 1},
513 'synch_count': 1,
514 'test_retry': 0,
515 'timeout': 24,
Dan Shic9e17142015-02-19 11:50:55 -0800516 'timeout_mins': 1440,
517 'require_ssp': None},
Jakob Juelichf88fa932014-09-03 17:58:04 -0700518 {'control_file': 'some control file\n\n\n',
519 'control_type': 2,
520 'created_on': '2014-09-04T13:09:35',
521 'dependency_labels': [{'id': 14,
522 'invalid': False,
523 'kernel_config': '',
524 'name': 'board:daisy',
525 'only_if_needed': False,
526 'platform': True},
527 {'id': 23,
528 'invalid': False,
529 'kernel_config': '',
530 'name': 'pool:suites',
531 'only_if_needed': False,
532 'platform': False},
533 {'id': 25,
534 'invalid': False,
535 'kernel_config': '',
536 'name': 'daisy-board-name',
537 'only_if_needed': False,
538 'platform': False}],
539 'email_list': '',
540 'hostqueueentry_set': [{'aborted': False,
541 'active': False,
542 'complete': False,
543 'deleted': False,
544 'execution_subdir': '',
545 'finished_on': None,
546 'id': 7,
547 'meta_host': {
548 'id': 14,
549 'invalid': False,
550 'kernel_config': '',
551 'name': 'board:daisy',
552 'only_if_needed': False,
553 'platform': True},
Prashanth Balasubramanian8c98ac12014-12-23 11:26:44 -0800554 'host_id': None,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700555 'started_on': None,
556 'status': 'Queued'}],
557 'id': 7,
558 'jobkeyval_set': [{'id': 16,
Fang Dengff361592015-02-02 15:27:34 -0800559 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700560 'key': 'suite',
561 'value': 'dummy'},
562 {'id': 17,
Fang Dengff361592015-02-02 15:27:34 -0800563 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700564 'key': 'build',
565 'value': 'daisy-release'},
566 {'id': 18,
Fang Dengff361592015-02-02 15:27:34 -0800567 'job_id': 7,
Jakob Juelichf88fa932014-09-03 17:58:04 -0700568 'key': 'experimental',
569 'value': 'False'}],
570 'max_runtime_hrs': 72,
571 'max_runtime_mins': 1440,
572 'name': 'daisy-experimental',
573 'owner': 'autotest',
574 'parse_failed_repair': True,
575 'priority': 40,
576 'reboot_after': 0,
577 'reboot_before': 1,
578 'run_reset': True,
579 'run_verify': False,
580 'shard': {'hostname': '1', 'id': 1},
581 'synch_count': 1,
582 'test_retry': 0,
583 'timeout': 24,
Dan Shic9e17142015-02-19 11:50:55 -0800584 'timeout_mins': 1440,
585 'require_ssp': None}]}
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700586
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700587
Jakob Juelichf88fa932014-09-03 17:58:04 -0700588 def test_response(self):
589 heartbeat_response = self._get_example_response()
590 hosts_serialized = heartbeat_response['hosts']
591 jobs_serialized = heartbeat_response['jobs']
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700592
Jakob Juelichf88fa932014-09-03 17:58:04 -0700593 # Persisting is automatically done inside deserialize
594 hosts = [models.Host.deserialize(host) for host in hosts_serialized]
595 jobs = [models.Job.deserialize(job) for job in jobs_serialized]
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700596
Jakob Juelichf88fa932014-09-03 17:58:04 -0700597 generated_heartbeat_response = {
598 'hosts': [host.serialize() for host in hosts],
599 'jobs': [job.serialize() for job in jobs]
600 }
Fang Dengff361592015-02-02 15:27:34 -0800601 example_response = self._get_example_response()
602 # For attribute-like objects, we don't care about its id.
603 for r in [generated_heartbeat_response, example_response]:
604 for job in r['jobs']:
605 for keyval in job['jobkeyval_set']:
606 keyval.pop('id')
607 for host in r['hosts']:
608 for attribute in host['hostattribute_set']:
609 keyval.pop('id')
610 self.assertEqual(generated_heartbeat_response, example_response)
Jakob Juelich3bb7c802014-09-02 16:31:11 -0700611
612
Jakob Juelich116ff0f2014-09-17 18:25:16 -0700613 def test_update(self):
614 job = self._create_job(hosts=[1])
615 serialized = job.serialize(include_dependencies=False)
616 serialized['owner'] = 'some_other_owner'
617
618 job.update_from_serialized(serialized)
619 self.assertEqual(job.owner, 'some_other_owner')
620
621 serialized = job.serialize()
622 self.assertRaises(
623 ValueError,
624 job.update_from_serialized, serialized)
625
626
Jakob Juelichf865d332014-09-29 10:47:49 -0700627 def test_sync_aborted(self):
628 job = self._create_job(hosts=[1])
629 serialized = job.serialize()
630
631 serialized['hostqueueentry_set'][0]['aborted'] = True
632 serialized['hostqueueentry_set'][0]['status'] = 'Running'
633
634 models.Job.deserialize(serialized)
635
636 job = models.Job.objects.get(pk=job.id)
637 self.assertTrue(job.hostqueueentry_set.all()[0].aborted)
638 self.assertEqual(job.hostqueueentry_set.all()[0].status, 'Queued')
Jakob Juelich116ff0f2014-09-17 18:25:16 -0700639
640
showarded2afea2009-07-07 20:54:07 +0000641if __name__ == '__main__':
642 unittest.main()