First iteration of pluggable metahost handlers.  This change adds the basic framework and moves the default, label-based metahost assignment code into a handler.  It includes some refactorings to the basic scheduling code to make things a bit cleaner.

Signed-off-by: Steve Howard <showard@google.com>


git-svn-id: http://test.kernel.org/svn/autotest/trunk@4232 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/scheduler/metahost_scheduler_unittest.py b/scheduler/metahost_scheduler_unittest.py
new file mode 100644
index 0000000..5933769
--- /dev/null
+++ b/scheduler/metahost_scheduler_unittest.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+
+import common
+import unittest
+from autotest_lib.client.common_lib.test_utils import mock
+from autotest_lib.scheduler import metahost_scheduler, monitor_db
+
+class LabelMetahostSchedulerTest(unittest.TestCase):
+    def setUp(self):
+        self.god = mock.mock_god()
+        self.scheduling_utility = self.god.create_mock_class(
+                metahost_scheduler.HostSchedulingUtility, 'utility')
+        self.metahost_scheduler = metahost_scheduler.LabelMetahostScheduler()
+
+
+    def entry(self):
+        return self.god.create_mock_class(monitor_db.HostQueueEntry, 'entry')
+
+
+    def test_can_schedule_metahost(self):
+        entry = self.entry()
+        entry.meta_host = None
+        self.assertFalse(self.metahost_scheduler.can_schedule_metahost(entry))
+
+        entry.meta_host = 1
+        self.assert_(self.metahost_scheduler.can_schedule_metahost(entry))
+
+
+    def test_schedule_metahost(self):
+        entry = self.entry()
+        entry.meta_host = 1
+        host = object()
+
+        self.scheduling_utility.hosts_in_label.expect_call(1).and_return(
+                [2, 3, 4, 5])
+        # 2 is in ineligible_hosts
+        (self.scheduling_utility.ineligible_hosts_for_entry.expect_call(entry)
+         .and_return([2]))
+        self.scheduling_utility.is_host_usable.expect_call(2).and_return(True)
+        # 3 is unusable
+        self.scheduling_utility.is_host_usable.expect_call(3).and_return(False)
+        self.scheduling_utility.remove_host_from_label.expect_call(3, 1)
+        # 4 is ineligible for the job
+        self.scheduling_utility.is_host_usable.expect_call(4).and_return(True)
+        (self.scheduling_utility.is_host_eligible_for_job.expect_call(4, entry)
+         .and_return(False))
+        # 5 runs
+        self.scheduling_utility.is_host_usable.expect_call(5).and_return(True)
+        (self.scheduling_utility.is_host_eligible_for_job.expect_call(5, entry)
+         .and_return(True))
+        self.scheduling_utility.remove_host_from_label.expect_call(5, 1)
+        self.scheduling_utility.pop_host.expect_call(5).and_return(host)
+        entry.set_host.expect_call(host)
+
+        self.metahost_scheduler.schedule_metahost(entry,
+                                                  self.scheduling_utility)
+        self.god.check_playback()
+
+
+    def test_no_hosts(self):
+        entry = self.entry()
+        entry.meta_host = 1
+
+        self.scheduling_utility.hosts_in_label.expect_call(1).and_return(())
+        (self.scheduling_utility.ineligible_hosts_for_entry.expect_call(entry)
+         .and_return(()))
+
+        self.metahost_scheduler.schedule_metahost(entry,
+                                                  self.scheduling_utility)
+        self.god.check_playback()
+
+
+if __name__ == '__main__':
+    unittest.main()