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## TestSimulator class
37class TestSimulator(unittest.TestCase):
38 ## @var _received_packet
39 # received packet
40 ## @var _args_received
41 # args
42 ## @var _cb_time
43 # current time
44 ## @var _context_received
45 # context
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.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.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.Socket.CreateSocket(node, ns.TypeId.LookupByName("ns3::UdpSocketFactory"))
232 sink.Bind(ns.InetSocketAddress(ns.Ipv4Address.GetAny(), 80).ConvertTo())
233 sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
234
235 source = ns.Socket.CreateSocket(node, ns.TypeId.LookupByName("ns3::UdpSocketFactory"))
236 source.SendTo(
237 ns.Packet(19),
238 0,
239 ns.InetSocketAddress(ns.Ipv4Address("127.0.0.1"), 80).ConvertTo(),
240 )
241
242 ns.Simulator.Run()
243 self.assertTrue(self._received_packet is not None)
244 self.assertEqual(self._received_packet.GetSize(), 19)
245
246 # Delete Ptr<>'s on the python side to let C++ clean them
247 del internet
248
249 def testAttributes(self):
250 """! Test attributes function
251 @param self this object
252 @return None
253 """
254 # Templated class DropTailQueue[ns.Packet] in C++
255 queue = ns.CreateObject[ns.DropTailQueue[ns.Packet]]()
256 queueSizeValue = ns.QueueSizeValue(ns.QueueSize("500p"))
257 queue.SetAttribute("MaxSize", queueSizeValue)
258
259 limit = ns.QueueSizeValue()
260 queue.GetAttribute("MaxSize", limit)
261 self.assertEqual(limit.Get(), ns.QueueSize("500p"))
262
263 ## -- object pointer values
264 mobility = ns.CreateObject[ns.RandomWaypointMobilityModel]()
265 ptr = ns.PointerValue()
266 mobility.GetAttribute("PositionAllocator", ptr)
267 self.assertEqual(ptr.GetObject(), ns.Ptr["Object"](ns.cppyy.nullptr))
268
269 pos = ns.ListPositionAllocator()
270 ptr.SetObject(pos)
271 mobility.SetAttribute("PositionAllocator", ptr)
272
273 ptr2 = ns.PointerValue()
274 mobility.GetAttribute("PositionAllocator", ptr2)
275 self.assertNotEqual(ptr.GetObject(), ns.Ptr["Object"](ns.cppyy.nullptr))
276
277 # Delete Ptr<>'s on the python side to let C++ clean them
278 del queue, mobility, ptr, ptr2
279
280 def testIdentity(self):
281 """! Test identify
282 @param self this object
283 @return None
284 """
285 csma = ns.CreateObject[ns.CsmaNetDevice]()
286 channel = ns.CreateObject[ns.CsmaChannel]()
287 csma.Attach(channel)
288
289 c1 = csma.GetChannel()
290 c2 = csma.GetChannel()
291
292 self.assertEqual(c1, c2)
293
294 # Delete Ptr<>'s on the python side to let C++ clean them
295 del csma, channel
296
297 def testTypeId(self):
298 """! Test type ID
299 @param self this object
300 @return None
301 """
302 ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory")
303 self.assertTrue(ok)
304 self.assertEqual(typeId1.GetName(), "ns3::UdpSocketFactory")
305
306 ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
307 self.assertFalse(ok)
308
310 """! Test command line
311 @param self this object
312 @return None
313 """
314 from ctypes import c_bool, c_char_p, c_double, c_int, create_string_buffer
315
316 test1 = c_bool(True)
317 test2 = c_int(42)
318 test3 = c_double(3.1415)
319 BUFFLEN = 40 # noqa
320 test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
321 test4 = c_char_p(test4Buffer.raw)
322
323 cmd = ns.CommandLine(__file__)
324 cmd.AddValue("Test1", "this is a test option", test1)
325 cmd.AddValue("Test2", "this is a test option", test2)
326 cmd.AddValue["double"]("Test3", "this is a test option", test3)
327 cmd.AddValue("Test4", "this is a test option", test4, BUFFLEN)
328
329 cmd.Parse(["python"])
330 self.assertEqual(test1.value, True)
331 self.assertEqual(test2.value, 42)
332 self.assertEqual(test3.value, 3.1415)
333 self.assertEqual(test4.value, b"this is a test option")
334
335 cmd.Parse(["python", "--Test1=false", "--Test2=0", "--Test3=0.0"])
336 self.assertEqual(test1.value, False)
337 self.assertEqual(test2.value, 0)
338 self.assertEqual(test3.value, 0.0)
339
340 cmd.Parse(["python", "--Test4=new_string"])
341 self.assertEqual(test4.value, b"new_string")
342
343 def testSubclass(self):
344 """! Test subclass
345 @param self this object
346 @return None
347 """
348
349 ## MyNode class
350 class MyNode(ns.Node):
351 def GetLocalTime(self) -> ns.Time:
352 return ns.Seconds(10)
353
354 node = MyNode()
355 forced_local_time = node.GetLocalTime()
356 self.assertEqual(forced_local_time, ns.Seconds(10))
357 del node
358
360 """! Test python-based application
361 @param self this object
362 @return None
363 """
364 ns.Simulator.Destroy()
365
366 nodes = ns.NodeContainer()
367 nodes.Create(2)
368
369 pointToPoint = ns.PointToPointHelper()
370 pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
371 pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
372
373 devices = pointToPoint.Install(nodes)
374
375 stack = ns.InternetStackHelper()
376 stack.Install(nodes)
377
378 address = ns.Ipv4AddressHelper()
379 address.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
380
381 interfaces = address.Assign(devices)
382
383 ns.cppyy.cppdef(
384 """
385 namespace ns3
386 {
387 Callback<void,Ptr<Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
388 {
389 return MakeCallback(func);
390 }
391 EventImpl* pythonMakeEventSend(void (*f)(Ptr<Socket>, Ptr<Packet>, Address&), Ptr<Socket> socket, Ptr<Packet> packet, Address address)
392 {
393 return MakeEvent(f, socket, packet, address);
394 }
395 }
396 """
397 )
398
399 ## EchoServer application class
400 class EchoServer(ns.Application):
401 LOGGING = False
402 ECHO_PORT = 1234
403 socketToInstanceDict = {}
404
405 def __init__(self, node: ns.Node, port=ECHO_PORT):
406 """! Constructor needs to call first the constructor to Application (super class)
407 @param self this object
408 @param node node where this application will be executed
409 @param port port to listen
410 return None
411 """
412 super().__init__()
413 ## __python_owns__ flag indicates that Cppyy should not manage the lifetime of this variable
414 self.__python_owns__ = False # Let C++ destroy this on Simulator::Destroy
415 ## Listen port for the server
416 self.port = port
417 ## Socket used by the server to listen to port
418 self.m_socket = ns.Socket.CreateSocket(
419 node, ns.TypeId.LookupByName("ns3::UdpSocketFactory")
420 )
421 self.m_socket.Bind(
422 ns.InetSocketAddress(ns.Ipv4Address.GetAny(), self.port).ConvertTo()
423 )
424 self.m_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
425 EchoServer.socketToInstanceDict[self.m_socket] = self
426
427 def __del__(self):
428 """! Destructor
429 @param self this object
430 return None
431 """
432 del EchoServer.socketToInstanceDict[self.m_socket]
433
434 def Send(self, packet: ns.Packet, address: ns.Address) -> None:
435 """! Function to send a packet to an address
436 @param self this object
437 @param packet packet to send
438 @param address destination address
439 return None
440 """
441 self.m_socket.SendTo(packet, 0, address)
442 if EchoServer.LOGGING:
443 inetAddress = ns.InetSocketAddress.ConvertFrom(address)
444 print(
445 "At time +{s}s server sent {b} bytes from {ip} port {port}".format(
446 s=ns.Simulator.Now().GetSeconds(),
447 b=packet.__deref__().GetSize(),
448 ip=inetAddress.GetIpv4(),
449 port=inetAddress.GetPort(),
450 ),
451 file=sys.stderr,
452 flush=True,
453 )
454
455 def Receive(self):
456 """! Function to receive a packet from an address
457 @param self this object
458 @return None
459 """
460 address = ns.Address()
461 packet = self.m_socket.RecvFrom(address)
462 if EchoServer.LOGGING:
463 inetAddress = ns.InetSocketAddress.ConvertFrom(address)
464 print(
465 "At time +{s}s server received {b} bytes from {ip} port {port}".format(
466 s=ns.Simulator.Now().GetSeconds(),
467 b=packet.__deref__().GetSize(),
468 ip=inetAddress.GetIpv4(),
469 port=inetAddress.GetPort(),
470 ),
471 file=sys.stderr,
472 flush=True,
473 )
474 event = ns.pythonMakeEventSend(EchoServer._Send, self.m_socket, packet, address)
475 ns.Simulator.Schedule(ns.Seconds(1), event)
476
477 @staticmethod
478 def _Send(socket: ns.Socket, packet: ns.Packet, address: ns.Address):
479 """! Static send function, which matches the output socket
480 to the EchoServer instance to call the instance Send function
481 @param socket socket from the instance that should send the packet
482 @param packet packet to send
483 @param address destination address
484 return None
485 """
486 instance = EchoServer.socketToInstanceDict[socket]
487 instance.Send(packet, address)
488
489 @staticmethod
490 def _Receive(socket: ns.Socket) -> None:
491 """! Static receive function, which matches the input socket
492 to the EchoServer instance to call the instance Receive function
493 @param socket socket from the instance that should receive the packet
494 return None
495 """
496 instance = EchoServer.socketToInstanceDict[socket]
497 instance.Receive()
498
499 echoServer = EchoServer(nodes.Get(1))
500 nodes.Get(1).AddApplication(echoServer)
501
502 serverApps = ns.ApplicationContainer()
503 serverApps.Add(echoServer)
504 serverApps.Start(ns.Seconds(1.0))
505 serverApps.Stop(ns.Seconds(10.0))
506
507 address = interfaces.GetAddress(1).ConvertTo()
508 echoClient = ns.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
509 echoClient.SetAttribute("MaxPackets", ns.UintegerValue(10))
510 echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
511 echoClient.SetAttribute("PacketSize", ns.UintegerValue(101))
512
513 clientApps = echoClient.Install(nodes.Get(0))
514 clientApps.Start(ns.Seconds(2.0))
515 clientApps.Stop(ns.Seconds(10.0))
516
517 ns.Simulator.Run()
518 ns.Simulator.Destroy()
519
520
521if __name__ == "__main__":
522 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