A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
python-unit-tests.py
Go to the documentation of this file.
1#! /usr/bin/env python3
2
3# Copyright (C) 2008-2011 INESC Porto
4
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19# Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
20
21import unittest
22
23try:
24 from ns import ns
25except ModuleNotFoundError:
26 raise SystemExit(
27 "Error: ns3 Python module not found;"
28 " Python bindings may not be enabled"
29 " or your PYTHONPATH might not be properly configured"
30 )
31import sys
32
33UINT32_MAX = 0xFFFFFFFF
34
35
36
37class TestSimulator(unittest.TestCase):
38
46
47 def testScheduleNow(self):
48 """! Test schedule now
49 @param self this object
50 @return None
51 """
52
53 def callback(args: ns.cppyy.gbl.std.vector) -> None:
54 """! Callback function
55 @param args arguments
56 @return None
57 """
58 self._args_received = list(map(lambda x: x.decode("utf-8"), args))
59 self._cb_time = ns.Simulator.Now()
60
61 ns.Simulator.Destroy()
62 self._args_received = None
63 self._cb_time = None
64 ns.cppyy.cppdef(
65 """
66 EventImpl* pythonMakeEvent(void (*f)(std::vector<std::string>), std::vector<std::string> l)
67 {
68 return MakeEvent(f, l);
69 }
70 """
71 )
72 event = ns.cppyy.gbl.pythonMakeEvent(callback, sys.argv)
73 ns.Simulator.ScheduleNow(event)
74 ns.Simulator.Run()
75 self.assertListEqual(self._args_received, sys.argv)
76 self.assertEqual(self._cb_time.GetSeconds(), 0.0)
77
78 def testSchedule(self):
79 """! Test schedule
80 @param self this object
81 @return None
82 """
83
84 def callback(args: ns.cppyy.gbl.std.vector):
85 """! Callback function
86 @param args arguments
87 @return None
88 """
89 self._args_received = list(map(lambda x: x.decode("utf-8"), args))
90 self._cb_time = ns.Simulator.Now()
91
92 ns.Simulator.Destroy()
93 self._args_received = None
94 self._cb_time = None
95 ns.cppyy.cppdef(
96 """
97 EventImpl* pythonMakeEvent2(void (*f)(std::vector<std::string>), std::vector<std::string> l)
98 {
99 return MakeEvent(f, l);
100 }
101 """
102 )
103 event = ns.cppyy.gbl.pythonMakeEvent2(callback, sys.argv)
104 ns.Simulator.Schedule(ns.Seconds(123), event)
105 ns.Simulator.Run()
106 self.assertListEqual(self._args_received, sys.argv)
107 self.assertEqual(self._cb_time.GetSeconds(), 123.0)
108
110 """! Test schedule destroy
111 @param self this object
112 @return None
113 """
114
115 def callback(args: ns.cppyy.gbl.std.vector):
116 """! Callback function
117 @param args
118 @return None
119 """
120 self._args_received = list(map(lambda x: x.decode("utf-8"), args))
121 self._cb_time = ns.Simulator.Now()
122
123 ns.Simulator.Destroy()
124 self._args_received = None
125 self._cb_time = None
126 ns.cppyy.cppdef("void null(){ return; }")
127 ns.Simulator.Schedule(ns.Seconds(123), ns.cppyy.gbl.null)
128 ns.cppyy.cppdef(
129 """
130 EventImpl* pythonMakeEvent3(void (*f)(std::vector<std::string>), std::vector<std::string> l)
131 {
132 return MakeEvent(f, l);
133 }
134 """
135 )
136 event = ns.cppyy.gbl.pythonMakeEvent3(callback, sys.argv)
137 ns.Simulator.ScheduleDestroy(event)
138 ns.Simulator.Run()
139 ns.Simulator.Destroy()
140 self.assertListEqual(self._args_received, sys.argv)
141 self.assertEqual(self._cb_time.GetSeconds(), 123.0)
142
144 """! Test schedule with context
145 @param self this object
146 @return None
147 """
148
149 def callback(context, args: ns.cppyy.gbl.std.vector):
150 """! Callback
151 @param context the context
152 @param args the arguments
153 @return None
154 """
155 self._context_received = context
156 self._args_received = list(map(lambda x: x.decode("utf-8"), args))
157 self._cb_time = ns.Simulator.Now()
158
159 ns.Simulator.Destroy()
160 self._args_received = None
161 self._cb_time = None
162 self._context_received = None
163 ns.cppyy.cppdef(
164 """
165 EventImpl* pythonMakeEvent4(void (*f)(uint32_t, std::vector<std::string>), uint32_t context, std::vector<std::string> l)
166 {
167 return MakeEvent(f, context, l);
168 }
169 """
170 )
171 event = ns.cppyy.gbl.pythonMakeEvent4(callback, 54321, sys.argv)
172 ns.Simulator.ScheduleWithContext(54321, ns.Seconds(123), event)
173 ns.Simulator.Run()
174 self.assertEqual(self._context_received, 54321)
175 self.assertListEqual(self._args_received, sys.argv)
176 self.assertEqual(self._cb_time.GetSeconds(), 123.0)
177
179 """! Test time comparison
180 @param self this object
181 @return None
182 """
183 self.assertTrue(ns.Seconds(123) == ns.Seconds(123))
184 self.assertTrue(ns.Seconds(123) >= ns.Seconds(123))
185 self.assertTrue(ns.Seconds(123) <= ns.Seconds(123))
186 self.assertTrue(ns.Seconds(124) > ns.Seconds(123))
187 self.assertTrue(ns.Seconds(123) < ns.Seconds(124))
188
190 """! Test numeric operations
191 @param self this object
192 @return None
193 """
194 self.assertEqual(ns.Seconds(10) + ns.Seconds(5), ns.Seconds(15))
195 self.assertEqual(ns.Seconds(10) - ns.Seconds(5), ns.Seconds(5))
196
197 v1 = ns.int64x64_t(5.0) * ns.int64x64_t(10)
198 self.assertEqual(v1, ns.int64x64_t(50))
199
200 def testConfig(self):
201 """! Test configuration
202 @param self this object
203 @return None
204 """
205 ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
206 # hm.. no Config.Get?
207
208 def testSocket(self):
209 """! Test socket
210 @param self
211 @return None
212 """
213 nc = ns.NodeContainer(1)
214 node = nc.Get(0)
215 internet = ns.CreateObject("InternetStackHelper")
216 internet.Install(node)
218
219 def python_rx_callback(socket) -> None:
220 self._received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0)
221
222 ns.cppyy.cppdef(
223 """
224 Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback_test_socket(void(*func)(Ptr<Socket>))
225 {
226 return MakeCallback(func);
227 }
228 """
229 )
230
231 sink = ns.network.Socket.CreateSocket(
232 node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
233 )
234 sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
235 sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
236
237 source = ns.network.Socket.CreateSocket(
238 node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
239 )
240 source.SendTo(
241 ns.network.Packet(19),
242 0,
243 ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo(),
244 )
245
246 ns.Simulator.Run()
247 self.assertTrue(self._received_packet is not None)
248 self.assertEqual(self._received_packet.GetSize(), 19)
249
250 # Delete Ptr<>'s on the python side to let C++ clean them
251 del internet
252
253 def testAttributes(self):
254 """! Test attributes function
255 @param self this object
256 @return None
257 """
258 # Templated class DropTailQueue<Packet> in C++
259 queue = ns.CreateObject("DropTailQueue<Packet>")
260 queueSizeValue = ns.network.QueueSizeValue(ns.network.QueueSize("500p"))
261 queue.SetAttribute("MaxSize", queueSizeValue)
262
263 limit = ns.network.QueueSizeValue()
264 queue.GetAttribute("MaxSize", limit)
265 self.assertEqual(limit.Get(), ns.network.QueueSize("500p"))
266
267
268 mobility = ns.CreateObject("RandomWaypointMobilityModel")
269 ptr = ns.CreateObject("PointerValue")
270 mobility.GetAttribute("PositionAllocator", ptr)
271 self.assertEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
272
273 pos = ns.mobility.ListPositionAllocator()
274 ptr.SetObject(pos)
275 mobility.SetAttribute("PositionAllocator", ptr)
276
277 ptr2 = ns.CreateObject("PointerValue")
278 mobility.GetAttribute("PositionAllocator", ptr2)
279 self.assertNotEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
280
281 # Delete Ptr<>'s on the python side to let C++ clean them
282 del queue, mobility, ptr, ptr2
283
284 def testIdentity(self):
285 """! Test identify
286 @param self this object
287 @return None
288 """
289 csma = ns.CreateObject("CsmaNetDevice")
290 channel = ns.CreateObject("CsmaChannel")
291 csma.Attach(channel)
292
293 c1 = csma.GetChannel()
294 c2 = csma.GetChannel()
295
296 self.assertEqual(c1, c2)
297
298 # Delete Ptr<>'s on the python side to let C++ clean them
299 del csma, channel
300
301 def testTypeId(self):
302 """! Test type ID
303 @param self this object
304 @return None
305 """
306 ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory")
307 self.assertTrue(ok)
308 self.assertEqual(typeId1.GetName(), "ns3::UdpSocketFactory")
309
310 ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
311 self.assertFalse(ok)
312
314 """! Test command line
315 @param self this object
316 @return None
317 """
318 from ctypes import c_bool, c_char_p, c_double, c_int, create_string_buffer
319
320 test1 = c_bool(True)
321 test2 = c_int(42)
322 test3 = c_double(3.1415)
323 BUFFLEN = 40 # noqa
324 test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
325 test4 = c_char_p(test4Buffer.raw)
326
327 cmd = ns.core.CommandLine(__file__)
328 cmd.AddValue("Test1", "this is a test option", test1)
329 cmd.AddValue("Test2", "this is a test option", test2)
330 cmd.AddValue["double"]("Test3", "this is a test option", test3)
331 cmd.AddValue("Test4", "this is a test option", test4, BUFFLEN)
332
333 cmd.Parse(["python"])
334 self.assertEqual(test1.value, True)
335 self.assertEqual(test2.value, 42)
336 self.assertEqual(test3.value, 3.1415)
337 self.assertEqual(test4.value, b"this is a test option")
338
339 cmd.Parse(["python", "--Test1=false", "--Test2=0", "--Test3=0.0"])
340 self.assertEqual(test1.value, False)
341 self.assertEqual(test2.value, 0)
342 self.assertEqual(test3.value, 0.0)
343
344 cmd.Parse(["python", "--Test4=new_string"])
345 self.assertEqual(test4.value, b"new_string")
346
347 def testSubclass(self):
348 """! Test subclass
349 @param self this object
350 @return None
351 """
352
353
354 class MyNode(ns.network.Node):
355 def GetLocalTime(self) -> ns.Time:
356 return ns.Seconds(10)
357
358 node = MyNode()
359 forced_local_time = node.GetLocalTime()
360 self.assertEqual(forced_local_time, ns.Seconds(10))
361 del node
362
364 """! Test python-based application
365 @param self this object
366 @return None
367 """
368 ns.Simulator.Destroy()
369
370 nodes = ns.network.NodeContainer()
371 nodes.Create(2)
372
373 pointToPoint = ns.point_to_point.PointToPointHelper()
374 pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
375 pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
376
377 devices = pointToPoint.Install(nodes)
378
379 stack = ns.internet.InternetStackHelper()
380 stack.Install(nodes)
381
382 address = ns.internet.Ipv4AddressHelper()
383 address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
384
385 interfaces = address.Assign(devices)
386
387 ns.cppyy.cppdef(
388 """
389 namespace ns3
390 {
391 Callback<void,Ptr<Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
392 {
393 return MakeCallback(func);
394 }
395 EventImpl* pythonMakeEventSend(void (*f)(Ptr<Socket>, Ptr<Packet>, Address&), Ptr<Socket> socket, Ptr<Packet> packet, Address address)
396 {
397 return MakeEvent(f, socket, packet, address);
398 }
399 }
400 """
401 )
402
403
404 class EchoServer(ns.applications.Application):
405 LOGGING = False
406 ECHO_PORT = 1234
407 socketToInstanceDict = {}
408
409 def __init__(self, node: ns.Node, port=ECHO_PORT):
410 """! Constructor needs to call first the constructor to Application (super class)
411 @param self this object
412 @param node node where this application will be executed
413 @param port port to listen
414 return None
415 """
416 super().__init__()
417
418 self.__python_owns__ = False # Let C++ destroy this on Simulator::Destroy
419
420 self.port = port
421
422 self.m_socket = ns.network.Socket.CreateSocket(
423 node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
424 )
425 self.m_socket.Bind(
426 ns.network.InetSocketAddress(
427 ns.network.Ipv4Address.GetAny(), self.port
428 ).ConvertTo()
429 )
430 self.m_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
431 EchoServer.socketToInstanceDict[self.m_socket] = self
432
433 def __del__(self):
434 """! Destructor
435 @param self this object
436 return None
437 """
438 del EchoServer.socketToInstanceDict[self.m_socket]
439
440 def Send(self, packet: ns.Packet, address: ns.Address) -> None:
441 """! Function to send a packet to an address
442 @param self this object
443 @param packet packet to send
444 @param address destination address
445 return None
446 """
447 self.m_socket.SendTo(packet, 0, address)
448 if EchoServer.LOGGING:
449 inetAddress = ns.InetSocketAddress.ConvertFrom(address)
450 print(
451 "At time +{s}s server sent {b} bytes from {ip} port {port}".format(
452 s=ns.Simulator.Now().GetSeconds(),
453 b=packet.__deref__().GetSize(),
454 ip=inetAddress.GetIpv4(),
455 port=inetAddress.GetPort(),
456 ),
457 file=sys.stderr,
458 flush=True,
459 )
460
461 def Receive(self):
462 """! Function to receive a packet from an address
463 @param self this object
464 @return None
465 """
466 address = ns.Address()
467 packet = self.m_socket.RecvFrom(address)
468 if EchoServer.LOGGING:
469 inetAddress = ns.InetSocketAddress.ConvertFrom(address)
470 print(
471 "At time +{s}s server received {b} bytes from {ip} port {port}".format(
472 s=ns.Simulator.Now().GetSeconds(),
473 b=packet.__deref__().GetSize(),
474 ip=inetAddress.GetIpv4(),
475 port=inetAddress.GetPort(),
476 ),
477 file=sys.stderr,
478 flush=True,
479 )
480 event = ns.pythonMakeEventSend(EchoServer._Send, self.m_socket, packet, address)
481 ns.Simulator.Schedule(ns.Seconds(1), event)
482
483 @staticmethod
484 def _Send(socket: ns.Socket, packet: ns.Packet, address: ns.Address):
485 """! Static send function, which matches the output socket
486 to the EchoServer instance to call the instance Send function
487 @param socket socket from the instance that should send the packet
488 @param packet packet to send
489 @param address destination address
490 return None
491 """
492 instance = EchoServer.socketToInstanceDict[socket]
493 instance.Send(packet, address)
494
495 @staticmethod
496 def _Receive(socket: ns.Socket) -> None:
497 """! Static receive function, which matches the input socket
498 to the EchoServer instance to call the instance Receive function
499 @param socket socket from the instance that should receive the packet
500 return None
501 """
502 instance = EchoServer.socketToInstanceDict[socket]
503 instance.Receive()
504
505 echoServer = EchoServer(nodes.Get(1))
506 nodes.Get(1).AddApplication(echoServer)
507
508 serverApps = ns.ApplicationContainer()
509 serverApps.Add(echoServer)
510 serverApps.Start(ns.core.Seconds(1.0))
511 serverApps.Stop(ns.core.Seconds(10.0))
512
513 address = interfaces.GetAddress(1).ConvertTo()
514 echoClient = ns.applications.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
515 echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(10))
516 echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
517 echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(101))
518
519 clientApps = echoClient.Install(nodes.Get(0))
520 clientApps.Start(ns.core.Seconds(2.0))
521 clientApps.Stop(ns.core.Seconds(10.0))
522
523 ns.Simulator.Run()
524 ns.Simulator.Destroy()
525
526
527if __name__ == "__main__":
528 unittest.main(verbosity=1, failfast=True)
def testScheduleDestroy(self)
Test schedule destroy.
port
Listen port for the server.
def testCommandLine(self)
Test command line.
def testTimeNumericOperations(self)
Test numeric operations.
def testEchoServerApplication(self)
Test python-based application.
__python_owns__
EchoServer application class.
def testScheduleNow(self)
Test schedule now.
def testTypeId(self)
Test type ID.
def testSubclass(self)
Test subclass.
def testSchedule(self)
Test schedule.
def testScheduleWithContext(self)
Test schedule with context.
def testAttributes(self)
Test attributes function.
def testSocket(self)
Test socket.
def testTimeComparison(self)
Test time comparison.
def testConfig(self)
Test configuration.
m_socket
Socket used by the server to listen to port.
def testIdentity(self)
Test identify.
static void Send(Ptr< NetDevice > dev, int level, std::string emuMode)
Definition: fd-emu-send.cc:54
#define list