Merge tenant reconfiguration events

Replace the queue used for management events with one that can
combine similar events.  In this case, make it able to merge
tenant reconfiguration events, so that if multiple patches which
change the config merge between iterations of the event processor,
we only reconfigure the tenant once.

Tenant reconfiguration events are also associated with projects,
so make sure that when we merge them, we combine the list of projects
as well, so they have their cached configuration cleared.

Finally, don't store a reference to the tenant, but rather just the
tenant name, so that if reconfiguration events are queued, we don't
keep extra copies of layouts in ram.

Change-Id: If1669a0119b52ad0e3b9a4b92ee10d318df2eb18
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index 6efc43f..3608ef0 100755
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -2506,6 +2506,28 @@
         self.assertIn('project-merge', status_jobs[1]['dependencies'])
         self.assertIn('project-merge', status_jobs[2]['dependencies'])
 
+    def test_reconfigure_merge(self):
+        """Test that two reconfigure events are merged"""
+
+        tenant = self.sched.abide.tenants['tenant-one']
+        (trusted, project) = tenant.getProject('org/project')
+
+        self.sched.run_handler_lock.acquire()
+        self.assertEqual(self.sched.management_event_queue.qsize(), 0)
+
+        self.sched.reconfigureTenant(tenant, project)
+        self.assertEqual(self.sched.management_event_queue.qsize(), 1)
+
+        self.sched.reconfigureTenant(tenant, project)
+        # The second event should have been combined with the first
+        # so we should still only have one entry.
+        self.assertEqual(self.sched.management_event_queue.qsize(), 1)
+
+        self.sched.run_handler_lock.release()
+        self.waitUntilSettled()
+
+        self.assertEqual(self.sched.management_event_queue.qsize(), 0)
+
     def test_live_reconfiguration(self):
         "Test that live reconfiguration works"
         self.executor_server.hold_jobs_in_build = True