00001
00002
00003 import sys
00004 import time
00005 import subprocess
00006 import unittest
00007
00008 import roslib; roslib.load_manifest('network_control_tests')
00009 import rospy
00010 import rostest
00011 import math
00012
00013 from network_monitor_udp.linktest import UdpmonsourceHandle
00014 from network_monitor_udp.linktest import LinkTest
00015 from network_monitor_udp.msg import LinktestGoal
00016 from network_traffic_control.projected_link_metrics import get_projected_link_metrics
00017 import dynamic_reconfigure.client
00018
00019 class DynreconfTest(unittest.TestCase):
00020 def __init__(self, *args):
00021 super(DynreconfTest, self).__init__(*args)
00022 rospy.init_node('network_traffic_control_test')
00023 self.srcnode = UdpmonsourceHandle('performance_test')
00024 self.dynclient = dynamic_reconfigure.client.Client("tc_lo")
00025 self.no_traffic_control_params = {
00026 "bandwidth_egress" : 0.0, "bandwidth_ingress" : 0.0,
00027 "latency_egress" : 0.0, "latency_ingress" : 0.0,
00028 "loss_egress" : 0.0, "loss_ingress" : 0.0,
00029 "packet_size" : 1500 }
00030 self.reset_tc_rules_via_dynreconf()
00031
00032 def reset_tc_rules_via_dynreconf(self):
00033 config = self.dynclient.update_configuration(self.no_traffic_control_params)
00034 if config['status'] != "OK":
00035 raise(ValueError(config['errmsg']))
00036
00037 def setUp(self):
00038 self.srcnode.cancel_all_tests()
00039
00040 def tearDown(self):
00041 self.reset_tc_rules_via_dynreconf()
00042
00043 def test_latency(self):
00044 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0,
00045 sink_ip = "127.0.0.1", sink_port = 12345,
00046 bw_type = LinktestGoal.BW_CONSTANT)
00047 test.start()
00048 time.sleep(3.5)
00049 self.assertTrue(test.done, "Test should have finished already")
00050 self.assertTrue(test.overall_latency < 0.01,
00051 "Expected latency to be < 1ms, instead it was %.2fms"%
00052 (test.overall_latency * 1e3))
00053
00054 config = self.dynclient.update_configuration({ "latency_egress": 0.03 })
00055 self.assertTrue(config['status'] == "OK",
00056 "Operation FAILed: " + config['errmsg'])
00057 self.assertAlmostEqual(config['latency_egress'], 0.03, 3,
00058 "Expected latency_egress dynreconf parameter to be ~30ms, instead it was %.2fms"%
00059 (config['latency_egress'] * 1e3))
00060
00061 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0,
00062 sink_ip = "127.0.0.1", sink_port = 12345,
00063 bw_type = LinktestGoal.BW_CONSTANT)
00064 test.start()
00065 time.sleep(3.5)
00066 self.assertTrue(test.done, "Test should have finished already")
00067 self.assertTrue(test.overall_latency > 0.02 and test.overall_latency < 0.04,
00068 "Expected latency to be ~30ms, instead it was %.2fms"%
00069 (test.overall_latency * 1e3))
00070 self.assertTrue(test.overall_bandwidth > 0.7e6,
00071 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"%
00072 (test.overall_bandwidth/1e6))
00073 self.assertTrue(test.overall_loss < 5.0,
00074 "Expected packet loss to be 0%%, instead it was %.2f%%"%
00075 (test.overall_loss))
00076
00077 config = self.dynclient.update_configuration({ "latency_egress": 0.01, "latency_ingress": 0.05 })
00078 self.assertTrue(config['status'] == "OK",
00079 "Operation FAILed: " + config['errmsg'])
00080 self.assertAlmostEqual(config['latency_egress'], 0.01, 3,
00081 "Expected latency_egress dynreconf parameter to be ~10ms, instead it was %.2fms"%
00082 (config['latency_egress'] * 1e3))
00083 self.assertAlmostEqual(config['latency_ingress'], 0.05, 3,
00084 "Expected latency_ingress dynreconf parameter to be ~50ms, instead it was %.2fms"%
00085 (config['latency_ingress'] * 1e3))
00086
00087 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0,
00088 sink_ip = "127.0.0.1", sink_port = 12345,
00089 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.1)
00090 test.start()
00091 time.sleep(3.5)
00092 self.assertTrue(test.done, "Test should have finished already")
00093 self.assertTrue(test.overall_latency > 0.045 and test.overall_latency < 0.075,
00094 "Expected latency to be ~ 60ms, instead it was %.2fms"%
00095 (test.overall_latency * 1e3))
00096 self.assertTrue(test.overall_bandwidth > 0.7e6,
00097 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"%
00098 (test.overall_bandwidth/1e6))
00099 self.assertTrue(test.overall_loss < 5.0,
00100 "Expected packet loss to be 0%%, instead it was %.2f%%"%
00101 (test.overall_loss))
00102
00103 def test_bandwidth(self):
00104 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0,
00105 sink_ip = "127.0.0.1", sink_port = 12345,
00106 bw_type = LinktestGoal.BW_CONSTANT)
00107 test.start()
00108 time.sleep(3.5)
00109 self.assertTrue(test.done, "Test should have finished already")
00110 self.assertTrue(test.overall_latency < 0.01,
00111 "Expected latency to be < 1ms, instead it was %.2fms"%
00112 (test.overall_latency * 1e3))
00113 self.assertTrue(test.overall_bandwidth > 2.7e6,
00114 "Expected overall bandwidth to be ~3Mbit/s, instead it was %.2fMbit/s"%
00115 (test.overall_bandwidth/1e6))
00116
00117 config = self.dynclient.update_configuration({ "bandwidth_egress": 2e6, "bandwidth_ingress": 2e6 })
00118 self.assertTrue(config['status'] == "OK",
00119 "Operation FAILed: " + config['errmsg'])
00120 self.assertAlmostEqual(config['bandwidth_egress']/1e6, 2.0, 3,
00121 "Expected bandwidth_egress dynreconf parameter to be ~2Mbit/s, instead it was %.2fMbit/s"%
00122 (config['bandwidth_egress']/1e6))
00123 self.assertAlmostEqual(config['bandwidth_ingress']/1e6, 2.0, 3,
00124 "Expected bandwidth_ingress dynreconf parameter to be ~2Mbit/s, instead it was %.2fMbit/s"%
00125 (config['bandwidth_ingress']/1e6))
00126
00127 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0,
00128 sink_ip = "127.0.0.1", sink_port = 12345,
00129 bw_type = LinktestGoal.BW_CONSTANT, latencybins = [ 0.01, 0.1, 0.3],
00130 max_return_time = 0.25)
00131 test.start()
00132 time.sleep(3.5)
00133 self.assertTrue(test.done, "Test should have finished already")
00134 self.assertTrue(test.overall_bandwidth > 1.5e6 and test.overall_bandwidth < 2.5e6,
00135 "Expected measured bandwidth to be ~2Mbit/s, instead it was %.2fMbit/s"%
00136 (test.overall_bandwidth/1e6))
00137
00138 config = self.dynclient.update_configuration({ "bandwidth_ingress": 1e6 })
00139
00140 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0,
00141 sink_ip = "127.0.0.1", sink_port = 12345,
00142 bw_type = LinktestGoal.BW_CONSTANT)
00143 test.start()
00144 time.sleep(3.5)
00145 self.assertTrue(test.done, "Test should have finished already")
00146 self.assertTrue(test.overall_bandwidth > 0.7e6 and test.overall_bandwidth < 1.3e6,
00147 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"%
00148 (test.overall_bandwidth/1e6))
00149
00150 def test_bandwidth_latency(self):
00151 config = self.dynclient.update_configuration({ "bandwidth_egress": 1e6, "latency_ingress": 0.03 })
00152 test = self.srcnode.create_test(bw = 0.7*10**6, pktsize = 1500, duration = 5.0,
00153 sink_ip = "127.0.0.1", sink_port = 12345,
00154 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00155 test.start()
00156 time.sleep(5.5)
00157 self.assertTrue(test.done, "Test should have finished already")
00158 self.assertTrue(test.overall_bandwidth > 0.5e6 and test.overall_bandwidth < 0.9e6,
00159 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"%
00160 (test.overall_bandwidth/1e6))
00161 self.assertTrue(test.latency.avg() > 0.025 and test.latency.avg() < 0.045,
00162 "Expected latency to be ~30ms (since capacity was not overrun), instead it was %.2fms"%
00163 (test.latency.avg()*1e3))
00164 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 5.0,
00165 sink_ip = "127.0.0.1", sink_port = 12345,
00166 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00167 test.start()
00168 time.sleep(5.5)
00169 self.assertTrue(test.done, "Test should have finished already")
00170 self.assertTrue(test.overall_bandwidth > 0.8e6 and test.overall_bandwidth < 1.2e6,
00171 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"%
00172 (test.overall_bandwidth/1e6))
00173 expected_latency = 1500.0/(1e6/8) + 0.03
00174 self.assertTrue(test.latency.avg() > expected_latency - 0.005 and test.latency.avg() < expected_latency + 0.005,
00175 "Expected latency to be ~%.2fms (since capacity was not overrun), instead it was %.2fms"%
00176 (expected_latency * 1e3, test.latency.avg()*1e3))
00177
00178 def test_ingress_egress_loss(self):
00179 config = self.dynclient.update_configuration({ "loss_egress": 20.0, "loss_ingress": 30.0 })
00180 test = self.srcnode.create_test(bw = 5*10**6, pktsize = 1500, duration = 5.0,
00181 sink_ip = "127.0.0.1", sink_port = 12345,
00182 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00183 test.start()
00184 time.sleep(5.5)
00185 self.assertTrue(test.done, "Test should have finished already")
00186 self.assertTrue(test.loss.avg() > 44.0 - 10.0 and test.loss.avg() < 44.0 + 10.0,
00187 "Expected aggregated loss (ingress+egress) to be ~44%%, instead it was %.2f%%"%
00188 (test.loss.avg()))
00189
00190 def test_packet_size(self):
00191 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0,
00192 sink_ip = "127.0.0.1", sink_port = 12345,
00193 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00194 config = self.dynclient.update_configuration({ "packet_size": 5000, "bandwidth_egress": 1e6 })
00195 test.start()
00196 time.sleep(3.5)
00197 self.assertTrue(test.done, "Test should have finished already")
00198 self.assertTrue(test.latency.avg() > 0.035 and test.latency.avg() < 0.045,
00199 "Expected latency to be ~40ms, instead it was %.2fms"%
00200 (test.latency.avg()*1e3))
00201
00202 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0,
00203 sink_ip = "127.0.0.1", sink_port = 12345,
00204 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00205 config = self.dynclient.update_configuration({ "packet_size": 500 })
00206
00207 test.start()
00208 time.sleep(3.5)
00209 self.assertTrue(test.done, "Test should have finished already")
00210 self.assertTrue(test.latency.avg() > 0.002 and test.latency.avg() < 0.006,
00211 "Expected latency to be ~4ms, instead it was %.2fms"%
00212 (test.latency.avg()*1e3))
00213
00214 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0,
00215 sink_ip = "127.0.0.1", sink_port = 12345,
00216 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00217 config = self.dynclient.update_configuration({ "bandwidth_ingress": 0.5e6 })
00218 test.start()
00219 time.sleep(3.5)
00220 self.assertTrue(test.done, "Test should have finished already")
00221 self.assertTrue(test.latency.avg() > 0.008 and test.latency.avg() < 0.015,
00222 "Expected latency to be ~12ms, instead it was %.2fms"%
00223 (test.latency.avg()*1e3))
00224
00225 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0,
00226 sink_ip = "127.0.0.1", sink_port = 12345,
00227 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00228 config = self.dynclient.update_configuration({ "packet_size": 300 })
00229 test.start()
00230 time.sleep(3.5)
00231 self.assertTrue(test.done, "Test should have finished already")
00232 self.assertTrue(test.loss.avg() > 95.0,
00233 "Expected loss to be 100% (tc limit smaller than packet size)")
00234
00235 def bandwidth_latency_loss_test(self, direction, bw_tx, bw_limit, latency, loss,
00236 expected_bw = None, expected_loss = None, expected_latency = None):
00237 self.reset_tc_rules_via_dynreconf()
00238 config = self.dynclient.update_configuration({ "bandwidth_" + direction: bw_limit,
00239 "latency_" + direction: latency,
00240 "loss_" + direction: loss })
00241
00242 self.assertTrue(config['status'] == "OK",
00243 "Operation FAILed: " + config['errmsg'])
00244
00245 test = self.srcnode.create_test(bw = bw_tx, pktsize = 1500, duration = 5.0,
00246 sink_ip = "127.0.0.1", sink_port = 12345,
00247 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01)
00248 test.start()
00249 time.sleep(5.5)
00250 self.assertTrue(test.done, "Test should have finished already")
00251
00252 (expected_bw, expected_latency, expected_loss) = get_projected_link_metrics(bw_limit, latency, loss, 1500.0, bw_tx)
00253
00254 print "bw_limit: ", bw_limit, "loss: ", loss, "latency: ", latency, "bw_tx: ", bw_tx
00255 print "meas_bw: ", test.bandwidth.avg(), " meas_latency: ", test.latency.avg()*1e3, " meas_loss: ", test.loss.avg()
00256 print "exp_bw", expected_bw, " exp_latency: ", expected_latency * 1e3, " exp_loss: ", expected_loss
00257 self.assertTrue(test.bandwidth.avg() > expected_bw * 0.75 and test.bandwidth.avg() < expected_bw * 1.25,
00258 "Expected measured bandwidth to be ~%.2fMbit/s, instead it was %.2fMbit/s"%
00259 (expected_bw/1e6, test.bandwidth.avg()/1e6))
00260 self.assertTrue(test.latency.avg() > expected_latency - 0.015 and test.latency.avg() < expected_latency + 0.015,
00261 "Expected latency to be ~%.2fms, instead it was %.2fms"%
00262 (expected_latency * 1e3, test.latency.avg() * 1e3))
00263 self.assertTrue((test.loss.avg() < 4.0 and expected_loss < 2.0) or
00264 (test.loss.avg() > expected_loss - 10.0 and test.latency.avg() < expected_loss + 10.0),
00265 "Expected loss to be ~%.2f%%, instead it was %.2f%%"%
00266 (expected_loss, test.loss.avg()))
00267
00268
00269 def test_bandwidth_latency_loss(self):
00270
00271 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6,
00272 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0)
00273
00274 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6,
00275 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0)
00276
00277 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6,
00278 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0)
00279
00280 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6,
00281 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0)
00282
00283 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6,
00284 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0)
00285
00286 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6,
00287 bw_limit=1.0*10**6, latency = 0.03, loss = 50.0)
00288
00289 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6,
00290 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0)
00291
00292 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6,
00293 bw_limit=1.0*10**6, latency = 0.03, loss = 50.0)
00294
00295 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6,
00296 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0)
00297 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6,
00298 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0)
00299 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6,
00300 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0)
00301 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6,
00302 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0)
00303 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6,
00304 bw_limit=1.0*10**6, latency = 0.02, loss = 0.0)
00305 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6,
00306 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0)
00307 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6,
00308 bw_limit=1.0*10**6, latency = 0.04, loss = 20.0)
00309 if __name__ == '__main__':
00310 try:
00311 rostest.run('network_control_tests', 'dynreconf_test', DynreconfTest)
00312 except KeyboardInterrupt, e:
00313 pass