Merge with aly's
[nepi.git] / test / testbeds / planetlab / execute.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import getpass
5 from nepi.util.constants import ApplicationStatus as AS
6 from nepi.testbeds import planetlab
7 import os
8 import shutil
9 import tempfile
10 import time
11 import unittest
12 import re
13 import test_util
14 import sys
15
16 class PlanetLabExecuteTestCase(unittest.TestCase):
17     testbed_id = "planetlab"
18     slicename = "inria_nepi"
19     plchost = "nepiplc.pl.sophia.inria.fr"
20     
21     host1 = "nepi1.pl.sophia.inria.fr"
22     host2 = "nepi2.pl.sophia.inria.fr"
23     
24     port_base = 2000 + (os.getpid() % 1000) * 13
25     
26     PLR50_PY = os.path.join(
27         os.path.dirname(planetlab.__file__), 
28         'scripts',
29         'plr50.py')
30     PLR50_C = os.path.join(
31         os.path.dirname(planetlab.__file__), 
32         'scripts',
33         'plr50.c')
34     TOS_PY = os.path.join(
35         os.path.dirname(planetlab.__file__), 
36         'scripts',
37         'tosqueue.py')
38     
39     def setUp(self):
40         self.root_dir = tempfile.mkdtemp()
41         self.__class__.port_base = self.port_base + 100
42         
43     def tearDown(self):
44         try:
45             shutil.rmtree(self.root_dir)
46         except:
47             # retry
48             time.sleep(0.1)
49             shutil.rmtree(self.root_dir)
50
51     def make_instance(self):
52         testbed_id = self.testbed_id
53         slicename = self.slicename
54         plchost = self.plchost
55         
56         instance = planetlab.TestbedController()
57         pl_ssh_key = os.environ.get(
58             "PL_SSH_KEY",
59             "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
60         slicename = os.environ.get(
61             "PL_SLICE",
62             slicename)
63         pl_user, pl_pwd = test_util.pl_auth()
64         
65         instance.defer_configure("homeDirectory", self.root_dir)
66         instance.defer_configure("slice", slicename)
67         instance.defer_configure("sliceSSHKey", pl_ssh_key)
68         instance.defer_configure("authUser", pl_user)
69         instance.defer_configure("authPass", pl_pwd)
70         instance.defer_configure("plcHost", plchost)
71         instance.defer_configure("tapPortBase", self.port_base)
72         instance.defer_configure("p2pDeployment", False) # it's interactive, we don't want it in tests
73         instance.defer_configure("dedicatedSlice", True)
74         
75         # Hack, but we need vsys_vnet
76         instance.do_setup()
77         vnet = instance.vsys_vnet
78         self.net_prefix = vnet.rsplit('.',1)[0]
79         
80         return instance
81
82     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
83     def test_simple(self):
84         instance = self.make_instance()
85         
86         instance.defer_create(2, "Node")
87         instance.defer_create_set(2, "hostname", self.host1)
88         instance.defer_create(3, "Node")
89         instance.defer_create_set(3, "hostname", self.host2)
90         instance.defer_create(4, "NodeInterface")
91         instance.defer_connect(2, "devs", 4, "node")
92         instance.defer_create(5, "NodeInterface")
93         instance.defer_connect(3, "devs", 5, "node")
94         instance.defer_create(6, "Internet")
95         instance.defer_connect(4, "inet", 6, "devs")
96         instance.defer_connect(5, "inet", 6, "devs")
97         instance.defer_create(7, "Application")
98         instance.defer_create_set(7, "command", "ping -qc1 {#[GUID-5].addr[0].[Address]#}")
99         instance.defer_add_trace(7, "stdout")
100         instance.defer_add_trace(7, "stderr")
101         instance.defer_connect(7, "node", 2, "apps")
102
103         comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
104
105 --- .* ping statistics ---
106 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
107 """
108
109         try:
110             instance.do_setup()
111             instance.do_create()
112             instance.do_connect_init()
113             instance.do_connect_compl()
114             instance.do_preconfigure()
115             
116             # Manually replace netref
117             instance.set(7, "command",
118                 instance.get(7, "command")
119                     .replace("{#[GUID-5].addr[0].[Address]#}", 
120                         instance.get_address(5, 0, "Address") )
121             )
122
123             instance.do_configure()
124             
125             instance.do_prestart()
126             instance.start()
127             while instance.status(7) != AS.STATUS_FINISHED:
128                 time.sleep(0.5)
129             ping_result = instance.trace(7, "stdout") or ""
130             instance.stop()
131         finally:
132             try:
133                 instance.shutdown()
134             except:
135                 pass
136
137         # asserts at the end, to make sure there's proper cleanup
138         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
139             "Unexpected trace:\n" + ping_result)
140         
141     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
142     def test_depends(self):
143         instance = self.make_instance()
144         
145         instance.defer_create(2, "Node")
146         instance.defer_create_set(2, "hostname", self.host1)
147         instance.defer_create(3, "NodeInterface")
148         instance.defer_connect(2, "devs", 3, "node")
149         instance.defer_create(4, "Internet")
150         instance.defer_connect(3, "inet", 4, "devs")
151         instance.defer_create(5, "Application")
152         instance.defer_create_set(5, "command", "gfortran --version")
153         instance.defer_create_set(5, "depends", "gcc-gfortran")
154         instance.defer_add_trace(5, "stdout")
155         instance.defer_add_trace(5, "stderr")
156         instance.defer_connect(5, "node", 2, "apps")
157
158         try:
159             instance.do_setup()
160             instance.do_create()
161             instance.do_connect_init()
162             instance.do_connect_compl()
163             instance.do_preconfigure()
164             instance.do_configure()
165             
166             instance.do_prestart()
167             instance.start()
168             while instance.status(5) != AS.STATUS_FINISHED:
169                 time.sleep(0.5)
170             ping_result = instance.trace(5, "stdout") or ""
171             comp_result = r".*GNU Fortran \(GCC\).*"
172             instance.stop()
173         finally:
174             try:
175                 instance.shutdown()
176             except:
177                 pass
178
179         # asserts at the end, to make sure there's proper cleanup
180         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
181             "Unexpected trace:\n" + ping_result)
182         
183     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
184     def test_build(self):
185         instance = self.make_instance()
186         
187         instance.defer_create(2, "Node")
188         instance.defer_create_set(2, "hostname", self.host1)
189         instance.defer_create(3, "NodeInterface")
190         instance.defer_connect(2, "devs", 3, "node")
191         instance.defer_create(4, "Internet")
192         instance.defer_connect(3, "inet", 4, "devs")
193         instance.defer_create(10, "Application")
194         instance.defer_create_set(10, "command", "./consts")
195         instance.defer_create_set(10, "buildDepends", "gcc")
196         instance.defer_create_set(10, "build", "gcc ${SOURCES}/consts.c -o consts")
197         instance.defer_create_set(10, "install", "cp consts ${SOURCES}/consts")
198         instance.defer_create_set(10, "sources", os.path.join(os.path.dirname(planetlab.__file__),'scripts','consts.c'))
199         instance.defer_add_trace(10, "stdout")
200         instance.defer_add_trace(10, "stderr")
201         instance.defer_connect(10, "node", 2, "apps")
202
203         comp_result = \
204 r""".*ETH_P_ALL = 0x[0-9a-fA-F]{8}
205 ETH_P_IP = 0x[0-9a-fA-F]{8}
206 TUNGETIFF = 0x[0-9a-fA-F]{8}
207 TUNSETIFF = 0x[0-9a-fA-F]{8}
208 IFF_NO_PI = 0x[0-9a-fA-F]{8}
209 IFF_TAP = 0x[0-9a-fA-F]{8}
210 IFF_TUN = 0x[0-9a-fA-F]{8}
211 IFF_VNET_HDR = 0x[0-9a-fA-F]{8}
212 TUN_PKT_STRIP = 0x[0-9a-fA-F]{8}
213 IFHWADDRLEN = 0x[0-9a-fA-F]{8}
214 IFNAMSIZ = 0x[0-9a-fA-F]{8}
215 IFREQ_SZ = 0x[0-9a-fA-F]{8}
216 FIONREAD = 0x[0-9a-fA-F]{8}.*
217 """
218
219         try:
220             instance.do_setup()
221             instance.do_create()
222             instance.do_connect_init()
223             instance.do_connect_compl()
224             instance.do_preconfigure()
225             instance.do_configure()
226             
227             instance.do_prestart()
228             instance.start()
229             while instance.status(10) != AS.STATUS_FINISHED:
230                 time.sleep(0.5)
231             ping_result = instance.trace(10, "stdout") or ""
232             instance.stop()
233         finally:
234             try:
235                 instance.shutdown()
236             except:
237                 pass
238
239         # asserts at the end, to make sure there's proper cleanup
240         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
241             "Unexpected trace:\n" + ping_result)
242         
243     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
244     def test_simple_vsys(self):
245         instance = self.make_instance()
246         
247         instance.defer_create(2, "Node")
248         instance.defer_create_set(2, "hostname", self.host1)
249         instance.defer_create(3, "NodeInterface")
250         instance.defer_connect(2, "devs", 3, "node")
251         instance.defer_create(4, "Internet")
252         instance.defer_connect(3, "inet", 4, "devs")
253         instance.defer_create(5, "TunInterface")
254         instance.defer_add_address(5, self.net_prefix+".2", 24, False)
255         instance.defer_connect(2, "devs", 5, "node")
256         instance.defer_create(6, "Application")
257         instance.defer_create_set(6, "command", """
258 set -e
259 netconfig help > /dev/null
260 test -e /vsys/vif_up.in > /dev/null
261 test -e /vsys/vif_up.out > /dev/null
262 test -e /vsys/fd_tuntap.control > /dev/null
263 echo 'OKIDOKI'
264 """)
265         instance.defer_create_set(6, "sudo", True) # only sudo has access to /vsys
266         instance.defer_add_trace(6, "stdout")
267         instance.defer_add_trace(6, "stderr")
268         instance.defer_connect(6, "node", 2, "apps")
269
270         try:
271             instance.do_setup()
272             instance.do_create()
273             instance.do_connect_init()
274             instance.do_connect_compl()
275             instance.do_preconfigure()
276             instance.do_configure()
277             
278             instance.do_prestart()
279             instance.start()
280             while instance.status(6) != AS.STATUS_FINISHED:
281                 time.sleep(0.5)
282             test_result = (instance.trace(6, "stdout") or "").strip()
283             comp_result = "OKIDOKI"
284             instance.stop()
285         finally:
286             try:
287                 instance.shutdown()
288             except:
289                 pass
290
291         # asserts at the end, to make sure there's proper cleanup
292         self.assertEqual(comp_result, test_result)
293
294     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
295     def test_emulation(self):
296         instance = self.make_instance()
297         
298         instance.defer_create(2, "Node")
299         instance.defer_create_set(2, "hostname", self.host1)
300         instance.defer_create(3, "NodeInterface")
301         instance.defer_connect(2, "devs", 3, "node")
302         instance.defer_create(4, "Internet")
303         instance.defer_connect(3, "inet", 4, "devs")
304         instance.defer_create(7, "NetPipe")
305         instance.defer_create_set(7, "mode", "CLIENT")
306         instance.defer_create_set(7, "portList", "80")
307         instance.defer_create_set(7, "bwOut", 12.0/1024.0) # 12kbps
308         instance.defer_create_set(7, "bwIn", 64.0/1024.0) # 64kbps
309         instance.defer_create_set(7, "plrOut", 0.01) # 1% plr outbound - high loss
310         instance.defer_create_set(7, "plrIn", 0.001) # 0.1% plr inbound - regular loss
311         instance.defer_create_set(7, "delayOut", int(1500 * 8 / (12.0/1024.0) / 1000)) # tx delay at 12kbps in ms
312         instance.defer_create_set(7, "delayIn", int(1500 * 8 / (64.0/1024.0) / 1000)) # rx delay at 64kbps in ms
313         instance.defer_add_trace(7, "netpipeStats")
314         instance.defer_connect(2, "pipes", 7, "node")
315         instance.defer_create(8, "Application")
316         instance.defer_create_set(8, "command", "time wget -q -O /dev/null http://www.google.com/") # Fetch ~10kb
317         instance.defer_add_trace(8, "stdout")
318         instance.defer_add_trace(8, "stderr")
319         instance.defer_connect(8, "node", 2, "apps")
320
321         try:
322             instance.do_setup()
323             instance.do_create()
324             instance.do_connect_init()
325             instance.do_connect_compl()
326             instance.do_preconfigure()
327             instance.do_configure()
328             
329             instance.do_prestart()
330             instance.start()
331             while instance.status(8) != AS.STATUS_FINISHED:
332                 time.sleep(0.5)
333             test_result = (instance.trace(8, "stderr") or "").strip()
334             comp_result = r".*real\s*(?P<min>[0-9]+)m(?P<sec>[0-9]+[.][0-9]+)s.*"
335             netpipe_stats = instance.trace(7, "netpipeStats")
336             
337             instance.stop()
338         finally:
339             try:
340                 instance.shutdown()
341             except:
342                 pass
343
344         # asserts at the end, to make sure there's proper cleanup
345         match = re.match(comp_result, test_result, re.MULTILINE)
346         self.assertTrue(match, "Unexpected output: %s" % (test_result,))
347         
348         minutes = int(match.group("min"))
349         seconds = float(match.group("sec"))
350         self.assertTrue((minutes * 60 + seconds) > 1.0, "Emulation not effective: %s" % (test_result,))
351
352         self.assertTrue(netpipe_stats, "Unavailable netpipe stats")
353
354     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
355     def _pingtest(self, TunClass, ConnectionProto, Cipher, Filter1=None, Filter2=None, Filter1args=None, Filter2args=None, PLREX=None):
356         instance = self.make_instance()
357         
358         instance.defer_create(2, "Node")
359         instance.defer_create_set(2, "hostname", self.host1)
360         instance.defer_create(3, "Node")
361         instance.defer_create_set(3, "hostname", self.host2)
362         instance.defer_create(4, "NodeInterface")
363         instance.defer_connect(2, "devs", 4, "node")
364         instance.defer_create(5, "Internet")
365         instance.defer_connect(4, "inet", 5, "devs")
366         instance.defer_create(6, "NodeInterface")
367         instance.defer_connect(3, "devs", 6, "node")
368         instance.defer_connect(6, "inet", 5, "devs")
369         instance.defer_create(7, TunClass)
370         instance.defer_create_set(7, "tun_cipher", Cipher)
371         instance.defer_add_trace(7, "packets")
372         instance.defer_add_address(7, self.net_prefix+".2", 24, False)
373         instance.defer_connect(2, "devs", 7, "node")
374         instance.defer_create(8, TunClass)
375         instance.defer_create_set(8, "tun_cipher", Cipher)
376         instance.defer_add_trace(8, "packets")
377         instance.defer_add_address(8, self.net_prefix+".3", 24, False)
378         instance.defer_connect(3, "devs", 8, "node")
379         instance.defer_create(9, "Application")
380         instance.defer_create_set(9, "command", "ping -qc10 {#[GUID-8].addr[0].[Address]#}")
381         instance.defer_add_trace(9, "stdout")
382         instance.defer_add_trace(9, "stderr")
383         instance.defer_connect(9, "node", 2, "apps")
384         
385         if Filter1:
386             instance.defer_create(10, "TunFilter")
387             instance.defer_create_set(10, "module", Filter1)
388             if Filter1args:
389                 instance.defer_create_set(10, "args", Filter1args)
390             instance.defer_connect(7, "fd->", 10, "->fd")
391             
392         if Filter2:
393             instance.defer_create(11, "TunFilter")
394             instance.defer_create_set(11, "module", Filter2)
395             if Filter2args:
396                 instance.defer_create_set(11, "args", Filter2args)
397             instance.defer_connect(8, "fd->", 11, "->fd")
398
399         if PLREX is None:
400             if Filter1 and Filter2:
401                 plr = "[5-9][0-9]"
402             elif Filter1 or Filter2:
403                 plr = "[3-9][0-9]"
404             else:
405                 plr = "0"
406         else:
407             plr = PLREX
408        
409         instance.defer_connect(
410             (10 if Filter1 else 7), ConnectionProto, 
411             (11 if Filter2 else 8), ConnectionProto)
412
413         comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
414
415 --- .* ping statistics ---
416 10 packets transmitted, [0-9]+ received,.* %s%% packet loss, time \d*ms.*
417 """ % (plr,)
418
419         try:
420             instance.do_setup()
421             instance.do_create()
422             instance.do_connect_init()
423             instance.do_connect_compl()
424             instance.do_preconfigure()
425             
426             # Manually replace netref
427             instance.set(9, "command",
428                 instance.get(9, "command")
429                     .replace("{#[GUID-8].addr[0].[Address]#}", 
430                         instance.get_address(8, 0, "Address") )
431             )
432             
433             instance.do_configure()
434             
435             instance.do_prestart()
436             instance.start()
437             while instance.status(9) != AS.STATUS_FINISHED:
438                 time.sleep(0.5)
439             ping_result = instance.trace(9, "stdout") or ""
440             packets1 = instance.trace(7, "packets") or ""
441             packets2 = instance.trace(8, "packets") or ""
442             instance.stop()
443         finally:
444             try:
445                 instance.shutdown()
446             except:
447                 pass
448
449         # asserts at the end, to make sure there's proper cleanup
450         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
451             "Unexpected trace:\n%s\nPackets @ source:\n%s\nPackets @ target:\n%s" % (
452                 ping_result,
453                 packets1,
454                 packets2))
455
456     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
457     def test_tun_ping(self):
458         self._pingtest("TunInterface", "tcp", "AES")
459
460     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
461     def test_tun_ping_udp(self):
462         self._pingtest("TunInterface", "udp", "AES")
463
464     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
465     def test_tun_ping_gre(self):
466         self._pingtest("TunInterface", "gre", "PLAIN")
467
468     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
469     def test_tap_ping(self):
470         self._pingtest("TapInterface", "tcp", "AES")
471
472     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
473     def test_tap_ping_udp(self):
474         self._pingtest("TapInterface", "udp", "AES")
475
476     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
477     def test_tap_ping_gre(self):
478         self._pingtest("TapInterface", "gre", "PLAIN")
479
480     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
481     def test_tap_ping_udp_loss1_py(self):
482         self._pingtest("TapInterface", "udp", "AES", self.PLR50_PY, None, "plr=50")
483
484     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
485     def test_tap_ping_udp_loss2_py(self):
486         self._pingtest("TapInterface", "udp", "AES", self.PLR50_PY, self.PLR50_PY, "plr=40", "plr=40")
487
488     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
489     def test_tap_ping_udp_loss1_c(self):
490         self._pingtest("TapInterface", "udp", "AES", self.PLR50_C, None, "plr=50")
491
492     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
493     def test_tap_ping_udp_loss2_c(self):
494         self._pingtest("TapInterface", "udp", "AES", self.PLR50_C, self.PLR50_C, "plr=40", "plr=40")
495
496     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
497     def test_tap_ping_udp_tos(self):
498         self._pingtest("TunInterface", "udp", "AES", self.TOS_PY, self.TOS_PY, "size=1000", "size=1000", "0")
499
500     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
501     def test_nepi_depends(self):
502         instance = self.make_instance()
503         
504         instance.defer_create(2, "Node")
505         instance.defer_create_set(2, "hostname", self.host1)
506         instance.defer_create(3, "NodeInterface")
507         instance.defer_connect(2, "devs", 3, "node")
508         instance.defer_create(4, "Internet")
509         instance.defer_connect(3, "inet", 4, "devs")
510         instance.defer_create(5, "NepiDependency")
511         instance.defer_connect(5, "node", 2, "deps")
512         instance.defer_create(12, "Application")
513         instance.defer_connect(12, "node", 2, "apps")
514         instance.defer_create_set(12, "command", "python -c 'import nepi'")
515         instance.defer_add_trace(12, "stderr")
516
517         try:
518             instance.do_setup()
519             instance.do_create()
520             instance.do_connect_init()
521             instance.do_connect_compl()
522             instance.do_preconfigure()
523             instance.do_configure()
524             
525             instance.do_prestart()
526             instance.start()
527             while instance.status(12) != AS.STATUS_FINISHED:
528                 time.sleep(0.5)
529             ping_result = (instance.trace(12, "stderr") or "").strip()
530             instance.stop()
531         finally:
532             try:
533                 instance.shutdown()
534             except:
535                 pass
536         
537         # asserts at the end, to make sure there's proper cleanup
538         self.assertEqual(ping_result, "")
539
540     @test_util.skipUnless(test_util.pl_auth() is not None, 
541         "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
542     @test_util.skipUnless(os.environ.get('NEPI_FULL_TESTS','').lower() in ('1','yes','true','on'),
543         "Test is expensive, requires NEPI_FULL_TESTS=yes")
544     def test_ns3_depends(self):
545         instance = self.make_instance()
546         
547         instance.defer_create(2, "Node")
548         instance.defer_create_set(2, "hostname", self.host1)
549         instance.defer_create(3, "NodeInterface")
550         instance.defer_connect(2, "devs", 3, "node")
551         instance.defer_create(4, "Internet")
552         instance.defer_connect(3, "inet", 4, "devs")
553         instance.defer_create(5, "NepiDependency")
554         instance.defer_connect(5, "node", 2, "deps")
555         instance.defer_create(6, "NS3Dependency")
556         instance.defer_connect(6, "node", 2, "deps")
557         instance.defer_create(12, "Application")
558         instance.defer_connect(12, "node", 2, "apps")
559         instance.defer_create_set(12, "command", "python -c 'import nepi.testbeds.ns3.execute ; tb = nepi.testbeds.ns3.execute.TestbedController() ; mod = tb._configure_ns3_module()'")
560         instance.defer_add_trace(12, "stderr")
561
562         try:
563             instance.do_setup()
564             instance.do_create()
565             instance.do_connect_init()
566             instance.do_connect_compl()
567             instance.do_preconfigure()
568             instance.do_configure()
569             
570             instance.do_prestart()
571             instance.start()
572             while instance.status(12) != AS.STATUS_FINISHED:
573                 time.sleep(0.5)
574             ping_result = (instance.trace(12, "stderr") or "").strip()
575             instance.stop()
576         finally:
577             try:
578                 instance.shutdown()
579             except:
580                 pass
581         
582         # asserts at the end, to make sure there's proper cleanup
583         self.assertEqual(ping_result, "")
584
585     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
586     def test_discovery(self):
587         instance = self.make_instance()
588         
589         instance.defer_create(2, "Node")
590         instance.defer_create_set(2, "operatingSystem", "f12")
591         instance.defer_create(3, "Node")
592         instance.defer_create_set(3, "operatingSystem", "f12")
593         instance.defer_create(4, "NodeInterface")
594         instance.defer_connect(2, "devs", 4, "node")
595         instance.defer_create(5, "NodeInterface")
596         instance.defer_connect(3, "devs", 5, "node")
597         instance.defer_create(6, "Internet")
598         instance.defer_connect(4, "inet", 6, "devs")
599         instance.defer_connect(5, "inet", 6, "devs")
600         instance.defer_create(7, "Application")
601         instance.defer_create_set(7, "command", "ping -qc1 {#[GUID-5].addr[0].[Address]#}")
602         instance.defer_add_trace(7, "stdout")
603         instance.defer_add_trace(7, "stderr")
604         instance.defer_connect(7, "node", 2, "apps")
605
606         comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
607
608 --- .* ping statistics ---
609 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
610 """
611
612         try:
613             instance.do_setup()
614             instance.do_create()
615             instance.do_connect_init()
616             instance.do_connect_compl()
617             instance.do_preconfigure()
618             
619             # Manually replace netref
620             instance.set(7, "command",
621                 instance.get(7, "command")
622                     .replace("{#[GUID-5].addr[0].[Address]#}", 
623                         instance.get_address(5, 0, "Address") )
624             )
625
626             instance.do_configure()
627             
628             instance.do_prestart()
629             instance.start()
630             while instance.status(7) != AS.STATUS_FINISHED:
631                 time.sleep(0.5)
632             ping_result = instance.trace(7, "stdout") or ""
633             instance.stop()
634         finally:
635             try:
636                 instance.shutdown()
637             except:
638                 pass
639
640         # asserts at the end, to make sure there's proper cleanup
641         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
642             "Unexpected trace:\n" + ping_result)
643         
644         
645
646 if __name__ == '__main__':
647     unittest.main()
648