[autotest] Deserialize records and persist them

To send records from the master to shards it's necessary to serialize
them. This adds the deserialization functionality.

TEST=Ran suites.
DEPLOY=apache

Change-Id: I2806b0cfe1e4fbfba5d89e6d422800c7637ed4e9
Reviewed-on: https://chromium-review.googlesource.com/216355
Reviewed-by: Prashanth B <beeps@chromium.org>
Tested-by: Jakob Jülich <jakobjuelich@chromium.org>
Commit-Queue: Jakob Jülich <jakobjuelich@chromium.org>
diff --git a/frontend/afe/models_test.py b/frontend/afe/models_test.py
index 555243f..b19eef3 100755
--- a/frontend/afe/models_test.py
+++ b/frontend/afe/models_test.py
@@ -308,109 +308,282 @@
 class SerializationTest(unittest.TestCase,
                         frontend_test_utils.FrontendTestMixin):
     def setUp(self):
-        self._frontend_common_setup()
+        self._frontend_common_setup(fill_data=False)
 
 
     def tearDown(self):
         self._frontend_common_teardown()
 
 
-    def test_serialize(self):
-        platform_label = models.Label.objects.get(platform=True)
+    def _get_example_response(self):
+        return {'hosts': [{'aclgroup_set': [{'description': '',
+                                             'id': 1,
+                                             'name': 'Everyone',
+                                             'users': [{
+                                                 'access_level': 100,
+                                                 'id': 1,
+                                                 'login': 'autotest_system',
+                                                 'reboot_after': 0,
+                                                 'reboot_before': 1,
+                                                 'show_experimental': False}]}],
+                           'dirty': True,
+                           'hostattribute_set': [],
+                           'hostname': '100.107.2.163',
+                           'id': 2,
+                           'invalid': False,
+                           'labels': [{'id': 7,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'power:battery',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 9,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'hw_video_acc_h264',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 10,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'hw_video_acc_enc_h264',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 11,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'webcam',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 12,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'touchpad',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 13,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'spring',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 14,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'board:daisy',
+                                       'only_if_needed': False,
+                                       'platform': True},
+                                      {'id': 15,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'board_freq_mem:daisy_1.7GHz',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 16,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'bluetooth',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 17,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'gpu_family:mali',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 18,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'graphics:gles',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 19,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'ec:cros',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 20,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'storage:mmc',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 21,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'hw_video_acc_vp8',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 22,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'video_glitch_detection',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 23,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'pool:suites',
+                                       'only_if_needed': False,
+                                       'platform': False},
+                                      {'id': 25,
+                                       'invalid': False,
+                                       'kernel_config': '',
+                                       'name': 'daisy-board-name',
+                                       'only_if_needed': False,
+                                       'platform': False}],
+                           'leased': False,
+                           'lock_time': None,
+                           'locked': False,
+                           'protection': 0,
+                           'shard': {'hostname': '1', 'id': 1},
+                           'status': 'Ready',
+                           'synch_id': None}],
+                'jobs': [{'control_file': 'some control file\n\n\n',
+                          'control_type': 2,
+                          'created_on': '2014-09-04T13:09:35',
+                          'dependency_labels': [{'id': 14,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'board:daisy',
+                                                 'only_if_needed': False,
+                                                 'platform': True},
+                                                {'id': 23,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'pool:suites',
+                                                 'only_if_needed': False,
+                                                 'platform': False},
+                                                {'id': 25,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'daisy-board-name',
+                                                 'only_if_needed': False,
+                                                 'platform': False}],
+                          'email_list': '',
+                          'hostqueueentry_set': [{'aborted': False,
+                                                  'active': False,
+                                                  'complete': False,
+                                                  'deleted': False,
+                                                  'execution_subdir': '',
+                                                  'finished_on': None,
+                                                  'id': 5,
+                                                  'meta_host': {
+                                                      'id': 14,
+                                                      'invalid': False,
+                                                      'kernel_config': '',
+                                                      'name': 'board:daisy',
+                                                      'only_if_needed': False,
+                                                      'platform': True},
+                                                  'started_on': None,
+                                                  'status': 'Queued'}],
+                          'id': 5,
+                          'jobkeyval_set': [{'id': 10,
+                                             'key': 'suite',
+                                             'value': 'dummy'},
+                                            {'id': 11,
+                                             'key': 'build',
+                                             'value': 'daisy-release'},
+                                            {'id': 12,
+                                             'key': 'experimental',
+                                             'value': 'False'}],
+                          'max_runtime_hrs': 72,
+                          'max_runtime_mins': 1440,
+                          'name': 'daisy-experimental',
+                          'owner': 'autotest',
+                          'parse_failed_repair': True,
+                          'priority': 40,
+                          'reboot_after': 0,
+                          'reboot_before': 1,
+                          'run_reset': True,
+                          'run_verify': False,
+                          'shard': {'hostname': '1', 'id': 1},
+                          'synch_count': 1,
+                          'test_retry': 0,
+                          'timeout': 24,
+                          'timeout_mins': 1440},
+                         {'control_file': 'some control file\n\n\n',
+                          'control_type': 2,
+                          'created_on': '2014-09-04T13:09:35',
+                          'dependency_labels': [{'id': 14,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'board:daisy',
+                                                 'only_if_needed': False,
+                                                 'platform': True},
+                                                {'id': 23,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'pool:suites',
+                                                 'only_if_needed': False,
+                                                 'platform': False},
+                                                {'id': 25,
+                                                 'invalid': False,
+                                                 'kernel_config': '',
+                                                 'name': 'daisy-board-name',
+                                                 'only_if_needed': False,
+                                                 'platform': False}],
+                          'email_list': '',
+                          'hostqueueentry_set': [{'aborted': False,
+                                                  'active': False,
+                                                  'complete': False,
+                                                  'deleted': False,
+                                                  'execution_subdir': '',
+                                                  'finished_on': None,
+                                                  'id': 7,
+                                                  'meta_host': {
+                                                      'id': 14,
+                                                      'invalid': False,
+                                                      'kernel_config': '',
+                                                      'name': 'board:daisy',
+                                                      'only_if_needed': False,
+                                                      'platform': True},
+                                                  'started_on': None,
+                                                  'status': 'Queued'}],
+                          'id': 7,
+                          'jobkeyval_set': [{'id': 16,
+                                             'key': 'suite',
+                                             'value': 'dummy'},
+                                            {'id': 17,
+                                             'key': 'build',
+                                             'value': 'daisy-release'},
+                                            {'id': 18,
+                                             'key': 'experimental',
+                                             'value': 'False'}],
+                          'max_runtime_hrs': 72,
+                          'max_runtime_mins': 1440,
+                          'name': 'daisy-experimental',
+                          'owner': 'autotest',
+                          'parse_failed_repair': True,
+                          'priority': 40,
+                          'reboot_after': 0,
+                          'reboot_before': 1,
+                          'run_reset': True,
+                          'run_verify': False,
+                          'shard': {'hostname': '1', 'id': 1},
+                          'synch_count': 1,
+                          'test_retry': 0,
+                          'timeout': 24,
+                          'timeout_mins': 1440}]}
 
-        suite_job = self._create_job(hostless=True)
-        job1 = self._create_job(parent_job_id=suite_job.id,
-                                metahosts=[platform_label.id]
-                                )
-        job2 = self._create_job(parent_job_id=suite_job.id,
-                                metahosts=[platform_label.id])
 
-        host1, host2 = models.Host.objects.all()[:2]
+    def test_response(self):
+        heartbeat_response = self._get_example_response()
+        hosts_serialized = heartbeat_response['hosts']
+        jobs_serialized = heartbeat_response['jobs']
 
-        job1_serialized = job1.serialize()
-        host1_serialized = host1.serialize()
+        # Persisting is automatically done inside deserialize
+        hosts = [models.Host.deserialize(host) for host in hosts_serialized]
+        jobs = [models.Job.deserialize(job) for job in jobs_serialized]
 
-        self.assertEqual(
-            job1_serialized,
-            {'control_file': 'control',
-             'control_type': 2,
-             'created_on': datetime.datetime(2008, 1, 1, 0, 0),
-             'dependency_labels': [{u'id': 10,
-                                    'invalid': False,
-                                    'kernel_config': u'',
-                                    'name': u'myplatform',
-                                    'only_if_needed': False,
-                                    'platform': True}],
-             'email_list': u'',
-             'hostqueueentry_set': [{'aborted': False,
-                                     'active': False,
-                                     'complete': False,
-                                     'deleted': False,
-                                     'execution_subdir': u'',
-                                     'finished_on': None,
-                                     u'id': 2,
-                                     'meta_host': {u'id': 10,
-                                                   'invalid': False,
-                                                   'kernel_config': u'',
-                                                   'name': u'myplatform',
-                                                   'only_if_needed': False,
-                                                   'platform': True},
-                                     'started_on': None,
-                                     'status': u'Queued'}],
-             u'id': 2,
-             'jobkeyval_set': [],
-             'max_runtime_hrs': 72,
-             'max_runtime_mins': u'1440',
-             'name': 'test',
-             'owner': 'autotest_system',
-             'parse_failed_repair': True,
-             'priority': 0,
-             'reboot_after': 0,
-             'reboot_before': 0,
-             'run_reset': True,
-             'run_verify': False,
-             'shard': None,
-             'synch_count': 1,
-             'test_retry': 0,
-             'timeout': u'24',
-             'timeout_mins': u'1440'}
-        )
-        self.assertEqual(
-            host1_serialized,
-            {'aclgroup_set': [{'description': u'',
-                               u'id': 2,
-                               'name': u'my_acl',
-                               'users': [{'access_level': 100,
-                                          u'id': 1,
-                                          'login': u'autotest_system',
-                                          'reboot_after': 0,
-                                          'reboot_before': 1,
-                                          'show_experimental': False}]}],
-             'dirty': True,
-             'hostattribute_set': [],
-             'hostname': u'host1',
-             u'id': 1,
-             'invalid': False,
-             'labels': [{u'id': 1,
-                         'invalid': False,
-                         'kernel_config': u'',
-                         'name': u'label1',
-                         'only_if_needed': False,
-                         'platform': False},
-                        {u'id': 10,
-                         'invalid': False,
-                         'kernel_config': u'',
-                         'name': u'myplatform',
-                         'only_if_needed': False,
-                         'platform': True}],
-             'leased': True,
-             'lock_time': None,
-             'locked': False,
-             'protection': 0,
-             'shard': None,
-             'status': u'Ready',
-             'synch_id': None}
-        )
+        generated_heartbeat_response = {
+            'hosts': [host.serialize() for host in hosts],
+            'jobs': [job.serialize() for job in jobs]
+        }
+
+        self.assertEqual(generated_heartbeat_response,
+                         self._get_example_response())
 
 
 if __name__ == '__main__':