Speed configuration building

Together, these changes build an OpenStack-sized configuration in
8% of the time it currently takes.

Change-Id: I85f538a7ebdb82724559203e2c5d5380c07f07e7
diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py
index e368108..628a45c 100644
--- a/tests/unit/test_model.py
+++ b/tests/unit/test_model.py
@@ -246,7 +246,11 @@
         })
         layout.addJob(python27essex)
 
-        project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
+        project_template_parser = configloader.ProjectTemplateParser(
+            tenant, layout)
+        project_parser = configloader.ProjectParser(
+            tenant, layout, project_template_parser)
+        project_config = project_parser.fromYaml([{
             '_source_context': self.context,
             '_start_mark': self.start_mark,
             'name': 'project',
@@ -505,6 +509,7 @@
     def test_job_inheritance_job_tree(self):
         tenant = model.Tenant('tenant')
         layout = model.Layout(tenant)
+
         tpc = model.TenantProjectConfig(self.project)
         tenant.addUntrustedProject(tpc)
 
@@ -539,7 +544,11 @@
         })
         layout.addJob(python27diablo)
 
-        project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
+        project_template_parser = configloader.ProjectTemplateParser(
+            tenant, layout)
+        project_parser = configloader.ProjectParser(
+            tenant, layout, project_template_parser)
+        project_config = project_parser.fromYaml([{
             '_source_context': self.context,
             '_start_mark': self.start_mark,
             'name': 'project',
@@ -609,7 +618,11 @@
         })
         layout.addJob(python27)
 
-        project_config = configloader.ProjectParser.fromYaml(tenant, layout, [{
+        project_template_parser = configloader.ProjectTemplateParser(
+            tenant, layout)
+        project_parser = configloader.ProjectParser(
+            tenant, layout, project_template_parser)
+        project_config = project_parser.fromYaml([{
             '_source_context': self.context,
             '_start_mark': self.start_mark,
             'name': 'project',
@@ -682,8 +695,12 @@
         context2 = model.SourceContext(project2, 'master',
                                        'test', True)
 
-        project2_config = configloader.ProjectParser.fromYaml(
-            self.tenant, self.layout, [{
+        project_template_parser = configloader.ProjectTemplateParser(
+            self.tenant, self.layout)
+        project_parser = configloader.ProjectParser(
+            self.tenant, self.layout, project_template_parser)
+        project2_config = project_parser.fromYaml(
+            [{
                 '_source_context': context2,
                 '_start_mark': self.start_mark,
                 'name': 'project2',
@@ -718,8 +735,12 @@
 
         self.layout.addJob(job)
 
-        project_config = configloader.ProjectParser.fromYaml(
-            self.tenant, self.layout, [{
+        project_template_parser = configloader.ProjectTemplateParser(
+            self.tenant, self.layout)
+        project_parser = configloader.ProjectParser(
+            self.tenant, self.layout, project_template_parser)
+        project_config = project_parser.fromYaml(
+            [{
                 '_source_context': self.context,
                 '_start_mark': self.start_mark,
                 'name': 'project',
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index 5226675..65a37ff 100755
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -2269,6 +2269,58 @@
         self.assertEqual(set(['project-test-nomatch-starts-empty',
                               'project-test-nomatch-starts-full']), run_jobs)
 
+    @simple_layout('layouts/job-vars.yaml')
+    def test_inherited_job_variables(self):
+        A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+        self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+        self.waitUntilSettled()
+        self.assertHistory([
+            dict(name='parentjob', result='SUCCESS'),
+            dict(name='child1', result='SUCCESS'),
+            dict(name='child2', result='SUCCESS'),
+            dict(name='child3', result='SUCCESS'),
+        ], ordered=False)
+        j = self.getJobFromHistory('parentjob')
+        rp = set([p['name'] for p in j.parameters['projects']])
+        self.assertEqual(j.parameters['vars']['override'], 0)
+        self.assertEqual(j.parameters['vars']['child1override'], 0)
+        self.assertEqual(j.parameters['vars']['parent'], 0)
+        self.assertFalse('child1' in j.parameters['vars'])
+        self.assertFalse('child2' in j.parameters['vars'])
+        self.assertFalse('child3' in j.parameters['vars'])
+        self.assertEqual(rp, set(['org/project', 'org/project0',
+                                  'org/project0']))
+        j = self.getJobFromHistory('child1')
+        rp = set([p['name'] for p in j.parameters['projects']])
+        self.assertEqual(j.parameters['vars']['override'], 1)
+        self.assertEqual(j.parameters['vars']['child1override'], 1)
+        self.assertEqual(j.parameters['vars']['parent'], 0)
+        self.assertEqual(j.parameters['vars']['child1'], 1)
+        self.assertFalse('child2' in j.parameters['vars'])
+        self.assertFalse('child3' in j.parameters['vars'])
+        self.assertEqual(rp, set(['org/project', 'org/project0',
+                                  'org/project1']))
+        j = self.getJobFromHistory('child2')
+        rp = set([p['name'] for p in j.parameters['projects']])
+        self.assertEqual(j.parameters['vars']['override'], 2)
+        self.assertEqual(j.parameters['vars']['child1override'], 0)
+        self.assertEqual(j.parameters['vars']['parent'], 0)
+        self.assertFalse('child1' in j.parameters['vars'])
+        self.assertEqual(j.parameters['vars']['child2'], 2)
+        self.assertFalse('child3' in j.parameters['vars'])
+        self.assertEqual(rp, set(['org/project', 'org/project0',
+                                  'org/project2']))
+        j = self.getJobFromHistory('child3')
+        rp = set([p['name'] for p in j.parameters['projects']])
+        self.assertEqual(j.parameters['vars']['override'], 3)
+        self.assertEqual(j.parameters['vars']['child1override'], 0)
+        self.assertEqual(j.parameters['vars']['parent'], 0)
+        self.assertFalse('child1' in j.parameters['vars'])
+        self.assertFalse('child2' in j.parameters['vars'])
+        self.assertEqual(j.parameters['vars']['child3'], 3)
+        self.assertEqual(rp, set(['org/project', 'org/project0',
+                                  'org/project3']))
+
     def test_queue_names(self):
         "Test shared change queue names"
         tenant = self.sched.abide.tenants.get('tenant-one')