Permit config shadowing

To support the idea that diverse zuul installations can share common
job definitions in a 'standard library' project, but still be able to
override some job definitions with their own local versions if needed,
add a tenant config option to permit a repo to shadow another one.

Place the local project first in configuration, then on the remote project,
indicate that it shadows the local one.  Then, any definitions in the
remote repository which conflict with the local will be ignored.

Change-Id: Ia715c5fa45141eacbb11449404ee3a3ec948d27f
diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py
index 3ab3305..7fe101e 100644
--- a/tests/unit/test_model.py
+++ b/tests/unit/test_model.py
@@ -40,7 +40,7 @@
         self.source = Dummy(canonical_hostname='git.example.com',
                             connection=self.connection)
         self.tenant = model.Tenant('tenant')
-        self.layout = model.Layout()
+        self.layout = model.Layout(self.tenant)
         self.project = model.Project('project', self.source)
         self.tpc = model.TenantProjectConfig(self.project)
         self.tenant.addUntrustedProject(self.tpc)
@@ -59,7 +59,7 @@
     @property
     def job(self):
         tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        layout = model.Layout(tenant)
         job = configloader.JobParser.fromYaml(tenant, layout, {
             '_source_context': self.context,
             '_start_mark': self.start_mark,
@@ -170,7 +170,7 @@
     def test_job_inheritance_configloader(self):
         # TODO(jeblair): move this to a configloader test
         tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        layout = model.Layout(tenant)
 
         pipeline = model.Pipeline('gate', layout)
         layout.addPipeline(pipeline)
@@ -333,8 +333,8 @@
                           'playbooks/base'])
 
     def test_job_auth_inheritance(self):
-        tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        tenant = self.tenant
+        layout = self.layout
 
         conf = yaml.safe_load('''
 - secret:
@@ -359,7 +359,7 @@
         secret = configloader.SecretParser.fromYaml(layout, conf)
         layout.addSecret(secret)
 
-        base = configloader.JobParser.fromYaml(tenant, layout, {
+        base = configloader.JobParser.fromYaml(self.tenant, self.layout, {
             '_source_context': self.context,
             '_start_mark': self.start_mark,
             'name': 'base',
@@ -443,7 +443,7 @@
 
     def test_job_inheritance_job_tree(self):
         tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        layout = model.Layout(tenant)
         tpc = model.TenantProjectConfig(self.project)
         tenant.addUntrustedProject(tpc)
 
@@ -520,7 +520,7 @@
 
     def test_inheritance_keeps_matchers(self):
         tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        layout = model.Layout(tenant)
 
         pipeline = model.Pipeline('gate', layout)
         layout.addPipeline(pipeline)
@@ -571,11 +571,13 @@
         self.assertEqual([], item.getJobs())
 
     def test_job_source_project(self):
-        tenant = model.Tenant('tenant')
-        layout = model.Layout()
+        tenant = self.tenant
+        layout = self.layout
         base_project = model.Project('base_project', self.source)
         base_context = model.SourceContext(base_project, 'master',
                                            'test', True)
+        tpc = model.TenantProjectConfig(base_project)
+        tenant.addUntrustedProject(tpc)
 
         base = configloader.JobParser.fromYaml(tenant, layout, {
             '_source_context': base_context,
@@ -587,6 +589,8 @@
         other_project = model.Project('other_project', self.source)
         other_context = model.SourceContext(other_project, 'master',
                                             'test', True)
+        tpc = model.TenantProjectConfig(other_project)
+        tenant.addUntrustedProject(tpc)
         base2 = configloader.JobParser.fromYaml(tenant, layout, {
             '_source_context': other_context,
             '_start_mark': self.start_mark,