Improved LinuxApplication behavior
[nepi.git] / test / execution / resource.py
1 #!/usr/bin/env python
2 #
3 #    NEPI, a framework to manage network experiments
4 #    Copyright (C) 2013 INRIA
5 #
6 #    This program is free software: you can redistribute it and/or modify
7 #    it under the terms of the GNU General Public License as published by
8 #    the Free Software Foundation, either version 3 of the License, or
9 #    (at your option) any later version.
10 #
11 #    This program is distributed in the hope that it will be useful,
12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #    GNU General Public License for more details.
15 #
16 #    You should have received a copy of the GNU General Public License
17 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
20
21
22 from nepi.execution.attribute import Attribute
23 from nepi.execution.ec import ExperimentController 
24 from nepi.execution.resource import ResourceManager, ResourceState, clsinit
25
26 import random
27 import time
28 import unittest
29
30 @clsinit
31 class MyResource(ResourceManager):
32     _rtype = "MyResource"
33
34     @classmethod
35     def _register_attributes(cls):
36         cool_attr = Attribute("my_attr", "is a really nice attribute!")
37         cls._register_attribute(cool_attr)
38
39     def __init__(self, ec, guid):
40         super(MyResource, self).__init__(ec, guid)
41
42 @clsinit
43 class AnotherResource(ResourceManager):
44     _rtype = "AnotherResource"
45
46     def __init__(self, ec, guid):
47         super(AnotherResource, self).__init__(ec, guid)
48      
49 class ResourceFactoryTestCase(unittest.TestCase):
50     def test_add_resource_factory(self):
51         from nepi.execution.resource import ResourceFactory
52
53         ResourceFactory.register_type(MyResource)
54         ResourceFactory.register_type(AnotherResource)
55
56         self.assertEquals(MyResource.rtype(), "MyResource")
57         self.assertEquals(len(MyResource._attributes), 1)
58
59         self.assertEquals(ResourceManager.rtype(), "Resource")
60         self.assertEquals(len(ResourceManager._attributes), 0)
61
62         self.assertEquals(AnotherResource.rtype(), "AnotherResource")
63         self.assertEquals(len(AnotherResource._attributes), 0)
64
65         self.assertEquals(len(ResourceFactory.resource_types()), 2)
66
67 class Channel(ResourceManager):
68     _rtype = "Channel"
69
70     def __init__(self, ec, guid):
71         super(Channel, self).__init__(ec, guid)
72
73     def deploy(self):
74         time.sleep(1)
75         super(Channel, self).deploy()
76         self.logger.debug(" -------- DEPLOYED ------- ")
77        
78 class Interface(ResourceManager):
79     _rtype = "Interface"
80
81     def __init__(self, ec, guid):
82         super(Interface, self).__init__(ec, guid)
83
84     def deploy(self):
85         node = self.get_connected(Node.rtype())[0]
86         chan = self.get_connected(Channel.rtype())[0]
87
88         if node.state < ResourceState.PROVISIONED:
89             self.ec.schedule("0.5s", self.deploy)
90         elif chan.state < ResourceState.READY:
91             self.ec.schedule("0.5s", self.deploy)
92         else:
93             time.sleep(2)
94             super(Interface, self).deploy()
95             self.logger.debug(" -------- DEPLOYED ------- ")
96
97 class Node(ResourceManager):
98     _rtype = "Node"
99
100     def __init__(self, ec, guid):
101         super(Node, self).__init__(ec, guid)
102
103     def deploy(self):
104         if self.state == ResourceState.NEW:
105             self.discover()
106             self.provision()
107             self.logger.debug(" -------- PROVISIONED ------- ")
108             self.ec.schedule("3s", self.deploy)
109         elif self.state == ResourceState.PROVISIONED:
110             ifaces = self.get_connected(Interface.rtype())
111             for rm in ifaces:
112                 if rm.state < ResourceState.READY:
113                     self.ec.schedule("0.5s", self.deploy)
114                     return 
115
116             super(Node, self).deploy()
117             self.logger.debug(" -------- DEPLOYED ------- ")
118
119 class Application(ResourceManager):
120     _rtype = "Application"
121
122     def __init__(self, ec, guid):
123         super(Application, self).__init__(ec, guid)
124
125     def deploy(self):
126         node = self.get_connected(Node.rtype())[0]
127         if node.state < ResourceState.READY:
128             self.ec.schedule("0.5s", self.deploy)
129         else:
130             time.sleep(random.random() * 5)
131             super(Application, self).deploy()
132             self.logger.debug(" -------- DEPLOYED ------- ")
133
134     def start(self):
135         super(Application, self).start()
136         time.sleep(random.random() * 5)
137         self._state = ResourceState.FINISHED
138
139 class ResourceManagerTestCase(unittest.TestCase):
140     def test_deploy_in_order(self):
141         """
142         Test scenario: 2 applications running one on 1 node each. 
143         Nodes are connected to Interfaces which are connected
144         through a channel between them.
145
146          - Application needs to wait until Node is ready to be ready
147          - Node needs to wait until Interface is ready to be ready
148          - Interface needs to wait until Node is provisioned to be ready
149          - Interface needs to wait until Channel is ready to be ready
150          - The channel doesn't wait for any other resource to be ready
151
152         """
153         from nepi.execution.resource import ResourceFactory
154         
155         ResourceFactory.register_type(Application)
156         ResourceFactory.register_type(Node)
157         ResourceFactory.register_type(Interface)
158         ResourceFactory.register_type(Channel)
159
160         ec = ExperimentController()
161
162         app1 = ec.register_resource("Application")
163         app2 = ec.register_resource("Application")
164         node1 = ec.register_resource("Node")
165         node2 = ec.register_resource("Node")
166         iface1 = ec.register_resource("Interface")
167         iface2 = ec.register_resource("Interface")
168         chan = ec.register_resource("Channel")
169
170         ec.register_connection(app1, node1)
171         ec.register_connection(app2, node2)
172         ec.register_connection(iface1, node1)
173         ec.register_connection(iface2, node2)
174         ec.register_connection(iface1, chan)
175         ec.register_connection(iface2, chan)
176
177         ec.deploy()
178
179         guids = [app1, app2]
180         ec.wait_finished(guids)
181
182         ec.shutdown()
183
184         rmapp1 = ec.get_resource(app1)
185         rmapp2 = ec.get_resource(app2)
186         rmnode1 = ec.get_resource(node1)
187         rmnode2 = ec.get_resource(node2)
188         rmiface1 = ec.get_resource(iface1)
189         rmiface2 = ec.get_resource(iface2)
190         rmchan = ec.get_resource(chan)
191
192         ## Validate deploy order
193         # - Application needs to wait until Node is ready to be ready
194         self.assertTrue(rmnode1.ready_time < rmapp1.ready_time)
195         self.assertTrue(rmnode2.ready_time < rmapp2.ready_time)
196
197          # - Node needs to wait until Interface is ready to be ready
198         self.assertTrue(rmnode1.ready_time > rmiface1.ready_time)
199         self.assertTrue(rmnode2.ready_time > rmiface2.ready_time)
200
201          # - Interface needs to wait until Node is provisioned to be ready
202         self.assertTrue(rmnode1.provision_time < rmiface1.ready_time)
203         self.assertTrue(rmnode2.provision_time < rmiface2.ready_time)
204
205          # - Interface needs to wait until Channel is ready to be ready
206         self.assertTrue(rmchan.ready_time < rmiface1.ready_time)
207         self.assertTrue(rmchan.ready_time < rmiface2.ready_time)
208
209     def test_concurrency(self):
210         from nepi.execution.resource import ResourceFactory
211         
212         ResourceFactory.register_type(Application)
213         ResourceFactory.register_type(Node)
214         ResourceFactory.register_type(Interface)
215         ResourceFactory.register_type(Channel)
216
217         ec = ExperimentController()
218
219         node = ec.register_resource("Node")
220
221         apps = list()
222         for i in xrange(1000):
223             app = ec.register_resource("Application")
224             ec.register_connection(app, node)
225             apps.append(app)
226
227         ec.deploy()
228
229         ec.wait_finished(apps)
230         
231         self.assertTrue(ec.state(node) == ResourceState.STARTED)
232         self.assertTrue(
233                all([ec.state(guid) == ResourceState.FINISHED \
234                 for guid in apps])
235                 )
236
237         ec.shutdown()
238
239     def test_start_with_condition(self):
240         # TODO!!!
241         pass
242     
243     def test_stop_with_condition(self):
244         # TODO!!!
245         pass
246
247     def test_set_with_condition(self):
248         # TODO!!!
249         pass
250
251
252 if __name__ == '__main__':
253     unittest.main()
254