def test_config_devices(): """ Test paradrop.core.config.devices """ from paradrop.core.config import devices # Test the isVirtual function assert devices.isVirtual("eth0") is False assert devices.isVirtual("v0000.eth0") assert devices.isVirtual("vethabcdef") assert devices.isWAN("eth0") assert devices.isWAN("wlan0") is False update = UpdateObject({'name': 'test'}) update.old = None update.new = MagicMock() hostConfig = { 'wan': { 'interface': 'eth0' }, 'lan': { 'interfaces': ['eth1'], 'ipaddr': '192.168.1.1', 'netmask': '255.255.255.0', 'dhcp': { 'start': 100, 'limit': 100, 'leasetime': '12h' } }, 'wifi': [{'macaddr': '00:11:22:33:44:55', 'channel': 1}] } update.cache_set('hostConfig', hostConfig) settings.UCI_CONFIG_DIR = tempfile.mkdtemp() settings.UCI_BACKUP_DIR = tempfile.mkdtemp() # Calling before getSystemDevices should do nothing. devices.setSystemDevices(update) # Test normal flow---our mock functions will simulate the existence of # various network interfaces. devices.getSystemDevices(update) devices.setSystemDevices(update) cachedDevices = update.cache_get("networkDevices") assert len(cachedDevices) == 3 # Make sure it continues to work with missing devices. cachedDevices['lan'] = [] devices.setSystemDevices(update) cachedDevices['wifi'] = [] devices.setSystemDevices(update) cachedDevices['wan'] = [] devices.setSystemDevices(update) pdos.remove(settings.UCI_CONFIG_DIR) pdos.remove(settings.UCI_BACKUP_DIR)
def test_config_wifi(): """ Test paradrop.lib.config.wifi """ from paradrop.core.config import wifi update = UpdateObject({'name': 'test'}) update.old = None update.new = MagicMock() # Chute has no net information, we should pass silently. assert wifi.getOSWirelessConfig(update) is None interfaces = fake_interface_list() update.cache_set("networkInterfaces", interfaces) wifi.getOSWirelessConfig(update) # Verify the new cache entry result = update.cache_get('osWirelessConfig') assert len(result) == 1 # Need to make a writable location for our config files. settings.UCI_CONFIG_DIR = tempfile.mkdtemp() settings.UCI_BACKUP_DIR = tempfile.mkdtemp() wifi.setOSWirelessConfig(update) # Clean up our config dir pdos.remove(settings.UCI_CONFIG_DIR) pdos.remove(settings.UCI_BACKUP_DIR)
def test_config_manager(): """ Test the pdconf configuration manager """ from paradrop.confd.base import ConfigObject from paradrop.confd.manager import findConfigFiles from paradrop.base import settings settings.loadSettings(mode="unittest") files = findConfigFiles() assert isinstance(files, list) files = findConfigFiles(search="this_should_not_exist") assert isinstance(files, list) temp = tempfile.mkdtemp() manager = ConfigManager(writeDir=temp) # Test previousCommands function manager.previousCommands = [Mock(priority=5), Mock(priority=10)] result = manager.getPreviousCommands() assert list(result) == manager.previousCommands obj = ConfigObject() manager.currentConfig = { ("interface", "wan"): obj } # Make a config that matches in name and content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan")) config.optionsMatch = Mock(return_value=True) assert manager.findMatchingConfig(config, byName=False) is not None assert manager.findMatchingConfig(config, byName=True) is not None # Make a config that matches by name but not content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan")) config.optionsMatch = Mock(return_value=False) assert manager.findMatchingConfig(config, byName=False) is None assert manager.findMatchingConfig(config, byName=True) is not None # Now make one that differs in name but matches in content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan2")) config.optionsMatch = Mock(return_value=True) assert manager.findMatchingConfig(config, byName=False) is not None assert manager.findMatchingConfig(config, byName=True) is not None # Test waitSystemUp method manager.systemUp.set() result = manager.waitSystemUp() assert isinstance(result, basestring) pdos.remove(temp)
def test_config_manager(): """ Test the pdconf configuration manager """ from paradrop.backend.pdconfd.config.base import ConfigObject from paradrop.backend.pdconfd.config.manager import findConfigFiles files = findConfigFiles() assert isinstance(files, list) files = findConfigFiles(search="this_should_not_exist") assert isinstance(files, list) temp = tempfile.mkdtemp() manager = ConfigManager(writeDir=temp) # Test previousCommands function manager.previousCommands = [Mock(priority=5), Mock(priority=10)] result = manager.getPreviousCommands() assert list(result) == manager.previousCommands obj = ConfigObject() manager.currentConfig = { ("interface", "wan"): obj } # Make a config that matches in name and content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan")) config.optionsMatch = Mock(return_value=True) assert manager.findMatchingConfig(config, byName=False) is not None assert manager.findMatchingConfig(config, byName=True) is not None # Make a config that matches by name but not content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan")) config.optionsMatch = Mock(return_value=False) assert manager.findMatchingConfig(config, byName=False) is None assert manager.findMatchingConfig(config, byName=True) is not None # Now make one that differs in name but matches in content. config = Mock() config.getTypeAndName = Mock(return_value=("interface", "wan2")) config.optionsMatch = Mock(return_value=True) assert manager.findMatchingConfig(config, byName=False) is not None assert manager.findMatchingConfig(config, byName=True) is not None # Test waitSystemUp method manager.systemUp.set() result = manager.waitSystemUp() assert isinstance(result, basestring) pdos.remove(temp)
def abortCreateVolumeDirs(update): # If there is no old version of the chute, then clean up directories that # we created. Otherwise, leave them in place for the old version. if update.old is None: extDataDir = update.cache_get('externalDataDir') pdos.remove(extDataDir) extSystemDir = update.cache_get('externalSystemDir') pdos.remove(extSystemDir)
def createVolumeDirs(update): extDataDir = update.new.getCache('externalDataDir') extSystemDir = update.new.getCache('externalSystemDir') if update.updateType == 'delete': pdos.remove(extDataDir, suppressNotFound=True) pdos.remove(extSystemDir, suppressNotFound=True) else: pdosq.makedirs(extDataDir) pdosq.makedirs(extSystemDir) os.chown(extDataDir, settings.CONTAINER_UID, -1)
def testConfigLoadingExisting(): contents = dict(pdid='pd.damouse.aardvark', version=1, pdserver='http://paradrop.org', wampRouter='ws://paradrop.org:9080/ws') nexus.writeYaml(contents, settings.CONFIG_FILE) nex = TestingNexus() assert nex.info.pdid == 'pd.damouse.aardvark' assert nex.info.pdserver == 'http://paradrop.org' assert nex.info.wampRouter == 'ws://paradrop.org:9080/ws' pdos.remove(settings.CONFIG_FILE)
def test_storage(): """ Test PDStorage class """ temp = tempfile.mkdtemp() filename = os.path.join(temp, "storage") storage = PDStorage(filename, MagicMock(), None) # Constructor should have called this start function. assert storage.repeater.start.called # PDStorage needs to be subclassed; the base class always returns not # saveable. assert storage.attrSaveable() is False storage = TestStorage(filename) data = {"key": "value"} with open(filename, "w") as output: output.write("BAD CONTENTS") # The first attempt to read it will fail and try to delete the file. We # will cause the unlink to fail on the first try and let it succeed on the # second try. with patch("paradrop.lib.utils.pdos.unlink", side_effect=Exception("Boom!")): storage.loadFromDisk() assert os.path.exists(filename) storage.loadFromDisk() assert not os.path.exists(filename) # The first write will fail because we have not provided data yet. storage.saveToDisk() assert not os.path.exists(filename) # Now we will save some data and verify that we can reload it. storage.setAttr(data) # Cause the save to fail on the first try, then let it succeed. with patch("paradrop.lib.utils.pdos.open", side_effect=Exception("Boom!")): storage.saveToDisk() assert not os.path.exists(filename) storage.saveToDisk() assert os.path.exists(filename) storage.setAttr(None) storage.loadFromDisk() assert storage.getAttr() == data # Clean up pdos.remove(temp)
def createVolumeDirs(update): """ Create directories required by the chute. """ extDataDir = update.cache_get('externalDataDir') extSystemDir = update.cache_get('externalSystemDir') if update.updateType == 'delete': pdos.remove(extDataDir, suppressNotFound=True) pdos.remove(extSystemDir, suppressNotFound=True) else: pdosq.makedirs(extDataDir) pdosq.makedirs(extSystemDir) os.chown(extDataDir, settings.CONTAINER_UID, -1)
def test_storage(): """ Test PDStorage class """ temp = tempfile.mkdtemp() filename = os.path.join(temp, "storage") storage = PDStorage(filename, 0) # PDStorage needs to be subclassed; the base class always returns not # saveable. assert storage.attrSaveable() is False storage = TestStorage(filename) data = {"key": "value"} with open(filename, "w") as output: output.write("BAD CONTENTS") # The first attempt to read it will fail and try to delete the file. We # will cause the unlink to fail on the first try and let it succeed on the # second try. with patch("paradrop.lib.utils.pdos.unlink", side_effect=Exception("Boom!")): storage.loadFromDisk() assert os.path.exists(filename) storage.loadFromDisk() assert not os.path.exists(filename) # The first write will fail because we have not provided data yet. storage.saveToDisk() assert not os.path.exists(filename) # Now we will save some data and verify that we can reload it. storage.setAttr(data) # Cause the save to fail on the first try, then let it succeed. with patch("paradrop.lib.utils.pdos.open", side_effect=Exception("Boom!")): storage.saveToDisk() storage.saveToDisk() assert os.path.exists(filename) storage.setAttr(None) storage.loadFromDisk() assert storage.getAttr() == data # Clean up pdos.remove(temp)
def test_revert_config(): """ Test the revertConfig function """ from paradrop.core.config import osconfig # Need to make a writable location for our config files. settings.UCI_CONFIG_DIR = tempfile.mkdtemp() settings.UCI_BACKUP_DIR = tempfile.mkdtemp() update = UpdateObject({'name': 'test'}) update.old = None update.new = MagicMock() osconfig.revertConfig(update, "network") # Clean up our config dir pdos.remove(settings.UCI_CONFIG_DIR) pdos.remove(settings.UCI_BACKUP_DIR)
def test_config_dhcp(): """ Test paradrop.lib.config.dhcp """ from paradrop.core.config import dhcp update = UpdateObject({'name': 'test'}) update.old = None update.new = MagicMock() # Should do nothing before we set "networkInterfaces". dhcp.getVirtDHCPSettings(update) interfaces = fake_interface_list() update.cache_set("externalSystemDir", "/tmp") update.cache_set("networkInterfaces", interfaces) settings.UCI_CONFIG_DIR = tempfile.mkdtemp() settings.UCI_BACKUP_DIR = tempfile.mkdtemp() # Test code path with caching enabled dhcp.DNSMASQ_CACHE_ENABLED = True dhcp.getVirtDHCPSettings(update) dhcp.setVirtDHCPSettings(update) # Test code path with caching disabled dhcp.DNSMASQ_CACHE_ENABLED = False dhcp.getVirtDHCPSettings(update) dhcp.setVirtDHCPSettings(update) pdos.remove(settings.UCI_CONFIG_DIR) pdos.remove(settings.UCI_BACKUP_DIR) # Test with missing "lease" field. interfaces.append({ 'name': 'broken', 'dhcp': { 'start': 100, 'limit': 100 } }) assert_raises(Exception, dhcp.getVirtDHCPSettings, update)
def createVolumeDirs(update): """ Create directories required by the chute. """ extDataDir = update.cache_get('externalDataDir') extSystemDir = update.cache_get('externalSystemDir') if update.updateType == 'delete': pdos.remove(extDataDir, suppressNotFound=True) pdos.remove(extSystemDir, suppressNotFound=True) else: pdosq.makedirs(extDataDir) pdosq.makedirs(extSystemDir) try: os.chown(extDataDir, settings.CONTAINER_UID, -1) except: # chown is not permitted in strict confinement. # TODO: do we need to chmod the data directory, or does it work # fine regardless? pass
def test_pdos(): """ Test pdos utility module """ assert pdos.getMountCmd() == "mount" assert pdos.isMount("/") assert pdos.ismount("/") assert pdos.oscall("true") is None assert pdos.oscall("false") is not None assert pdos.oscall("echo hello") is None assert pdos.oscall("echo hello 1>&2") is None # Make a file, check that our functions respond correctly to it path = writeTempFile("hello") assert pdos.fixpath(path) == path assert "text" in pdos.getFileType(path) assert pdos.exists(path) assert not pdos.isdir(path) assert pdos.isfile(path) # Remove the file, check that our functions detect that pdos.unlink(path) assert pdos.fixpath(path) == path assert pdos.getFileType(path) is None assert not pdos.exists(path) assert not pdos.isdir(path) assert not pdos.isfile(path) # Make a directory there instead pdos.mkdir(path) assert pdos.fixpath(path) == path assert "directory" in pdos.getFileType(path) assert pdos.exists(path) assert pdos.isdir(path) assert not pdos.isfile(path) # Now we will do some manipulations on files under that directory a = os.path.join(path, "a") b = os.path.join(path, "b") c = os.path.join(path, "c") d = os.path.join(path, "d") pdos.write(a, "hello") assert pdos.isfile(a) pdos.copy(a, b) assert pdos.isfile(b) pdos.symlink(a, c) assert pdos.isfile(c) pdos.move(a, b) assert not pdos.isfile(a) pdos.remove(b) assert not pdos.isfile(b) pdos.mkdir(a) pdos.copytree(a, b) assert pdos.isdir(b) # Remove a non-empty directory pdos.remove(path) assert not pdos.isdir(path) # This file is under a directory that no longer exists, so the write must # fail. # # TODO: These should not fail silently. They should either return an error # indicator or raise an exception. pdos.writeFile(a, "c") pdos.write(a, "c") # Test various ways to call writeFile pdos.writeFile(path, ["a", "b"]) pdos.writeFile(path, "c") pdos.writeFile(path, 5) # This one does nothing. # Test the content with readFile data = pdos.readFile(path, array=False, delimiter="") assert data == "abc" data = pdos.readFile(path, array=True) assert data == ["a", "b", "c"] pdos.remove(path) assert pdos.readFile(path) is None
def teardown(): pdos.remove(settings.CONFIG_HOME_DIR)
def test_get_network_config(): """ Test generating network configuration for a chute update. """ from paradrop.lib.config import network # Test interfaceDefsEqual function iface1 = { 'name': 'mywifi', 'netType': 'wifi', 'internalIntf': 'wlan0' } iface2 = iface1.copy() assert network.interfaceDefsEqual(iface1, iface2) iface2['internalIntf'] = 'wlan1' assert not network.interfaceDefsEqual(iface1, iface2) # 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 = MockUpdate() update.old = None update.new = MockChute() # 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 update.new.net = { 'mywifi': { 'type': 'wifi', 'intfName': 'wlan0', 'encryption': 'psk2', 'key': 'password' } } devices = { 'wifi': [{'name': 'wlan0'}] } update.new.setCache("networkDevices", devices) # Missing 'ssid' field should raise exception. assert_raises(Exception, network.getNetworkConfig, update) update.new.net['mywifi']['ssid'] = "Paradrop" # Need to make a writable location for our config files. settings.UCI_CONFIG_DIR = tempfile.mkdtemp() # Try the normal sequence of steps for installing a new chute. network.getNetworkConfig(update) network.getOSNetworkConfig(update) network.getVirtNetworkConfig(update) network.setOSNetworkConfig(update) network.abortNetworkConfig(update) # Set up state so that old chute matches new chute. update.old = MockChute() update.old.net = update.new.net.copy() ifaces = list(update.new.getCache("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.getVirtNetworkConfig(update) network.setOSNetworkConfig(update) # Try asking for a new chute without any interfaces. update.new.net = dict() # 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.getVirtNetworkConfig(update) network.setOSNetworkConfig(update) network.abortNetworkConfig(update) # Try a network interface with missing 'type' field. update.new.net = { 'mywifi': { 'intfName': 'wlan0', } } assert_raises(Exception, network.getNetworkConfig, update) # Try asking for something funny. update.new.net = { 'mywifi': { 'type': 'fail', 'intfName': 'wlan0', } } assert_raises(Exception, network.getNetworkConfig, update) # Clean up our config dir pdos.remove(settings.UCI_CONFIG_DIR)
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)
def test_config_firewall(): """ Test paradrop.lib.config.firewall """ from paradrop.core.config import firewall # Test findMatchingInterface function interfaces = fake_interface_list() assert firewall.findMatchingInterface("*wifi", interfaces) is not None assert firewall.findMatchingInterface("??lan", interfaces) is not None assert firewall.findMatchingInterface("missing", interfaces) is None update = UpdateObject({'name': 'test'}) update.old = None update.new = MagicMock() # No interfaces in the cache---should return without a problem firewall.getOSFirewallRules(update) firewall.getDeveloperFirewallRules(update) update.cache_set("networkInterfaces", interfaces) firewall.getOSFirewallRules(update) result = update.cache_get("osFirewallRules") assert len(result) >= 4 update.new.firewall = fake_rules_list() firewall.getDeveloperFirewallRules(update) result = update.cache_get('developerFirewallRules') assert len(result) == 1 # Need to make a writable location for our config files. settings.UCI_CONFIG_DIR = tempfile.mkdtemp() settings.UCI_BACKUP_DIR = tempfile.mkdtemp() firewall.setOSFirewallRules(update) pdos.remove(settings.UCI_CONFIG_DIR) pdos.remove(settings.UCI_BACKUP_DIR) # Try a bad rule that has both from/to outside the chute. update.new.firewall = fake_rules_list() update.new.firewall.append({ 'name': 'bad', 'type': 'redirect', 'from': '@host.lan', 'to': '@host.lan' }) assert_raises(Exception, firewall.getDeveloperFirewallRules, update) # Try a bad rule that does not match an interface. update.new.firewall = fake_rules_list() update.new.firewall.append({ 'name': 'bad', 'type': 'redirect', 'from': '@host.lan', 'to': 'missing' }) assert_raises(Exception, firewall.getDeveloperFirewallRules, update) # Try an SNAT rule, which is not currently supported. update.new.firewall = fake_rules_list() update.new.firewall.append({ 'name': 'bad', 'type': 'redirect', 'from': 'missing', 'to': '@host.lan' }) assert_raises(Exception, firewall.getDeveloperFirewallRules, update) # Try something else that we do not recognize. update.new.firewall = fake_rules_list() update.new.firewall.append({ 'name': 'bad', 'type': 'redirect', 'from': 'missing', 'to': 'missing' }) assert_raises(Exception, firewall.getDeveloperFirewallRules, update)
def test_pdos(): """ Test pdos utility module """ assert pdos.getMountCmd() == "mount" assert pdos.isMount("/") assert pdos.ismount("/") assert pdos.oscall("true") is None assert pdos.oscall("false") is not None assert pdos.oscall("echo hello") is None assert pdos.oscall("echo hello 1>&2") is None assert pdos.syncFS() is None # Make a file, check that our functions respond correctly to it path = writeTempFile("hello") assert pdos.fixpath(path) == path assert "text" in pdos.getFileType(path) assert pdos.exists(path) assert not pdos.isdir(path) assert pdos.isfile(path) # Remove the file, check that our functions detect that pdos.unlink(path) assert pdos.fixpath(path) == path assert pdos.getFileType(path) is None assert not pdos.exists(path) assert not pdos.isdir(path) assert not pdos.isfile(path) # Make a directory there instead pdos.mkdir(path) assert pdos.fixpath(path) == path assert "directory" in pdos.getFileType(path) assert pdos.exists(path) assert pdos.isdir(path) assert not pdos.isfile(path) # Now we will do some manipulations on files under that directory a = os.path.join(path, "a") b = os.path.join(path, "b") c = os.path.join(path, "c") d = os.path.join(path, "d") pdos.write(a, "hello") assert pdos.isfile(a) pdos.copy(a, b) assert pdos.isfile(b) pdos.symlink(a, c) assert pdos.isfile(c) pdos.move(a, b) assert not pdos.isfile(a) pdos.remove(b) assert not pdos.isfile(b) pdos.mkdir(a) pdos.copytree(a, b) assert pdos.isdir(b) # Remove a non-empty directory pdos.remove(path) assert not pdos.isdir(path) # This file is under a directory that no longer exists, so the write must # fail. # # TODO: These should not fail silently. They should either return an error # indicator or raise an exception. pdos.writeFile(a, "c") pdos.write(a, "c") # Test various ways to call writeFile pdos.writeFile(path, ["a", "b"]) pdos.writeFile(path, "c") pdos.writeFile(path, 5) # This one does nothing. # Test the content with readFile data = pdos.readFile(path, array=False, delimiter="") assert data == "abc" data = pdos.readFile(path, array=True) assert data == ["a", "b", "c"] pdos.remove(path) assert pdos.readFile(path) is None
def clearChuteStorage(self): ChuteStorage.chuteList = {} pdos.remove(settings.FC_CHUTESTORAGE_SAVE_PATH)