def test_prepare_port_bindings(ChuteContainer):
    chute = Chute(name="test")
    chute.web = {
        "service": "main",
        "port": 80
    }

    service = Service(name="main", chute=chute)
    chute.add_service(service)

    container = MagicMock()
    container.inspect.side_effect = ChuteNotFound()
    ChuteContainer.return_value = container

    bindings = dockerapi.prepare_port_bindings(service)
    assert bindings["80/tcp"] is None

    container.inspect.side_effect = None
    container.inspect.return_value = {
        "NetworkSettings": {
            "Ports": {
                "80/tcp": [{
                    "HostIp": "0.0.0.0",
                    "HostPort": "32784"
                }]
            }
        }
    }

    bindings = dockerapi.prepare_port_bindings(service)
    assert bindings["80/tcp"] == "32784"
def test_ChuteApi_get_network(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    iface = {
        'name': 'vwlan0',
        'type': 'wifi',
        'internalIntf': 'wlan0'
    }

    chute = Chute(name="test")
    chute.setCache("networkInterfaces", [iface])

    ChuteStorage.chuteList = {
        "test": chute
    }

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_network(request, "test", "nomatch")
    assert result == "{}"

    result = api.get_network(request, "test", "vwlan0")
    data = json.loads(result)
    assert data['name'] == iface['name']
    assert data['type'] == iface['type']
    assert data['interface'] == iface['internalIntf']
Beispiel #3
0
def test_prepare_port_bindings(ChuteContainer):
    chute = Chute(name="test")
    chute.web = {"service": "main", "port": 80}

    service = Service(name="main", chute=chute)
    chute.add_service(service)

    container = MagicMock()
    container.inspect.side_effect = ChuteNotFound()
    ChuteContainer.return_value = container

    bindings = dockerapi.prepare_port_bindings(service)
    assert bindings["80/tcp"] is None

    container.inspect.side_effect = None
    container.inspect.return_value = {
        "NetworkSettings": {
            "Ports": {
                "80/tcp": [{
                    "HostIp": "0.0.0.0",
                    "HostPort": "32784"
                }]
            }
        }
    }

    bindings = dockerapi.prepare_port_bindings(service)
    assert bindings["80/tcp"] == "32784"
Beispiel #4
0
def test_reloadChutes(mock_getChuteList, getChute, mockSettings, mResources,
                      mWait, mTime, mOut, mTimeint):
    """
    Test that the reloadChutes function does it's job.
    """
    #Test that if pdconfd isn't enabled we return an empty list
    mockSettings.PDCONFD_ENABLED = False

    #Call
    ret = restart.reloadChutes()

    #Assertions
    assert ret == []
    assert not mock_getChuteList.called

    #Test that if pdconfd is enabled we do our job
    mTimeint.return_value = 'Now'
    mockSettings.PDCONFD_ENABLED = True
    ch1 = Chute(name="ch1", state="running")
    ch2 = Chute(name="ch2", state="stopped")
    ch3 = Chute(name="ch3", state="running")
    mock_getChuteList.return_value = [ch1, ch2, ch3]
    mWait.side_effect = [
        None, None,
        '[{"success": false, "comment": "__PARADROP__"},{"success": false, "comment": "ch1"},{"success": false, "comment": "ch2"},{"success": true, "comment": "ch3"},{"success": true, "comment": "error"}]'
    ]

    chutes = {ch.name: ch for ch in [ch1, ch2, ch3]}

    def mock_getChute(name):
        return chutes.get(name, None)

    getChute.side_effect = mock_getChute

    #Call
    ret = restart.reloadChutes()

    #Assertions
    mResources.assert_called_with(ch3)
    print(mResources.call_count)
    assert mResources.call_count == 2
    assert mTime.sleep.call_count == 2
    assert mTime.sleep.called_with(1)
    assert mOut.warn.call_count == 2
    assert 'Failed to load a system config section' in str(
        mOut.warn.call_args_list[0])
    assert 'Failed to load config section for unrecognized chute: ch2' in str(
        mOut.warn.call_args_list[1])
    assert all(update.updateType == "restart" for update in ret)
    assert all(update.new.name in chutes for update in ret)
def test_configure_airshark_abnormal(mockSystem):
    hostconfig = {
        'wifi-interfaces': [{
            'mode': 'airshark',
            'device': 'pci-wifi-0'
        }, {
            'mode': 'airshark',
            'device': 'usb-wifi-0'
        }]
    }

    networkDevices = {
        'wifi': [{
            'id': 'pci-wifi-0',
            'name': 'wifiXXXX',
            'mac': '00:00:00:00:00:01',
            'phy': 'phy0',
            'primary_interface': 'wlan0'
        }, {
            'id': 'usb-wifi-0',
            'name': 'wifiYYYY',
            'mac': '00:00:00:00:00:02',
            'phy': 'phy1',
            'primary_interface': 'wlan1'
        }]
    }

    update = MagicMock()
    update.new = Chute({})

    update.new.setCache('hostConfig', hostconfig)
    update.new.setCache('networkDevices', networkDevices)

    assert_raises(Exception, airshark.configure, update)
    mockSystem.assert_not_called()
def test_UpdateChute(ChuteStorage):
    storage = MagicMock()
    ChuteStorage.return_value = storage

    #
    # Test creating a new chute.
    #
    storage.getChute.return_value = None

    update_data = {'name': 'test', 'version': 4, 'updateType': 'create'}
    update = update_object.UpdateChute(update_data)

    # Expected new chute state is RUNNING
    assert update.state == Chute.STATE_RUNNING

    # Update should have picked up version number from update_data.
    assert update.new.version == update_data['version']

    #
    # Test stopping an existing chute.
    #
    old_chute_data = {'name': 'test', 'version': 5}
    storage.getChute.return_value = Chute(old_chute_data)

    update_data = {'name': 'test', 'updateType': 'stop'}
    update = update_object.UpdateChute(update_data)

    # Expected new chute state is RUNNING
    assert update.state == Chute.STATE_STOPPED

    # Update should have picked up version number from the old chute.
    assert update.new.version == old_chute_data['version']
    def __init__(self, obj):
        self.pkg = None

        # Pull in all the keys from the obj identified
        self.__dict__.update(obj)
        # Any module can add notes and warnings here
        self.responses = []
        # In case of a failure, the final message about failure goes here
        self.failure = None

        # Each update gets its own plan map
        self.plans = plan.plangraph.PlanMap(self.name)
        # Grab a reference to our storage system
        self.chuteStor = ChuteStorage()
        # Explicitly define a reference to the new data object
        self.new = Chute(obj, strip=UPDATE_SPECIFIC_ARGS)
        # Grab the old version if it exists
        self.old = self.chuteStor.getChute(self.name)

        # Save a timestamp from when the update object was created.
        self.createdTime = time.time()

        # Set to True if this update is delegated to an external program (e.g.
        # pdinstall).  In that case, the external program will be responsible
        # for reporting on the completion status of the update.
        self.delegated = False

        # Store progress messages so that they can be retrieved by API.
        self.messages = []
        self.message_observers = []
        self.completed = False
Beispiel #8
0
def test_configure_airshark_enabled(mockSystem):
    hostconfig = {
        'wifi-interfaces': [{
            'mode': 'ap',
            'device': 'pci-wifi-0'
        }, {
            'mode': 'airshark',
            'device': 'usb-wifi-0'
        }]
    }

    networkDevices = {
        'wifi': [{
            'id': 'pci-wifi-0',
            'name': 'wifiXXXX',
            'mac': '00:00:00:00:00:01',
            'phy': 'phy0',
            'primary_interface': 'wlan0'
        }, {
            'id': 'usb-wifi-0',
            'name': 'wifiYYYY',
            'mac': '00:00:00:00:00:02',
            'phy': 'phy1',
            'primary_interface': 'wlan1'
        }]
    }

    update = UpdateObject({'name': 'test'})
    update.new = Chute({})

    update.cache_set('hostConfig', hostconfig)
    update.cache_set('networkDevices', networkDevices)

    airshark.configure(update)
    mockSystem.assert_called()
    def __init__(self):
        self.update_manager = MagicMock()
        self.update_manager.assign_change_id.return_value = 1

        self.api = chute_api.ChuteApi(self.update_manager)

        self.interface = {
            'name': 'testing',
            'netType': 'wifi',
            'internalIntf': 'wlan0',
            'externalIntf': 'vwlan0'
        }

        chute = {'name': 'test', 'web': {'port': 5000}}
        self.chute = Chute(chute)
        self.chute.setCache("externalSystemDir", "/tmp")
        self.chute.setCache("networkInterfaces", [self.interface])
def test_ChuteApi_get_networks(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    iface = {'name': 'vwlan0', 'netType': 'wifi', 'internalIntf': 'wlan0'}

    chute = Chute(dict(name="test"))
    chute.setCache("networkInterfaces", [iface])

    ChuteStorage.chuteList = {"test": chute}

    request = MagicMock()

    result = api.get_networks(request, "test")
    data = json.loads(result)
    assert len(data) == 1
    assert data[0]['name'] == iface['name']
    assert data[0]['type'] == iface['netType']
    assert data[0]['interface'] == iface['internalIntf']
Beispiel #11
0
def test_chute_storage(mSave):

    #Test setAttr & getAttr
    s = chute_storage.ChuteStorage()
    assert s.chuteList == {}
    s.setAttr('test')
    assert s.chuteList == 'test'
    ch2 = MagicMock()
    s.setAttr({1: 'ch1', 2: ch2 , 3: 'ch3'})
    for ch in ['ch1', ch2, 'ch3']:
        assert ch in s.getChuteList()
    assert s.getAttr() == {1: 'ch1', 2: ch2, 3: 'ch3'}
    assert s.attrSaveable()

    #Test saveChute
    ch = MagicMock()
    ch.name = 'ch1'
    s.saveChute(ch)
    mSave.assert_called_once_with()
    mSave.reset_mock()
    ch.name = 2
    s.saveChute(ch)
    mSave.assert_called_once_with()

    #Test deleteChute
    ch = Chute({})
    assert not ch.isValid()
    mSave.reset_mock()
    ch.name = 'test'
    s.saveChute(ch)
    mSave.assert_called_once_with()
    assert ch in s.getChuteList()
    mSave.reset_mock()
    s.deleteChute(ch)
    mSave.assert_called_once_with()
    assert ch not in s.getChuteList()
    mSave.assert_called_once_with()
    assert 'ch1' in s.getChuteList()
    mSave.reset_mock()
    s.deleteChute(1)
    mSave.assert_called_once_with()
    assert 'ch1' not in s.getChuteList()

    #Test clearChuteStorage
    assert s.getChuteList != []
    mSave.reset_mock()
    s.clearChuteStorage()
    mSave.assert_called_once_with()
    assert s.getChuteList() == []
def test_ChuteApi_get_network(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    iface = {'name': 'vwlan0', 'type': 'wifi', 'internalIntf': 'wlan0'}

    chute = Chute(name="test")
    chute.setCache("networkInterfaces", [iface])

    ChuteStorage.chuteList = {"test": chute}

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_network(request, "test", "nomatch")
    assert result == "{}"

    result = api.get_network(request, "test", "vwlan0")
    data = json.loads(result)
    assert data['name'] == iface['name']
    assert data['type'] == iface['type']
    assert data['interface'] == iface['internalIntf']
Beispiel #13
0
def test_Service():
    chute = Chute(name="test", version="1")

    # Test a service with no name of its own.
    service = Service(chute=chute)
    assert service.get_container_name() == "test"
    assert service.get_image_name() == "test:1"

    # Test a named service.
    service = Service(chute=chute, name="main")
    assert service.get_container_name() == "test-main"

    # Test a service that pulls an external image.
    service = Service(chute=chute, type="image", image="mongo:3.0")
    assert service.get_image_name() == "mongo:3.0"
    def __init__(self):
        self.update_manager = MagicMock()
        self.update_manager.assign_change_id.return_value = 1

        self.api = chute_api.ChuteApi(self.update_manager)

        self.interface = {
            'name': 'testing',
            'type': 'wifi',
            'internalIntf': 'wlan0',
            'externalIntf': 'vwlan0'
        }

        chute = Chute(name="test")
        chute.setCache("networkInterfaces", [self.interface])
        chute.setCache("externalSystemDir", "/tmp")
        chute.config = {"web": {"port": 5000}}

        self.chute = chute
Beispiel #15
0
def test_getNetworkConfig():
    update = UpdateObject({'name': 'test'})
    update.old = None

    service = Service(name="main")
    service.interfaces = {
        "wlan0": {}
    }

    update.new = Chute(name="test")
    update.new.add_service(service)

    update.cache_set('deviceReservations', {})
    update.cache_set('interfaceReservations', set())
    update.cache_set('subnetReservations', set())

    update.state = "running"

    # Exception: Interafce definition missing field(s)
    assert_raises(Exception, network.getNetworkConfig, update)

    service.interfaces = {
        "eth1": {
            'intfName': 'eth1',
            'type': 'vlan',
            'dhcp': {},
            'vlan_id': 5
        }
    }

    network.getNetworkConfig(update)

    # Should have called setCache with a list containing one interface.
    value = update.cache_get('networkInterfaces')
    assert isinstance(value, list) and len(value) == 1

    # Should have passed through the dhcp section.
    iface = value[0]
    assert 'dhcp' in iface
Beispiel #16
0
    def __init__(self):
        self.update_manager = MagicMock()
        self.update_manager.assign_change_id.return_value = 1

        self.api = chute_api.ChuteApi(self.update_manager)

        self.interface = {
            'name': 'testing',
            'type': 'wifi',
            'internalIntf': 'wlan0',
            'externalIntf': 'vwlan0'
        }

        chute = Chute(name="test")
        chute.setCache("networkInterfaces", [self.interface])
        chute.setCache("externalSystemDir", "/tmp")
        chute.config = {
            "web": {
                "port": 5000
            }
        }

        self.chute = chute
Beispiel #17
0
def test_state():
    """
    Test plan generation for state module
    """
    from paradrop.core.plan import state
    from paradrop.core.chute.chute import Chute
    from paradrop.base import settings

    # Set this to exercise debug mode code
    settings.DEBUG_MODE = True

    update = MockUpdate()

    # generatePlans returns:
    # True on failure
    # None on success

    # Stop with no old chute should fail
    update.old = None
    update.new = Chute(name="test")
    update.updateType = "stop"
    assert state.generatePlans(update) is True

    # Install with no old chute should succeed
    update.updateType = "install"
    update.new.state = Chute.STATE_RUNNING
    assert state.generatePlans(update) is None

    # Entering invalid state should fail
    update.new.state = Chute.STATE_INVALID
    assert state.generatePlans(update) is True

    # Start with old chute already running should fail
    update.old = Chute(name="test")
    update.old.state = Chute.STATE_RUNNING
    update.updateType = "start"
    assert state.generatePlans(update) is True

    # But if the old chute was stopped, then start should succeed
    update.new.state = "running"
    update.old.state = Chute.STATE_STOPPED
    assert state.generatePlans(update) is None

    # Should be fine
    update.updateType = "restart"
    assert state.generatePlans(update) is None

    # Create should fail when old chute exists
    update.updateType = "create"
    assert state.generatePlans(update) is True

    # Delete and set to stopped is fine
    update.new.state = Chute.STATE_STOPPED
    update.updateType = "delete"
    assert state.generatePlans(update) is None

    # Stopping an already stopped chute should fail
    update.updateType = "stop"
    update.old.state = Chute.STATE_STOPPED
    assert state.generatePlans(update) is True

    # Stopping a running chute is fine
    update.old.state = Chute.STATE_RUNNING
    assert state.generatePlans(update) is None
Beispiel #18
0
def test_get_network_config():
    """
    Test generating network configuration for a chute update.
    """
    from paradrop.core.config import network
    from paradrop.core.config.reservations import DeviceReservations

    # Test normal case where key is defined and encryption is implied.
    iface = dict()
    cfg = {'key': 'password'}
    network.getWifiKeySettings(cfg, iface)
    assert iface['key'] == "password"

    # Test normal case where encryption is set to "none".
    iface = dict()
    cfg = {'encryption': 'none'}
    network.getWifiKeySettings(cfg, iface)
    assert iface['encryption'] == "none"

    # Test error case where encryption is defined but no key is present.
    iface = dict()
    cfg = {'encryption': 'psk2'}
    assert_raises(Exception, network.getWifiKeySettings, cfg, iface)

    update = UpdateObject({'name': 'test'})
    update.old = None
    update.new = MagicMock()

    # Should do nothing on a chute with no "networkInterfaces" cache key.
    network.reclaimNetworkResources(update.new)

    # Chute has no net information, we should pass silently.
    assert network.getNetworkConfig(update) is None

    wireless = {
        'encryption': 'psk2',
        'key': 'password'
    }

    service = Service(name="main")
    service.interfaces = {
        "wlan0": {
            'type': 'wifi-ap',
            'intfName': 'wlan0',
            'wireless': wireless
        }
    }

    chute = Chute(name="test")
    chute.add_service(service)
    update.new = chute

    devices = {
        'wifi': [{'name': 'wlan0', 'mac': '00:11:22:33:44:55', 'phy': 'phy0'}]
    }
    update.cache_set("networkDevices", devices)
    update.cache_set("deviceReservations", {
        "wlan0": DeviceReservations()
    })
    update.cache_set("subnetReservations", set())
    update.cache_set("interfaceReservations", set())

    # Missing 'ssid' field should raise exception.
    assert_raises(Exception, network.getNetworkConfig, update)

    wireless['ssid'] = "Paradrop"

    # Need to make a writable location for our config files.
    settings.UCI_CONFIG_DIR = tempfile.mkdtemp()
    settings.UCI_BACKUP_DIR = tempfile.mkdtemp()

    # Try the normal sequence of steps for installing a new chute.
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.setOSNetworkConfig(update)
    network.abortNetworkConfig(update)

    # Set up state so that old chute matches new chute.
    update.old = Chute(name="test")
    update.old.add_service(service)
    ifaces = list(update.cache_get("networkInterfaces"))
    update.old.setCache("networkInterfaces", ifaces)

    # Now try sequence of steps that would occur for a restart.
    network.reclaimNetworkResources(update.old)
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.setOSNetworkConfig(update)

    # Try asking for a new chute without any interfaces.
    service.interfaces = {}

    # This would be a restart where we remove an interface that was in old but
    # not in new.
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.setOSNetworkConfig(update)
    network.abortNetworkConfig(update)

    # Try a network interface with missing 'type' field.
    service.interfaces = {
        "wlan0": {
            'intfName': 'wlan0',
        }
    }
    assert_raises(Exception, network.getNetworkConfig, update)

    # Try asking for something funny.
    service.interfaces = {
        "wlan0": {
            'type': 'something funny',
            'intfName': 'wlan0',
        }
    }
    assert_raises(Exception, network.getNetworkConfig, update)

    # Clean up our config dir
    pdos.remove(settings.UCI_CONFIG_DIR)
    pdos.remove(settings.UCI_BACKUP_DIR)
class TestChuteApi(object):
    def __init__(self):
        self.update_manager = MagicMock()
        self.update_manager.assign_change_id.return_value = 1

        self.api = chute_api.ChuteApi(self.update_manager)

        self.interface = {
            'name': 'testing',
            'netType': 'wifi',
            'internalIntf': 'wlan0',
            'externalIntf': 'vwlan0'
        }

        chute = {'name': 'test', 'web': {'port': 5000}}
        self.chute = Chute(chute)
        self.chute.setCache("externalSystemDir", "/tmp")
        self.chute.setCache("networkInterfaces", [self.interface])

    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_get_leases(self, ChuteStorage):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()

        with open("/tmp/dnsmasq-testing.leases", "w") as output:
            output.write("1512058246 00:0d:b9:40:30:80 10.42.0.213 * *")

        result = self.api.get_leases(request, "test", "testing")
        leases = json.loads(result)
        assert len(leases) == 1
        assert leases[0]['mac_addr'] == "00:0d:b9:40:30:80"
        assert leases[0]['ip_addr'] == "10.42.0.213"

    @patch("paradrop.backend.chute_api.hostapd_control.execute")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_get_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {self.chute.name: self.chute}
        execute.return_value = "OK"

        request = MagicMock()
        result = self.api.get_ssid(request, self.chute.name,
                                   self.interface['name'])
        assert result == "OK"

    @patch("paradrop.backend.chute_api.hostapd_control.execute")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_set_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {self.chute.name: self.chute}
        execute.return_value = "OK"

        request = MagicMock()

        body = {}
        request.content.read.return_value = json.dumps(body)

        # Exception: ssid required
        assert_raises(Exception, self.api.set_ssid, request, "test", "testing")

        body = {'ssid': 'Free WiFi'}
        request.content.read.return_value = json.dumps(body)

        result = self.api.set_ssid(request, self.chute.name,
                                   self.interface['name'])
        assert result == "OK"

    @patch("paradrop.backend.chute_api.hostapd_control.execute")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_get_hostapd_status(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {self.chute.name: self.chute}
        execute.return_value = "OK"

        request = MagicMock()

        result = self.api.get_hostapd_status(request, self.chute.name,
                                             self.interface['name'])
        assert result == "OK"

    @patch("paradrop.backend.chute_api.subprocess.Popen")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_get_stations(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = [
            "Station 12:34:56:78:9a:bc (on wlan0)", "	inactive time:  304 ms",
            "	rx bytes:       18816", "	rx packets:     75",
            "	tx bytes:       5386", "	tx packets:     21",
            "	signal:         -29 dBm", "	tx bitrate:     54.0 MBit/s"
        ]

        request = MagicMock()

        result = self.api.get_stations(request, self.chute.name,
                                       self.interface['name'])
        stations = json.loads(result)
        assert len(stations) == 1
        assert stations[0]['mac_addr'] == '12:34:56:78:9a:bc'
        assert stations[0]['rx_bytes'] == '18816'
        assert stations[0]['signal'] == '-29 dBm'
        assert stations[0]['tx_bitrate'] == '54.0 MBit/s'

    @patch("paradrop.backend.chute_api.subprocess.Popen")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_get_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = [
            "Station 12:34:56:78:9a:bc (on wlan0)", "	inactive time:  304 ms",
            "	rx bytes:       18816", "	rx packets:     75",
            "	tx bytes:       5386", "	tx packets:     21",
            "	signal:         -29 dBm", "	tx bitrate:     54.0 MBit/s"
        ]

        request = MagicMock()

        result = self.api.get_station(request, self.chute.name,
                                      self.interface['name'],
                                      '12:34:56:78:9a:bc')
        station = json.loads(result)
        assert station['mac_addr'] == '12:34:56:78:9a:bc'
        assert station['rx_bytes'] == '18816'
        assert station['signal'] == '-29 dBm'
        assert station['tx_bitrate'] == '54.0 MBit/s'

    @patch("paradrop.backend.chute_api.subprocess.Popen")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_delete_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = ["OK"]

        request = MagicMock()

        result = self.api.delete_station(request, self.chute.name,
                                         self.interface['name'],
                                         '12:34:56:78:9a:bc')
        messages = json.loads(result)
        assert len(messages) == 1
        assert messages[0] == "OK"

    @patch("paradrop.backend.chute_api.WebSocketResource")
    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_hostapd_control(self, ChuteStorage, WebSocketResource):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()

        self.api.hostapd_control(request, self.chute.name,
                                 self.interface['name'])
        WebSocketResource.assert_called()

    @patch("paradrop.backend.chute_api.ChuteStorage")
    def test_set_chute_config(self, ChuteStorage):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()

        result = self.api.set_chute_config(request, self.chute.name)
        change = json.loads(result)
        assert change['change_id'] == 1