Merge "conman: WifiSimulateWireless experiment."
diff --git a/conman/Makefile b/conman/Makefile
index 8ff1719..0faf301 100644
--- a/conman/Makefile
+++ b/conman/Makefile
@@ -9,6 +9,7 @@
echo 'echo "(gpylint-missing)" >&2'; \
fi \
)
+NOINSTALL=%_test.py options.py experiment.py experiment_testutils.py
all:
@@ -35,7 +36,7 @@
install:
mkdir -p $(LIBDIR) $(BINDIR)
- $(INSTALL) -m 0644 $(filter-out %_test.py, $(wildcard *.py)) $(LIBDIR)/
+ $(INSTALL) -m 0644 $(filter-out $(NOINSTALL), $(wildcard *.py)) $(LIBDIR)/
$(INSTALL) -m 0755 main.py $(LIBDIR)/
rm -f $(BINDIR)/conman
ln -s /usr/conman/main.py $(BINDIR)/conman
diff --git a/conman/experiment.py b/conman/experiment.py
new file mode 120000
index 0000000..b9d7638
--- /dev/null
+++ b/conman/experiment.py
@@ -0,0 +1 @@
+../experiment.py
\ No newline at end of file
diff --git a/conman/experiment_testutils.py b/conman/experiment_testutils.py
new file mode 120000
index 0000000..cca000f
--- /dev/null
+++ b/conman/experiment_testutils.py
@@ -0,0 +1 @@
+../experiment_testutils.py
\ No newline at end of file
diff --git a/conman/interface.py b/conman/interface.py
index f575bf3..82d1506 100755
--- a/conman/interface.py
+++ b/conman/interface.py
@@ -8,6 +8,7 @@
import re
import subprocess
+import experiment
import wpactrl
METRIC_5GHZ = 20
@@ -15,6 +16,10 @@
METRIC_24GHZ = 22
METRIC_TEMPORARY_CONNECTION_CHECK = 99
+experiment.register('WifiSimulateWireless')
+CWMP_PATH = '/tmp/cwmp'
+MAX_ACS_FAILURE_S = 60
+
class Interface(object):
"""Represents an interface.
@@ -310,6 +315,33 @@
os.unlink(self._acs_autoprovisioning_filepath)
super(Bridge, self).delete_route()
+ def _connection_check(self, check_acs):
+ """Support for WifiSimulateWireless."""
+ failure_s = self._acs_session_failure_s()
+ if (experiment.enabled('WifiSimulateWireless')
+ and failure_s < MAX_ACS_FAILURE_S):
+ logging.debug('WifiSimulateWireless: failing bridge connection check (no '
+ 'ACS contact for %d seconds, max %d seconds)',
+ failure_s, MAX_ACS_FAILURE_S)
+ return False
+
+ return super(Bridge, self)._connection_check(check_acs)
+
+ def _acs_session_failure_s(self):
+ """How long have we been failing to connect to the ACS?
+
+ Returns:
+ The number of seconds between the last attempted ACS session and the last
+ successful ACS session.
+ """
+ contact = os.path.join(CWMP_PATH, 'acscontact')
+ connected = os.path.join(CWMP_PATH, 'acsconnected')
+
+ if not os.path.exists(contact) or not os.path.exists(connected):
+ return 0
+
+ return os.stat(contact).st_mtime - os.stat(connected).st_mtime
+
class Wifi(Interface):
"""Represents a wireless interface."""
diff --git a/conman/interface_test.py b/conman/interface_test.py
index 034c5b0..4283a2a 100755
--- a/conman/interface_test.py
+++ b/conman/interface_test.py
@@ -7,17 +7,21 @@
import os
import shutil
import tempfile
+import time
+
+# This has to be called before another module calls it with a higher log level.
+# pylint: disable=g-import-not-at-top
+logging.basicConfig(level=logging.DEBUG)
# This is in site-packages on the device, but not when running tests, and so
# raises lint errors.
# pylint: disable=g-bad-import-order
import wpactrl
+import experiment_testutils
import interface
from wvtest import wvtest
-logging.basicConfig(level=logging.DEBUG)
-
class FakeInterfaceMixin(object):
"""Replace Interface methods which interact with the system."""
@@ -420,5 +424,69 @@
shutil.rmtree(wifiinfo_path)
+@wvtest.wvtest
+def simulate_wireless_test():
+ """Test the WifiSimulateWireless experiment."""
+ unused_raii = experiment_testutils.MakeExperimentDirs()
+
+ tmp_dir = tempfile.mkdtemp()
+ interface.CWMP_PATH = tempfile.mkdtemp()
+ interface.MAX_ACS_FAILURE_S = 1
+
+ contact = os.path.join(interface.CWMP_PATH, 'acscontact')
+ connected = os.path.join(interface.CWMP_PATH, 'acsconnected')
+
+ try:
+ autoprov_filepath = os.path.join(tmp_dir, 'autoprov')
+ b = Bridge('br0', '10', acs_autoprovisioning_filepath=autoprov_filepath)
+ b.add_moca_station(0)
+ b.set_gateway_ip('192.168.1.1')
+ b.set_connection_check_result('succeed')
+ b.initialize()
+
+ # Initially, the connection check passes.
+ wvtest.WVPASS(b.internet())
+
+ # Enable the experiment.
+ experiment_testutils.enable('WifiSimulateWireless')
+ # Calling update_routes overwrites the connection status cache, which we
+ # need in order to see the effects we are looking for immediately
+ # (ConnectionManager calls this every few seconds).
+ b.update_routes()
+ wvtest.WVFAIL(b.internet())
+
+ # Create an ACS connection attempt.
+ open(contact, 'w')
+ b.update_routes()
+ wvtest.WVFAIL(b.internet())
+
+ # Record success.
+ open(connected, 'w')
+ b.update_routes()
+ wvtest.WVFAIL(b.internet())
+
+ # Disable the experiment and the connection check should pass again.
+ experiment_testutils.disable('WifiSimulateWireless')
+ b.update_routes()
+ wvtest.WVPASS(b.internet())
+
+ # Reenable the experiment and the connection check should fail again.
+ experiment_testutils.enable('WifiSimulateWireless')
+ b.update_routes()
+ wvtest.WVFAIL(b.internet())
+
+ # Wait until we've failed for long enough for the experiment to "expire",
+ # then log another attempt without success. Make sure the connection check
+ # passes.
+ time.sleep(interface.MAX_ACS_FAILURE_S)
+ open(contact, 'w')
+ b.update_routes()
+ wvtest.WVPASS(b.internet())
+
+ finally:
+ shutil.rmtree(tmp_dir)
+ shutil.rmtree(interface.CWMP_PATH)
+
+
if __name__ == '__main__':
wvtest.wvtest_main()