Add support for 'connection' concept

This is a large refactor and as small as I could feasibly make it
while keeping the tests working. I'll do the documentation and
touch ups in the next commit to make digesting easier.

Change-Id: Iac5083996a183d1d8a9b6cb8f70836f7c39ee910
diff --git a/tests/base.py b/tests/base.py
index 731d842..2534f11 100755
--- a/tests/base.py
+++ b/tests/base.py
@@ -42,6 +42,8 @@
 import testtools
 from git import GitCommandError
 
+import zuul.connection.gerrit
+import zuul.connection.smtp
 import zuul.scheduler
 import zuul.webapp
 import zuul.rpclistener
@@ -379,20 +381,20 @@
         self.reported += 1
 
 
-class FakeGerrit(object):
-    log = logging.getLogger("zuul.test.FakeGerrit")
+class FakeGerritConnection(zuul.connection.gerrit.GerritConnection):
+    log = logging.getLogger("zuul.test.FakeGerritConnection")
 
-    def __init__(self, hostname, username, port=29418, keyfile=None,
-                 changes_dbs={}, queues_dbs={}):
-        self.hostname = hostname
-        self.username = username
-        self.port = port
-        self.keyfile = keyfile
-        self.event_queue = queues_dbs.get(hostname, {})
+    def __init__(self, connection_name, connection_config,
+                 changes_db=None, queues_db=None):
+        super(FakeGerritConnection, self).__init__(connection_name,
+                                                   connection_config)
+
+        self.event_queue = queues_db
         self.fixture_dir = os.path.join(FIXTURE_DIR, 'gerrit')
         self.change_number = 0
-        self.changes = changes_dbs.get(hostname, {})
+        self.changes = changes_db
         self.queries = []
+        self.upstream_root = None
 
     def addFakeChange(self, project, branch, subject, status='NEW'):
         self.change_number += 1
@@ -402,15 +404,6 @@
         self.changes[self.change_number] = c
         return c
 
-    def addEvent(self, data):
-        return self.event_queue.put((time.time(), data))
-
-    def getEvent(self):
-        return self.event_queue.get()
-
-    def eventDone(self):
-        self.event_queue.task_done()
-
     def review(self, project, changeid, message, action):
         number, ps = changeid.split(',')
         change = self.changes[int(number)]
@@ -427,11 +420,11 @@
 
         for cat in ['CRVW', 'VRFY', 'APRV']:
             if cat in action:
-                change.addApproval(cat, action[cat], username=self.username)
+                change.addApproval(cat, action[cat], username=self.user)
 
         if 'label' in action:
             parts = action['label'].split('=')
-            change.addApproval(parts[0], parts[2], username=self.username)
+            change.addApproval(parts[0], parts[2], username=self.user)
 
         change.messages.append(message)
 
@@ -464,9 +457,12 @@
             l = [change.query() for change in self.changes.values()]
         return l
 
-    def startWatching(self, *args, **kw):
+    def _start_watcher_thread(self, *args, **kw):
         pass
 
+    def getGitUrl(self, project):
+        return os.path.join(self.upstream_root, project.name)
+
 
 class BuildHistory(object):
     def __init__(self, **kw):
@@ -500,19 +496,6 @@
         return ret
 
 
-class FakeGerritSource(zuul.source.gerrit.GerritSource):
-    name = 'gerrit'
-
-    def __init__(self, upstream_root, *args):
-        super(FakeGerritSource, self).__init__(*args)
-        self.upstream_root = upstream_root
-        self.replication_timeout = 1.5
-        self.replication_retry_interval = 0.5
-
-    def getGitUrl(self, project):
-        return os.path.join(self.upstream_root, project.name)
-
-
 class FakeStatsd(threading.Thread):
     def __init__(self):
         threading.Thread.__init__(self)
@@ -898,7 +881,6 @@
             shutil.rmtree(self.test_root)
         os.makedirs(self.test_root)
         os.makedirs(self.upstream_root)
-        os.makedirs(self.git_root)
 
         # Make per test copy of Configuration.
         self.setup_config()
@@ -942,15 +924,22 @@
         self.worker.addServer('127.0.0.1', self.gearman_server.port)
         self.gearman_server.worker = self.worker
 
-        self.merge_server = zuul.merger.server.MergeServer(self.config)
-        self.merge_server.start()
+        zuul.source.gerrit.GerritSource.replication_timeout = 1.5
+        zuul.source.gerrit.GerritSource.replication_retry_interval = 0.5
+        zuul.connection.gerrit.GerritEventConnector.delay = 0.0
 
-        self.sched = zuul.scheduler.Scheduler()
+        self.sched = zuul.scheduler.Scheduler(self.config)
 
         self.useFixture(fixtures.MonkeyPatch('swiftclient.client.Connection',
                                              FakeSwiftClientConnection))
         self.swift = zuul.lib.swift.Swift(self.config)
 
+        # Set up connections and give out the default gerrit for testing
+        self.configure_connections()
+        self.sched.registerConnections(self.connections)
+        self.fake_gerrit = self.connections['gerrit']
+        self.fake_gerrit.upstream_root = self.upstream_root
+
         def URLOpenerFactory(*args, **kw):
             if isinstance(args[0], urllib2.Request):
                 return old_urlopen(*args, **kw)
@@ -960,30 +949,9 @@
         old_urlopen = urllib2.urlopen
         urllib2.urlopen = URLOpenerFactory
 
-        self.smtp_messages = []
-
-        def FakeSMTPFactory(*args, **kw):
-            args = [self.smtp_messages] + list(args)
-            return FakeSMTP(*args, **kw)
-
-        # Set a changes database so multiple FakeGerrit's can report back to
-        # a virtual canonical database given by the configured hostname
-        self.gerrit_queues_dbs = {
-            self.config.get('gerrit', 'server'): Queue.Queue()
-        }
-        self.gerrit_changes_dbs = {
-            self.config.get('gerrit', 'server'): {}
-        }
-
-        def FakeGerritFactory(*args, **kw):
-            kw['changes_dbs'] = self.gerrit_changes_dbs
-            kw['queues_dbs'] = self.gerrit_queues_dbs
-            return FakeGerrit(*args, **kw)
-
-        self.useFixture(fixtures.MonkeyPatch('zuul.lib.gerrit.Gerrit',
-                                             FakeGerritFactory))
-
-        self.useFixture(fixtures.MonkeyPatch('smtplib.SMTP', FakeSMTPFactory))
+        self.merge_server = zuul.merger.server.MergeServer(self.config,
+                                                           self.connections)
+        self.merge_server.start()
 
         self.launcher = zuul.launcher.gearman.Gearman(self.config, self.sched,
                                                       self.swift)
@@ -993,13 +961,6 @@
         self.sched.setLauncher(self.launcher)
         self.sched.setMerger(self.merge_client)
 
-        self.register_sources()
-        self.fake_gerrit = self.gerrit_source.gerrit
-        self.fake_gerrit.upstream_root = self.upstream_root
-
-        self.register_triggers()
-        self.register_reporters()
-
         self.webapp = zuul.webapp.WebApp(self.sched, port=0)
         self.rpc = zuul.rpclistener.RPCListener(self.config, self.sched)
 
@@ -1016,37 +977,67 @@
         self.addCleanup(self.assertFinalState)
         self.addCleanup(self.shutdown)
 
-    def register_sources(self):
-        # Register the available sources
-        self.gerrit_source = FakeGerritSource(
-            self.upstream_root, self.config, self.sched)
-        self.gerrit_source.replication_timeout = 1.5
-        self.gerrit_source.replication_retry_interval = 0.5
+    def configure_connections(self):
+        # Register connections from the config
+        self.smtp_messages = []
 
-        self.sched.registerSource(self.gerrit_source)
+        def FakeSMTPFactory(*args, **kw):
+            args = [self.smtp_messages] + list(args)
+            return FakeSMTP(*args, **kw)
 
-    def register_triggers(self):
-        # Register the available triggers
-        self.gerrit_trigger = zuul.trigger.gerrit.GerritTrigger(
-            self.fake_gerrit, self.config, self.sched, self.gerrit_source)
-        self.gerrit_trigger.gerrit_connector.delay = 0.0
+        self.useFixture(fixtures.MonkeyPatch('smtplib.SMTP', FakeSMTPFactory))
 
-        self.sched.registerTrigger(self.gerrit_trigger)
-        self.timer = zuul.trigger.timer.TimerTrigger(self.config, self.sched)
-        self.sched.registerTrigger(self.timer)
-        self.zuultrigger = zuul.trigger.zuultrigger.ZuulTrigger(self.config,
-                                                                self.sched)
-        self.sched.registerTrigger(self.zuultrigger)
+        # Set a changes database so multiple FakeGerrit's can report back to
+        # a virtual canonical database given by the configured hostname
+        self.gerrit_changes_dbs = {}
+        self.gerrit_queues_dbs = {}
+        self.connections = {}
 
-    def register_reporters(self):
-        # Register the available reporters
-        self.sched.registerReporter(
-            zuul.reporter.gerrit.GerritReporter(self.fake_gerrit))
-        self.smtp_reporter = zuul.reporter.smtp.SMTPReporter(
-            self.config.get('smtp', 'default_from'),
-            self.config.get('smtp', 'default_to'),
-            self.config.get('smtp', 'server'))
-        self.sched.registerReporter(self.smtp_reporter)
+        for section_name in self.config.sections():
+            con_match = re.match(r'^connection ([\'\"]?)(.*)(\1)$',
+                                 section_name, re.I)
+            if not con_match:
+                continue
+            con_name = con_match.group(2)
+            con_config = dict(self.config.items(section_name))
+
+            if 'driver' not in con_config:
+                raise Exception("No driver specified for connection %s."
+                                % con_name)
+
+            con_driver = con_config['driver']
+
+            # TODO(jhesketh): load the required class automatically
+            if con_driver == 'gerrit':
+                self.gerrit_changes_dbs[con_name] = {}
+                self.gerrit_queues_dbs[con_name] = Queue.Queue()
+                self.connections[con_name] = FakeGerritConnection(
+                    con_name, con_config,
+                    changes_db=self.gerrit_changes_dbs[con_name],
+                    queues_db=self.gerrit_queues_dbs[con_name]
+                )
+            elif con_driver == 'smtp':
+                self.connections[con_name] = \
+                    zuul.connection.smtp.SMTPConnection(con_name, con_config)
+            else:
+                raise Exception("Unknown driver, %s, for connection %s"
+                                % (con_config['driver'], con_name))
+
+        # If the [gerrit] or [smtp] sections still exist, load them in as a
+        # connection named 'gerrit' or 'smtp' respectfully
+
+        if 'gerrit' in self.config.sections():
+            self.gerrit_changes_dbs['gerrit'] = {}
+            self.gerrit_queues_dbs['gerrit'] = Queue.Queue()
+            self.connections['gerrit'] = FakeGerritConnection(
+                '_legacy_gerrit', dict(self.config.items('gerrit')),
+                changes_db=self.gerrit_changes_dbs['gerrit'],
+                queues_db=self.gerrit_queues_dbs['gerrit'])
+
+        if 'smtp' in self.config.sections():
+            self.connections['smtp'] = \
+                zuul.connection.smtp.SMTPConnection(
+                    '_legacy_smtp', dict(self.config.items('smtp')))
 
     def setup_config(self):
         """Per test config object. Override to set different config."""
@@ -1074,8 +1065,6 @@
         self.merge_server.join()
         self.merge_client.stop()
         self.worker.shutdown()
-        self.gerrit_trigger.stop()
-        self.timer.stop()
         self.sched.stop()
         self.sched.join()
         self.statsd.stop()
diff --git a/tests/fixtures/layouts/bad_gerrit_missing.yaml b/tests/fixtures/layouts/bad_gerrit_missing.yaml
new file mode 100644
index 0000000..8db7248
--- /dev/null
+++ b/tests/fixtures/layouts/bad_gerrit_missing.yaml
@@ -0,0 +1,18 @@
+pipelines:
+  - name: check
+    manager: IndependentPipelineManager
+    trigger:
+      not_gerrit:
+        - event: patchset-created
+    success:
+      review_gerrit:
+        verified: 1
+    failure:
+      review_gerrit:
+        verified: -1
+
+projects:
+  - name: test-org/test
+    check:
+      - test-merge
+      - test-test
diff --git a/tests/fixtures/layouts/bad_merge_failure.yaml b/tests/fixtures/layouts/bad_merge_failure.yaml
index fc6854e..d9b973c 100644
--- a/tests/fixtures/layouts/bad_merge_failure.yaml
+++ b/tests/fixtures/layouts/bad_merge_failure.yaml
@@ -2,13 +2,13 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
     # merge-failure-message needs a string.
     merge-failure-message:
@@ -17,20 +17,20 @@
     manager: DependentPipelineManager
     failure-message: Build failed.  For information on how to proceed, see http://wiki.example.org/Test_Failures
     trigger:
-      gerrit:
+      review_gerrit:
         - event: comment-added
           approval:
             - approved: 1
     success:
-      gerrit:
+      review_gerrit:
         verified: 2
         submit: true
     failure:
-      gerrit:
+      review_gerrit:
         verified: -2
     merge-failure:
     start:
-      gerrit:
+      review_gerrit:
         verified: 0
     precedence: high
 
diff --git a/tests/fixtures/layouts/bad_misplaced_ref.yaml b/tests/fixtures/layouts/bad_misplaced_ref.yaml
index f009c39..d8bb6bc 100644
--- a/tests/fixtures/layouts/bad_misplaced_ref.yaml
+++ b/tests/fixtures/layouts/bad_misplaced_ref.yaml
@@ -2,7 +2,7 @@
   - name: 'check'
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
           ref: /some/ref/path
 
diff --git a/tests/fixtures/layouts/bad_pipelines5.yaml b/tests/fixtures/layouts/bad_pipelines5.yaml
index f95a78e..a91ac7a 100644
--- a/tests/fixtures/layouts/bad_pipelines5.yaml
+++ b/tests/fixtures/layouts/bad_pipelines5.yaml
@@ -2,7 +2,7 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         # event is a required item but it is missing.
         - approval:
             - approved: 1
diff --git a/tests/fixtures/layouts/bad_pipelines6.yaml b/tests/fixtures/layouts/bad_pipelines6.yaml
index aa91c77..bf2d538 100644
--- a/tests/fixtures/layouts/bad_pipelines6.yaml
+++ b/tests/fixtures/layouts/bad_pipelines6.yaml
@@ -2,7 +2,7 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: comment-added
           # approved is not a valid entry. Should be approval.
           approved: 1
diff --git a/tests/fixtures/layouts/bad_reject.yaml b/tests/fixtures/layouts/bad_reject.yaml
index b1e7f84..0549875 100644
--- a/tests/fixtures/layouts/bad_reject.yaml
+++ b/tests/fixtures/layouts/bad_reject.yaml
@@ -17,5 +17,5 @@
         - code-review: [-1, -2]
           username: core-person
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
diff --git a/tests/fixtures/layouts/bad_swift.yaml b/tests/fixtures/layouts/bad_swift.yaml
index e79dca6..f217821 100644
--- a/tests/fixtures/layouts/bad_swift.yaml
+++ b/tests/fixtures/layouts/bad_swift.yaml
@@ -2,13 +2,13 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
 jobs:
diff --git a/tests/fixtures/layouts/bad_template1.yaml b/tests/fixtures/layouts/bad_template1.yaml
index cab17a1..8868edf 100644
--- a/tests/fixtures/layouts/bad_template1.yaml
+++ b/tests/fixtures/layouts/bad_template1.yaml
@@ -4,7 +4,7 @@
   - name: 'check'
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
 
 project-templates:
diff --git a/tests/fixtures/layouts/bad_template2.yaml b/tests/fixtures/layouts/bad_template2.yaml
index b731543..09a5f91 100644
--- a/tests/fixtures/layouts/bad_template2.yaml
+++ b/tests/fixtures/layouts/bad_template2.yaml
@@ -4,7 +4,7 @@
   - name: 'check'
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
 
 project-templates:
diff --git a/tests/fixtures/layouts/good_connections1.conf b/tests/fixtures/layouts/good_connections1.conf
new file mode 100644
index 0000000..768cbb0
--- /dev/null
+++ b/tests/fixtures/layouts/good_connections1.conf
@@ -0,0 +1,42 @@
+[gearman]
+server=127.0.0.1
+
+[zuul]
+layout_config=layout.yaml
+url_pattern=http://logs.example.com/{change.number}/{change.patchset}/{pipeline.name}/{job.name}/{build.number}
+job_name_in_report=true
+
+[merger]
+git_dir=/tmp/zuul-test/git
+git_user_email=zuul@example.com
+git_user_name=zuul
+zuul_url=http://zuul.example.com/p
+
+[swift]
+authurl=https://identity.api.example.org/v2.0/
+user=username
+key=password
+tenant_name=" "
+
+default_container=logs
+region_name=EXP
+logserver_prefix=http://logs.example.org/server.app/
+
+[connection review_gerrit]
+driver=gerrit
+server=review.example.com
+user=jenkins
+sshkey=none
+
+[connection other_gerrit]
+driver=gerrit
+server=review2.example.com
+user=jenkins2
+sshkey=none
+
+[connection my_smtp]
+driver=smtp
+server=localhost
+port=25
+default_from=zuul@example.com
+default_to=you@example.com
diff --git a/tests/fixtures/layouts/good_connections1.yaml b/tests/fixtures/layouts/good_connections1.yaml
new file mode 100644
index 0000000..f5f55b1
--- /dev/null
+++ b/tests/fixtures/layouts/good_connections1.yaml
@@ -0,0 +1,18 @@
+pipelines:
+  - name: check
+    manager: IndependentPipelineManager
+    source: review_gerrit
+    trigger:
+      review_gerrit:
+        - event: patchset-created
+    success:
+      review_gerrit:
+        verified: 1
+    failure:
+      other_gerrit:
+        verified: -1
+
+projects:
+  - name: org/project
+    check:
+      - project-check
diff --git a/tests/fixtures/layouts/good_layout.yaml b/tests/fixtures/layouts/good_layout.yaml
index 3608d0c..0e21d57 100644
--- a/tests/fixtures/layouts/good_layout.yaml
+++ b/tests/fixtures/layouts/good_layout.yaml
@@ -8,7 +8,7 @@
       open: True
       current-patchset: True
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
         - event: comment-added
           require-approval:
@@ -17,16 +17,16 @@
           approval:
             - workflow: 1
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
   - name: post
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: ref-updated
           ref: ^(?!refs/).*$
           ignore-deletes: True
@@ -46,32 +46,32 @@
       approval:
         - code-review: [-1, -2]
     trigger:
-      gerrit:
+      review_gerrit:
         - event: comment-added
           approval:
             - approved: 1
     start:
-      gerrit:
+      review_gerrit:
         verified: 0
     success:
-      gerrit:
+      review_gerrit:
         verified: 2
         code-review: 1
         submit: true
     failure:
-      gerrit:
+      review_gerrit:
         verified: -2
         workinprogress: true
 
   - name: merge-check
     manager: IndependentPipelineManager
-    source: gerrit
+    source: review_gerrit
     ignore-dependencies: true
     trigger:
       zuul:
         - event: project-change-merged
     merge-failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
 jobs:
diff --git a/tests/fixtures/layouts/good_merge_failure.yaml b/tests/fixtures/layouts/good_merge_failure.yaml
index f69b764..afede3c 100644
--- a/tests/fixtures/layouts/good_merge_failure.yaml
+++ b/tests/fixtures/layouts/good_merge_failure.yaml
@@ -3,47 +3,47 @@
     manager: IndependentPipelineManager
     merge-failure-message: "Could not merge the change. Please rebase..."
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
   - name: post
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: ref-updated
           ref: ^(?!refs/).*$
     merge-failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
   - name: gate
     manager: DependentPipelineManager
     failure-message: Build failed.  For information on how to proceed, see http://wiki.example.org/Test_Failures
     trigger:
-      gerrit:
+      review_gerrit:
         - event: comment-added
           approval:
             - approved: 1
     success:
-      gerrit:
+      review_gerrit:
         verified: 2
         submit: true
     failure:
-      gerrit:
+      review_gerrit:
         verified: -2
     merge-failure:
-      gerrit:
+      review_gerrit:
         verified: -1
-      smtp:
+      my_smtp:
         to: you@example.com
     start:
-      gerrit:
+      review_gerrit:
         verified: 0
     precedence: high
 
diff --git a/tests/fixtures/layouts/good_require_approvals.yaml b/tests/fixtures/layouts/good_require_approvals.yaml
index 75bdc8e..d899765 100644
--- a/tests/fixtures/layouts/good_require_approvals.yaml
+++ b/tests/fixtures/layouts/good_require_approvals.yaml
@@ -5,7 +5,7 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: comment-added
           require-approval:
             - username: jenkins
@@ -23,10 +23,10 @@
               username: jenkins
               email: jenkins@example.com
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
 projects:
diff --git a/tests/fixtures/layouts/good_swift.yaml b/tests/fixtures/layouts/good_swift.yaml
index 913c268..48ca7f0 100644
--- a/tests/fixtures/layouts/good_swift.yaml
+++ b/tests/fixtures/layouts/good_swift.yaml
@@ -2,13 +2,13 @@
   - name: check
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
     success:
-      gerrit:
+      review_gerrit:
         verified: 1
     failure:
-      gerrit:
+      review_gerrit:
         verified: -1
 
 jobs:
diff --git a/tests/fixtures/layouts/good_template1.yaml b/tests/fixtures/layouts/good_template1.yaml
index ad060a4..1680c7b 100644
--- a/tests/fixtures/layouts/good_template1.yaml
+++ b/tests/fixtures/layouts/good_template1.yaml
@@ -2,7 +2,7 @@
   - name: 'check'
     manager: IndependentPipelineManager
     trigger:
-      gerrit:
+      review_gerrit:
         - event: patchset-created
 
 project-templates:
diff --git a/tests/fixtures/layouts/zuul_default.conf b/tests/fixtures/layouts/zuul_default.conf
new file mode 100644
index 0000000..6440027
--- /dev/null
+++ b/tests/fixtures/layouts/zuul_default.conf
@@ -0,0 +1,36 @@
+[gearman]
+server=127.0.0.1
+
+[zuul]
+layout_config=layout.yaml
+url_pattern=http://logs.example.com/{change.number}/{change.patchset}/{pipeline.name}/{job.name}/{build.number}
+job_name_in_report=true
+
+[merger]
+git_dir=/tmp/zuul-test/git
+git_user_email=zuul@example.com
+git_user_name=zuul
+zuul_url=http://zuul.example.com/p
+
+[swift]
+authurl=https://identity.api.example.org/v2.0/
+user=username
+key=password
+tenant_name=" "
+
+default_container=logs
+region_name=EXP
+logserver_prefix=http://logs.example.org/server.app/
+
+[connection review_gerrit]
+driver=gerrit
+server=review.example.com
+user=jenkins
+sshkey=none
+
+[connection my_smtp]
+driver=smtp
+server=localhost
+port=25
+default_from=zuul@example.com
+default_to=you@example.com
diff --git a/tests/fixtures/zuul.conf b/tests/fixtures/zuul.conf
index ec76cd0..b250c6d 100644
--- a/tests/fixtures/zuul.conf
+++ b/tests/fixtures/zuul.conf
@@ -1,11 +1,6 @@
 [gearman]
 server=127.0.0.1
 
-[gerrit]
-server=review.example.com
-user=jenkins
-sshkey=none
-
 [zuul]
 layout_config=layout.yaml
 url_pattern=http://logs.example.com/{change.number}/{change.patchset}/{pipeline.name}/{job.name}/{build.number}
@@ -17,12 +12,6 @@
 git_user_name=zuul
 zuul_url=http://zuul.example.com/p
 
-[smtp]
-server=localhost
-port=25
-default_from=zuul@example.com
-default_to=you@example.com
-
 [swift]
 authurl=https://identity.api.example.org/v2.0/
 user=username
@@ -32,3 +21,16 @@
 default_container=logs
 region_name=EXP
 logserver_prefix=http://logs.example.org/server.app/
+
+[connection gerrit]
+driver=gerrit
+server=review.example.com
+user=jenkins
+sshkey=none
+
+[connection smtp]
+driver=smtp
+server=localhost
+port=25
+default_from=zuul@example.com
+default_to=you@example.com
diff --git a/tests/test_connection.py b/tests/test_connection.py
new file mode 100644
index 0000000..b95fafa
--- /dev/null
+++ b/tests/test_connection.py
@@ -0,0 +1,26 @@
+# Copyright 2014 Rackspace Australia
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import logging
+import testtools
+
+import zuul.connection.gerrit
+
+
+class TestGerritConnection(testtools.TestCase):
+    log = logging.getLogger("zuul.test_connection")
+
+    def test_driver_name(self):
+        self.assertEqual('gerrit',
+                         zuul.connection.gerrit.GerritConnection.driver_name)
diff --git a/tests/test_gerrit.py b/tests/test_gerrit.py
index dad2c6d..93ce122 100644
--- a/tests/test_gerrit.py
+++ b/tests/test_gerrit.py
@@ -21,7 +21,7 @@
     import mock
 
 from tests.base import BaseTestCase
-from zuul.lib.gerrit import Gerrit
+from zuul.connection.gerrit import GerritConnection
 
 FIXTURE_DIR = os.path.join(os.path.dirname(__file__), 'fixtures/gerrit')
 
@@ -46,9 +46,13 @@
 
 class TestGerrit(BaseTestCase):
 
-    @mock.patch('zuul.lib.gerrit.Gerrit._ssh')
+    @mock.patch('zuul.connection.gerrit.GerritConnection._ssh')
     def run_query(self, files, expected_patches, _ssh_mock):
-        gerrit = Gerrit('localhost', 'user')
+        gerrit_config = {
+            'user': 'gerrit',
+            'server': 'localhost',
+        }
+        gerrit = GerritConnection('review_gerrit', gerrit_config)
 
         calls, values = read_fixtures(files)
         _ssh_mock.side_effect = values
diff --git a/tests/test_layoutvalidator.py b/tests/test_layoutvalidator.py
index 5a8fc46..3dc3234 100644
--- a/tests/test_layoutvalidator.py
+++ b/tests/test_layoutvalidator.py
@@ -14,6 +14,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import ConfigParser
 import os
 import re
 
@@ -22,6 +23,7 @@
 import yaml
 
 import zuul.layoutvalidator
+import zuul.lib.connections
 
 FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
                            'fixtures')
@@ -38,19 +40,31 @@
             if not m:
                 continue
             print fn
+
+            # Load any .conf file by the same name but .conf extension.
+            config_file = ("%s.conf" %
+                           os.path.join(FIXTURE_DIR, 'layouts',
+                                        fn.split('.yaml')[0]))
+            if not os.path.isfile(config_file):
+                config_file = os.path.join(FIXTURE_DIR, 'layouts',
+                                           'zuul_default.conf')
+            config = ConfigParser.ConfigParser()
+            config.read(config_file)
+            connections = zuul.lib.connections.configure_connections(config)
+
             layout = os.path.join(FIXTURE_DIR, 'layouts', fn)
             data = yaml.load(open(layout))
             validator = zuul.layoutvalidator.LayoutValidator()
             if m.group(1) == 'good':
                 try:
-                    validator.validate(data)
+                    validator.validate(data, connections)
                 except voluptuous.Invalid as e:
                     raise Exception(
                         'Unexpected YAML syntax error in %s:\n  %s' %
                         (fn, str(e)))
             else:
                 try:
-                    validator.validate(data)
+                    validator.validate(data, connections)
                     raise Exception("Expected a YAML syntax error in %s." %
                                     fn)
                 except voluptuous.Invalid as e:
diff --git a/tests/test_reporter.py b/tests/test_reporter.py
index e7290b1..8d3090a 100644
--- a/tests/test_reporter.py
+++ b/tests/test_reporter.py
@@ -26,7 +26,7 @@
 
     def test_reporter_abc(self):
         # We only need to instantiate a class for this
-        reporter = zuul.reporter.smtp.SMTPReporter('', '')  # noqa
+        reporter = zuul.reporter.smtp.SMTPReporter({})  # noqa
 
     def test_reporter_name(self):
         self.assertEqual('smtp', zuul.reporter.smtp.SMTPReporter.name)
diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py
index f6fd7df..5168588 100755
--- a/tests/test_scheduler.py
+++ b/tests/test_scheduler.py
@@ -61,7 +61,7 @@
     """.strip()
         data = yaml.load(job_yaml)
         config_job = data.get('jobs')[0]
-        sched = zuul.scheduler.Scheduler()
+        sched = zuul.scheduler.Scheduler({})
         cm = zuul.change_matcher
         expected = cm.MatchAny([
             cm.MatchAll([
@@ -762,9 +762,9 @@
         self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
         self.waitUntilSettled()
 
-        self.log.debug("len %s" % self.gerrit_source._change_cache.keys())
+        self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
         # there should still be changes in the cache
-        self.assertNotEqual(len(self.gerrit_source._change_cache.keys()), 0)
+        self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
 
         self.worker.hold_jobs_in_build = False
         self.worker.release()
@@ -1469,7 +1469,7 @@
         "Test that the merger works with large changes after a repack"
         # https://bugs.launchpad.net/zuul/+bug/1078946
         # This test assumes the repo is already cloned; make sure it is
-        url = self.sched.sources['gerrit'].getGitUrl(
+        url = self.fake_gerrit.getGitUrl(
             self.sched.layout.projects['org/project1'])
         self.merge_server.merger.addProject('org/project1', url)
         A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
@@ -2164,7 +2164,8 @@
 
     def test_test_config(self):
         "Test that we can test the config"
-        self.sched.testConfig(self.config.get('zuul', 'layout_config'))
+        self.sched.testConfig(self.config.get('zuul', 'layout_config'),
+                              self.connections)
 
     def test_build_description(self):
         "Test that build descriptions update"
diff --git a/tests/test_trigger.py b/tests/test_trigger.py
index a09da21..7eb1b69 100644
--- a/tests/test_trigger.py
+++ b/tests/test_trigger.py
@@ -23,8 +23,7 @@
 
     def test_trigger_abc(self):
         # We only need to instantiate a class for this
-        trigger = zuul.trigger.gerrit.GerritTrigger(None, None, None,  # noqa
-                                                    None)
+        zuul.trigger.gerrit.GerritTrigger({})
 
     def test_trigger_name(self):
         self.assertEqual('gerrit', zuul.trigger.gerrit.GerritTrigger.name)
@@ -35,7 +34,7 @@
 
     def test_trigger_abc(self):
         # We only need to instantiate a class for this
-        trigger = zuul.trigger.timer.TimerTrigger(None, None)  # noqa
+        zuul.trigger.timer.TimerTrigger({})
 
     def test_trigger_name(self):
         self.assertEqual('timer', zuul.trigger.timer.TimerTrigger.name)
@@ -46,7 +45,7 @@
 
     def test_trigger_abc(self):
         # We only need to instantiate a class for this
-        trigger = zuul.trigger.zuultrigger.ZuulTrigger(None, None)  # noqa
+        zuul.trigger.zuultrigger.ZuulTrigger({})
 
     def test_trigger_name(self):
         self.assertEqual('zuul', zuul.trigger.zuultrigger.ZuulTrigger.name)