#!/usr/bin/env python # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """End-to-end tests for traffic control library.""" import os import re import sys import unittest import traffic_control class TrafficControlTests(unittest.TestCase): """System tests for traffic_control functions. These tests require root access. """ # A dummy interface name to use instead of real interface. _INTERFACE = 'myeth' def setUp(self): """Setup a dummy interface.""" # If we update to python version 2.7 or newer we can use setUpClass() or # unittest.skipIf(). if os.getuid() != 0: sys.exit('You need root access to run these tests.') command = ['ip', 'link', 'add', 'name', self._INTERFACE, 'type', 'dummy'] traffic_control._Exec(command, 'Error creating dummy interface %s.' % self._INTERFACE) def tearDown(self): """Teardown the dummy interface and any network constraints on it.""" # Deleting the dummy interface deletes all associated constraints. command = ['ip', 'link', 'del', self._INTERFACE] traffic_control._Exec(command) def testExecOutput(self): output = traffic_control._Exec(['echo', ' Test ']) self.assertEqual(output, 'Test') def testExecException(self): self.assertRaises(traffic_control.TrafficControlError, traffic_control._Exec, command=['ls', '!doesntExist!']) def testExecErrorCustomMsg(self): try: traffic_control._Exec(['ls', '!doesntExist!'], msg='test_msg') self.fail('No exception raised for invalid command.') except traffic_control.TrafficControlError as e: self.assertEqual(e.msg, 'test_msg') def testAddRootQdisc(self): """Checks adding a root qdisc is successful.""" config = {'interface': self._INTERFACE} root_detail = 'qdisc htb 1: root' # Assert no htb root at startup. command = ['tc', 'qdisc', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) self.assertFalse(root_detail in output) traffic_control._AddRootQdisc(config['interface']) output = traffic_control._Exec(command) # Assert htb root is added. self.assertTrue(root_detail in output) def testConfigureClassAdd(self): """Checks adding and deleting a class to the root qdisc.""" config = { 'interface': self._INTERFACE, 'port': 12345, 'server_port': 33333, 'bandwidth': 2000 } class_detail = ('class htb 1:%x root prio 0 rate %dKbit ceil %dKbit' % (config['port'], config['bandwidth'], config['bandwidth'])) # Add root qdisc. traffic_control._AddRootQdisc(config['interface']) # Assert class does not exist prior to adding it. command = ['tc', 'class', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) self.assertFalse(class_detail in output) # Add class to root. traffic_control._ConfigureClass('add', config) # Assert class is added. command = ['tc', 'class', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) self.assertTrue(class_detail in output) # Delete class. traffic_control._ConfigureClass('del', config) # Assert class is deleted. command = ['tc', 'class', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) self.assertFalse(class_detail in output) def testAddSubQdisc(self): """Checks adding a sub qdisc to existing class.""" config = { 'interface': self._INTERFACE, 'port': 12345, 'server_port': 33333, 'bandwidth': 2000, 'latency': 250, 'loss': 5 } qdisc_re_detail = ('qdisc netem %x: parent 1:%x .* delay %d.0ms loss %d%%' % (config['port'], config['port'], config['latency'], config['loss'])) # Add root qdisc. traffic_control._AddRootQdisc(config['interface']) # Add class to root. traffic_control._ConfigureClass('add', config) # Assert qdisc does not exist prior to adding it. command = ['tc', 'qdisc', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) handle_id_re = re.search(qdisc_re_detail, output) self.assertEqual(handle_id_re, None) # Add qdisc to class. traffic_control._AddSubQdisc(config) # Assert qdisc is added. command = ['tc', 'qdisc', 'ls', 'dev', config['interface']] output = traffic_control._Exec(command) handle_id_re = re.search(qdisc_re_detail, output) self.assertNotEqual(handle_id_re, None) def testAddDeleteFilter(self): config = { 'interface': self._INTERFACE, 'port': 12345, 'bandwidth': 2000 } # Assert no filter exists. command = ['tc', 'filter', 'list', 'dev', config['interface'], 'parent', '1:0'] output = traffic_control._Exec(command) self.assertEqual(output, '') # Create the root and class to which the filter will be attached. # Add root qdisc. traffic_control._AddRootQdisc(config['interface']) # Add class to root. traffic_control._ConfigureClass('add', config) # Add the filter. traffic_control._AddFilter(config['interface'], config['port']) handle_id = traffic_control._GetFilterHandleId(config['interface'], config['port']) self.assertNotEqual(handle_id, None) # Delete the filter. # The output of tc filter list is not None because tc adds default filters. traffic_control._DeleteFilter(config['interface'], config['port']) self.assertRaises(traffic_control.TrafficControlError, traffic_control._GetFilterHandleId, config['interface'], config['port']) if __name__ == '__main__': unittest.main()