Removing 'waiters' from Resource (TO DISCUSS!). Proposing alterbative way for deployi...
[nepi.git] / test / execution / resource.py
index 87e0338..d90b137 100755 (executable)
@@ -1,7 +1,9 @@
 #!/usr/bin/env python
-from neco.execution.resource import ResourceManager, ResourceFactory, clsinit
 from neco.execution.attribute import Attribute
+from neco.execution.ec import ExperimentController 
+from neco.execution.resource import ResourceManager, ResourceState, clsinit
 
+import time
 import unittest
 
 @clsinit
@@ -23,11 +25,10 @@ class AnotherResource(ResourceManager):
     def __init__(self, ec, guid):
         super(AnotherResource, self).__init__(ec, guid)
      
-class EC(object):
-    pass
-
 class ResourceFactoryTestCase(unittest.TestCase):
     def test_add_resource_factory(self):
+        from neco.execution.resource import ResourceFactory
+
         ResourceFactory.register_type(MyResource)
         ResourceFactory.register_type(AnotherResource)
 
@@ -42,15 +43,163 @@ class ResourceFactoryTestCase(unittest.TestCase):
 
         self.assertEquals(len(ResourceFactory.resource_types()), 2)
 
-# TODO:!!!
+def get_connected(connections, rtype, ec):
+    connected = []
+    for guid in connections:
+        rm = ec.get_resource(guid)
+        if rm.rtype() == rtype:
+            connected.append(rm)
+    return connected
+
+class Channel(ResourceManager):
+    _rtype = "Channel"
+
+    def __init__(self, ec, guid):
+        super(Channel, self).__init__(ec, guid)
+
+    def deploy(self):
+        time.sleep(1)
+        super(Channel, self).deploy()
+        self.logger.debug(" -------- DEPLOYED ------- ")
+       
+class Interface(ResourceManager):
+    _rtype = "Interface"
+
+    def __init__(self, ec, guid):
+        super(Interface, self).__init__(ec, guid)
+
+    def deploy(self):
+        node = get_connected(self.connections, Node.rtype(), self.ec)[0]
+        chan = get_connected(self.connections, Channel.rtype(), self.ec)[0]
+
+        if node.state < ResourceState.PROVISIONED:
+            self.ec.schedule("0.5s", self.deploy)
+        elif chan.state < ResourceState.READY:
+            self.ec.schedule("0.5s", self.deploy)
+        else:
+            time.sleep(2)
+            super(Interface, self).deploy()
+            self.logger.debug(" -------- DEPLOYED ------- ")
+
+class Node(ResourceManager):
+    _rtype = "Node"
+
+    def __init__(self, ec, guid):
+        super(Node, self).__init__(ec, guid)
+
+    def deploy(self):
+        if self.state == ResourceState.NEW:
+            self.discover()
+            self.provision()
+            self.logger.debug(" -------- PROVISIONED ------- ")
+            self.ec.schedule("3s", self.deploy)
+        elif self.state == ResourceState.PROVISIONED:
+            ifaces = get_connected(self.connections, Interface.rtype(), self.ec)
+            for rm in ifaces:
+                if rm.state < ResourceState.READY:
+                    self.ec.schedule("0.5s", self.deploy)
+                    return 
+
+            super(Node, self).deploy()
+            self.logger.debug(" -------- DEPLOYED ------- ")
+
+class Application(ResourceManager):
+    _rtype = "Application"
+
+    def __init__(self, ec, guid):
+        super(Application, self).__init__(ec, guid)
+
+    def deploy(self):
+        node = get_connected(self.connections, Node.rtype(), self.ec)[0]
+        if node.state < ResourceState.READY:
+            self.ec.schedule("0.5s", self.deploy)
+        else:
+            super(Application, self).deploy()
+            self.logger.debug(" -------- DEPLOYED ------- ")
+
 class ResourceManagerTestCase(unittest.TestCase):
+    def test_deploy_in_order(self):
+        """
+        Test scenario: 2 applications running one on 1 node each. 
+        Nodes are connected to Interfaces which are connected
+        through a channel between them.
+
+         - Application needs to wait until Node is ready to be ready
+         - Node needs to wait until Interface is ready to be ready
+         - Interface needs to wait until Node is provisioned to be ready
+         - Interface needs to wait until Channel is ready to be ready
+         - The channel doesn't wait for any other resource to be ready
+
+        """
+        from neco.execution.resource import ResourceFactory
+        
+        ResourceFactory.register_type(Application)
+        ResourceFactory.register_type(Node)
+        ResourceFactory.register_type(Interface)
+        ResourceFactory.register_type(Channel)
+
+        ec = ExperimentController()
+
+        app1 = ec.register_resource("Application")
+        app2 = ec.register_resource("Application")
+        node1 = ec.register_resource("Node")
+        node2 = ec.register_resource("Node")
+        iface1 = ec.register_resource("Interface")
+        iface2 = ec.register_resource("Interface")
+        chan = ec.register_resource("Channel")
+
+        ec.register_connection(app1, node1)
+        ec.register_connection(app2, node2)
+        ec.register_connection(iface1, node1)
+        ec.register_connection(iface2, node2)
+        ec.register_connection(iface1, chan)
+        ec.register_connection(iface2, chan)
+
+        try:
+            ec.deploy()
+
+            while not all([ ec.state(guid) == ResourceState.STARTED \
+                    for guid in [app1, app2, node1, node2, iface1, iface2, chan]]):
+                time.sleep(0.5)
+
+        finally:
+            ec.shutdown()
+
+        rmapp1 = ec.get_resource(app1)
+        rmapp2 = ec.get_resource(app2)
+        rmnode1 = ec.get_resource(node1)
+        rmnode2 = ec.get_resource(node2)
+        rmiface1 = ec.get_resource(iface1)
+        rmiface2 = ec.get_resource(iface2)
+        rmchan = ec.get_resource(chan)
+
+        ## Validate deploy order
+        # - Application needs to wait until Node is ready to be ready
+        self.assertTrue(rmnode1.ready_time < rmapp1.ready_time)
+        self.assertTrue(rmnode2.ready_time < rmapp2.ready_time)
+
+         # - Node needs to wait until Interface is ready to be ready
+        self.assertTrue(rmnode1.ready_time > rmiface1.ready_time)
+        self.assertTrue(rmnode2.ready_time > rmiface2.ready_time)
+
+         # - Interface needs to wait until Node is provisioned to be ready
+        self.assertTrue(rmnode1.provision_time < rmiface1.ready_time)
+        self.assertTrue(rmnode2.provision_time < rmiface2.ready_time)
+
+         # - Interface needs to wait until Channel is ready to be ready
+        self.assertTrue(rmchan.ready_time < rmiface1.ready_time)
+        self.assertTrue(rmchan.ready_time < rmiface2.ready_time)
+
     def test_start_with_condition(self):
+        # TODO!!!
         pass
     
     def test_stop_with_condition(self):
+        # TODO!!!
         pass
 
     def test_set_with_condition(self):
+        # TODO!!!
         pass