A Discrete-Event Network Simulator
API
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 
21 import unittest
22 from ns import ns
23 import sys
24 
25 UINT32_MAX = 0xFFFFFFFF
26 
27 
28 
29 class TestSimulator(unittest.TestCase):
30 
38 
39  def testScheduleNow(self):
40  """! Test schedule now
41  @param self this object
42  @return None
43  """
44 
45  def callback(args: ns.cppyy.gbl.std.vector) -> None:
46  """! Callback function
47  @param args arguments
48  @return None
49  """
50  self._args_received_args_received = list(map(lambda x: x.decode("utf-8"), args))
51  self._cb_time_cb_time = ns.Simulator.Now()
52 
53  ns.Simulator.Destroy()
54  self._args_received_args_received = None
55  self._cb_time_cb_time = None
56  ns.cppyy.cppdef("""
57  EventImpl* pythonMakeEvent(void (*f)(std::vector<std::string>), std::vector<std::string> l)
58  {
59  return MakeEvent(f, l);
60  }
61  """)
62  event = ns.cppyy.gbl.pythonMakeEvent(callback, sys.argv)
63  ns.Simulator.ScheduleNow(event)
64  ns.Simulator.Run()
65  self.assertListEqual(self._args_received_args_received, sys.argv)
66  self.assertEqual(self._cb_time_cb_time.GetSeconds(), 0.0)
67 
68  def testSchedule(self):
69  """! Test schedule
70  @param self this object
71  @return None
72  """
73 
74  def callback(args: ns.cppyy.gbl.std.vector):
75  """! Callback function
76  @param args arguments
77  @return None
78  """
79  self._args_received_args_received = list(map(lambda x: x.decode("utf-8"), args))
80  self._cb_time_cb_time = ns.Simulator.Now()
81 
82  ns.Simulator.Destroy()
83  self._args_received_args_received = None
84  self._cb_time_cb_time = None
85  ns.cppyy.cppdef("""
86  EventImpl* pythonMakeEvent2(void (*f)(std::vector<std::string>), std::vector<std::string> l)
87  {
88  return MakeEvent(f, l);
89  }
90  """)
91  event = ns.cppyy.gbl.pythonMakeEvent2(callback, sys.argv)
92  ns.Simulator.Schedule(ns.Seconds(123), event)
93  ns.Simulator.Run()
94  self.assertListEqual(self._args_received_args_received, sys.argv)
95  self.assertEqual(self._cb_time_cb_time.GetSeconds(), 123.0)
96 
98  """! Test schedule destroy
99  @param self this object
100  @return None
101  """
102 
103  def callback(args: ns.cppyy.gbl.std.vector):
104  """! Callback function
105  @param args
106  @return None
107  """
108  self._args_received_args_received = list(map(lambda x: x.decode("utf-8"), args))
109  self._cb_time_cb_time = ns.Simulator.Now()
110 
111  ns.Simulator.Destroy()
112  self._args_received_args_received = None
113  self._cb_time_cb_time = None
114  ns.cppyy.cppdef("void null(){ return; }")
115  ns.Simulator.Schedule(ns.Seconds(123), ns.cppyy.gbl.null)
116  ns.cppyy.cppdef("""
117  EventImpl* pythonMakeEvent3(void (*f)(std::vector<std::string>), std::vector<std::string> l)
118  {
119  return MakeEvent(f, l);
120  }
121  """)
122  event = ns.cppyy.gbl.pythonMakeEvent3(callback, sys.argv)
123  ns.Simulator.ScheduleDestroy(event)
124  ns.Simulator.Run()
125  ns.Simulator.Destroy()
126  self.assertListEqual(self._args_received_args_received, sys.argv)
127  self.assertEqual(self._cb_time_cb_time.GetSeconds(), 123.0)
128 
130  """! Test schedule with context
131  @param self this object
132  @return None
133  """
134 
135  def callback(context, args: ns.cppyy.gbl.std.vector):
136  """! Callback
137  @param context the context
138  @param args the arguments
139  @return None
140  """
141  self._context_received_context_received = context
142  self._args_received_args_received = list(map(lambda x: x.decode("utf-8"), args))
143  self._cb_time_cb_time = ns.Simulator.Now()
144 
145  ns.Simulator.Destroy()
146  self._args_received_args_received = None
147  self._cb_time_cb_time = None
148  self._context_received_context_received = None
149  ns.cppyy.cppdef("""
150  EventImpl* pythonMakeEvent4(void (*f)(uint32_t, std::vector<std::string>), uint32_t context, std::vector<std::string> l)
151  {
152  return MakeEvent(f, context, l);
153  }
154  """)
155  event = ns.cppyy.gbl.pythonMakeEvent4(callback, 54321, sys.argv)
156  ns.Simulator.ScheduleWithContext(54321, ns.Seconds(123), event)
157  ns.Simulator.Run()
158  self.assertEqual(self._context_received_context_received, 54321)
159  self.assertListEqual(self._args_received_args_received, sys.argv)
160  self.assertEqual(self._cb_time_cb_time.GetSeconds(), 123.0)
161 
163  """! Test time comparison
164  @param self this object
165  @return None
166  """
167  self.assertTrue(ns.Seconds(123) == ns.Seconds(123))
168  self.assertTrue(ns.Seconds(123) >= ns.Seconds(123))
169  self.assertTrue(ns.Seconds(123) <= ns.Seconds(123))
170  self.assertTrue(ns.Seconds(124) > ns.Seconds(123))
171  self.assertTrue(ns.Seconds(123) < ns.Seconds(124))
172 
174  """! Test numeric operations
175  @param self this object
176  @return None
177  """
178  self.assertEqual(ns.Seconds(10) + ns.Seconds(5), ns.Seconds(15))
179  self.assertEqual(ns.Seconds(10) - ns.Seconds(5), ns.Seconds(5))
180 
181  v1 = ns.int64x64_t(5.0) * ns.int64x64_t(10)
182  self.assertEqual(v1, ns.int64x64_t(50))
183 
184  def testConfig(self):
185  """! Test configuration
186  @param self this object
187  @return None
188  """
189  ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
190  # hm.. no Config.Get?
191 
192  def testSocket(self):
193  """! Test socket
194  @param self
195  @return None
196  """
197  nc = ns.NodeContainer(1)
198  node = nc.Get(0)
199  internet = ns.CreateObject("InternetStackHelper")
200  internet.Install(node)
201  self._received_packet_received_packet = None
202 
203  def python_rx_callback(socket) -> None:
204  self._received_packet_received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0)
205 
206  ns.cppyy.cppdef("""
207  Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback_test_socket(void(*func)(Ptr<Socket>))
208  {
209  return MakeCallback(func);
210  }
211  """)
212 
213  sink = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
214  sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
215  sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
216 
217  source = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
218  source.SendTo(ns.network.Packet(19), 0,
219  ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo())
220 
221  ns.Simulator.Run()
222  self.assertTrue(self._received_packet_received_packet is not None)
223  self.assertEqual(self._received_packet_received_packet.GetSize(), 19)
224 
225  # Delete Ptr<>'s on the python side to let C++ clean them
226  del internet
227 
228  def testAttributes(self):
229  """! Test attributes function
230  @param self this object
231  @return None
232  """
233  # Templated class DropTailQueue<Packet> in C++
234  queue = ns.CreateObject("DropTailQueue<Packet>")
235  queueSizeValue = ns.network.QueueSizeValue(ns.network.QueueSize("500p"))
236  queue.SetAttribute("MaxSize", queueSizeValue)
237 
238  limit = ns.network.QueueSizeValue()
239  queue.GetAttribute("MaxSize", limit)
240  self.assertEqual(limit.Get(), ns.network.QueueSize("500p"))
241 
242 
243  mobility = ns.CreateObject("RandomWaypointMobilityModel")
244  ptr = ns.CreateObject("PointerValue")
245  mobility.GetAttribute("PositionAllocator", ptr)
246  self.assertEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
247 
248  pos = ns.mobility.ListPositionAllocator()
249  ptr.SetObject(pos)
250  mobility.SetAttribute("PositionAllocator", ptr)
251 
252  ptr2 = ns.CreateObject("PointerValue")
253  mobility.GetAttribute("PositionAllocator", ptr2)
254  self.assertNotEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
255 
256  # Delete Ptr<>'s on the python side to let C++ clean them
257  del queue, mobility, ptr, ptr2
258 
259  def testIdentity(self):
260  """! Test identify
261  @param self this object
262  @return None
263  """
264  csma = ns.CreateObject("CsmaNetDevice")
265  channel = ns.CreateObject("CsmaChannel")
266  csma.Attach(channel)
267 
268  c1 = csma.GetChannel()
269  c2 = csma.GetChannel()
270 
271  self.assertEqual(c1, c2)
272 
273  # Delete Ptr<>'s on the python side to let C++ clean them
274  del csma, channel
275 
276  def testTypeId(self):
277  """! Test type ID
278  @param self this object
279  @return None
280  """
281  ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory")
282  self.assertTrue(ok)
283  self.assertEqual(typeId1.GetName(), "ns3::UdpSocketFactory")
284 
285  ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
286  self.assertFalse(ok)
287 
288  def testCommandLine(self):
289  """! Test command line
290  @param self this object
291  @return None
292  """
293  from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
294 
295  test1 = c_bool(True)
296  test2 = c_int(42)
297  test3 = c_double(3.1415)
298  BUFFLEN = 40 # noqa
299  test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
300  test4 = c_char_p(test4Buffer.raw)
301 
302  cmd = ns.core.CommandLine(__file__)
303  cmd.AddValue("Test1", "this is a test option", test1)
304  cmd.AddValue("Test2", "this is a test option", test2)
305  cmd.AddValue("Test3", "this is a test option", test3)
306  cmd.AddValue("Test4", "this is a test option", test4, BUFFLEN)
307 
308  cmd.Parse(["python"])
309  self.assertEqual(test1.value, True)
310  self.assertEqual(test2.value, 42)
311  self.assertEqual(test3.value, 3.1415)
312  self.assertEqual(test4.value, b"this is a test option")
313 
314  cmd.Parse(["python", "--Test1=false", "--Test2=0", "--Test3=0.0"])
315  self.assertEqual(test1.value, False)
316  self.assertEqual(test2.value, 0)
317  self.assertEqual(test3.value, 0.0)
318 
319  cmd.Parse(["python", "--Test4=new_string"])
320  self.assertEqual(test4.value, b"new_string")
321 
322  def testSubclass(self):
323  """! Test subclass
324  @param self this object
325  @return None
326  """
327 
328 
329  class MyNode(ns.network.Node):
330  def GetLocalTime(self) -> ns.Time:
331  return ns.Seconds(10)
332 
333  node = MyNode()
334  forced_local_time = node.GetLocalTime()
335  self.assertEqual(forced_local_time, ns.Seconds(10))
336  del node
337 
339  """! Test python-based application
340  @param self this object
341  @return None
342  """
343  ns.Simulator.Destroy()
344 
345  nodes = ns.network.NodeContainer()
346  nodes.Create(2)
347 
348  pointToPoint = ns.point_to_point.PointToPointHelper()
349  pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
350  pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
351 
352  devices = pointToPoint.Install(nodes)
353 
354  stack = ns.internet.InternetStackHelper()
355  stack.Install(nodes)
356 
357  address = ns.internet.Ipv4AddressHelper()
358  address.SetBase(ns.network.Ipv4Address("10.1.1.0"),
359  ns.network.Ipv4Mask("255.255.255.0"))
360 
361  interfaces = address.Assign(devices)
362 
363  ns.cppyy.cppdef("""
364  namespace ns3
365  {
366  Callback<void,Ptr<Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
367  {
368  return MakeCallback(func);
369  }
370  EventImpl* pythonMakeEventSend(void (*f)(Ptr<Socket>, Ptr<Packet>, Address&), Ptr<Socket> socket, Ptr<Packet> packet, Address address)
371  {
372  return MakeEvent(f, socket, packet, address);
373  }
374  }
375  """)
376 
377 
378  class EchoServer(ns.applications.Application):
379  LOGGING = False
380  ECHO_PORT = 1234
381  socketToInstanceDict = {}
382 
383  def __init__(self, node: ns.Node, port=ECHO_PORT):
384  """! Constructor needs to call first the constructor to Application (super class)
385  @param self this object
386  @param node node where this application will be executed
387  @param port port to listen
388  return None
389  """
390  super().__init__()
391  self.__python_owns____python_owns__ = False # Let C++ destroy this on Simulator::Destroy
392 
393  self.portport = port
394 
395  self.m_socketm_socket = ns.network.Socket.CreateSocket(node,
396  ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
397  self.m_socketm_socket.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), self.portport).ConvertTo())
398  self.m_socketm_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
399  EchoServer.socketToInstanceDict[self.m_socketm_socket] = self
400 
401  def __del__(self):
402  """! Destructor
403  @param self this object
404  return None
405  """
406  del EchoServer.socketToInstanceDict[self.m_socketm_socket]
407 
408  def Send(self, packet: ns.Packet, address: ns.Address) -> None:
409  """! Function to send a packet to an address
410  @param self this object
411  @param packet packet to send
412  @param address destination address
413  return None
414  """
415  self.m_socketm_socket.SendTo(packet, 0, address)
416  if EchoServer.LOGGING:
417  inetAddress = ns.InetSocketAddress.ConvertFrom(address)
418  print("At time +{s}s server sent {b} bytes from {ip} port {port}"
419  .format(s=ns.Simulator.Now().GetSeconds(),
420  b=packet.__deref__().GetSize(),
421  ip=inetAddress.GetIpv4(),
422  port=inetAddress.GetPort()),
423  file=sys.stderr,
424  flush=True)
425 
426  def Receive(self):
427  """! Function to receive a packet from an address
428  @param self this object
429  @return None
430  """
431  address = ns.Address()
432  packet = self.m_socketm_socket.RecvFrom(address)
433  if EchoServer.LOGGING:
434  inetAddress = ns.InetSocketAddress.ConvertFrom(address)
435  print("At time +{s}s server received {b} bytes from {ip} port {port}"
436  .format(s=ns.Simulator.Now().GetSeconds(),
437  b=packet.__deref__().GetSize(),
438  ip=inetAddress.GetIpv4(),
439  port=inetAddress.GetPort()),
440  file=sys.stderr,
441  flush=True)
442  event = ns.pythonMakeEventSend(EchoServer._Send, self.m_socketm_socket, packet, address)
443  ns.Simulator.Schedule(ns.Seconds(1), event)
444 
445  @staticmethod
446  def _Send(socket: ns.Socket, packet: ns.Packet, address: ns.Address):
447  """! Static send function, which matches the output socket
448  to the EchoServer instance to call the instance Send function
449  @param socket socket from the instance that should send the packet
450  @param packet packet to send
451  @param address destination address
452  return None
453  """
454  instance = EchoServer.socketToInstanceDict[socket]
455  instance.Send(packet, address)
456 
457  @staticmethod
458  def _Receive(socket: ns.Socket) -> None:
459  """! Static receive function, which matches the input socket
460  to the EchoServer instance to call the instance Receive function
461  @param socket socket from the instance that should receive the packet
462  return None
463  """
464  instance = EchoServer.socketToInstanceDict[socket]
465  instance.Receive()
466 
467  echoServer = EchoServer(nodes.Get(1))
468  nodes.Get(1).AddApplication(echoServer)
469 
470  serverApps = ns.ApplicationContainer()
471  serverApps.Add(echoServer)
472  serverApps.Start(ns.core.Seconds(1.0))
473  serverApps.Stop(ns.core.Seconds(10.0))
474 
475  address = interfaces.GetAddress(1).ConvertTo()
476  echoClient = ns.applications.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
477  echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(10))
478  echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
479  echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(101))
480 
481  clientApps = echoClient.Install(nodes.Get(0))
482  clientApps.Start(ns.core.Seconds(2.0))
483  clientApps.Stop(ns.core.Seconds(10.0))
484 
485  ns.Simulator.Run()
486  ns.Simulator.Destroy()
487 
488 
489 if __name__ == '__main__':
490  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
uint32_t GetSize(Ptr< const Packet > packet, const WifiMacHeader *hdr, bool isAmpdu)
Return the total size of the packet after WifiMacHeader and FCS trailer have been added.
Definition: wifi-utils.cc:132
#define list