Retry client connections in selftest
authorJeremy Stanley <fungi@yuggoth.org>
Sat, 17 Apr 2021 16:07:33 +0000 (16:07 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Sat, 24 Apr 2021 13:31:41 +0000 (13:31 +0000)
Replace a hard-coded delay after process start with a dynamic client
connection retry, which attempts to connect up to five times with
the first being immediate while subsequent connections observe an
exponential backoff over a three-second period before giving up.
This improves both speed and stability of test runs.

Also combine the ConnectionResetError and EOFError conditions which
could be raised later once the socket is in use, as the end result
of either is effectively the same.

mudpy/tests/selftest.py

index bb6f28a..c0bfc3c 100644 (file)
@@ -477,7 +477,6 @@ def start_service(config):
     service = subprocess.Popen(("mudpy", config),
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
-    time.sleep(1)
     return service
 
 
@@ -551,6 +550,31 @@ def check_debug():
     return False
 
 
+def connect_client(luser, service):
+    # Try multiple times to connect, with an exponential backoff
+    for retry in range(5):
+        try:
+            # Skipping the retry=0 case gives an immediate first attempt
+            if retry:
+                time.sleep((2 ** retry) / 10)
+            luser.open("::1", 4000)
+            # Attempt to poll the connection, closing if unusable
+            try:
+                luser.fill_rawq()
+            except ConnectionResetError:
+                luser.close()
+                continue
+            # Short-circuit if we get this far, connection is safe to use
+            return luser
+        except ConnectionRefusedError:
+            continue
+    else:
+        # Connection retries have been exhausted, so give up
+        tlog("\nERROR: Client could not connect.\n")
+        stop_service(service)
+        sys.exit(1)
+
+
 def main():
     captures = ["", "", ""]
     lusers = [telnetlib.Telnet(), telnetlib.Telnet(), telnetlib.Telnet()]
@@ -564,7 +588,7 @@ def main():
             tlog("\nERROR: Service did not start.\n")
             sys.exit(1)
     for luser in lusers:
-        luser.open("::1", 4000)
+        connect_client(luser, service)
         luser.set_option_negotiation_callback(option_callback)
     selected_dialogue = dict(dialogue)
     if check_debug():
@@ -583,11 +607,7 @@ def main():
                 index, match, received = lusers[conversant].expect(
                     [re.compile(question.encode("utf-8"), flags=re.DOTALL)], 5)
                 captures[conversant] += received.decode("utf-8")
-            except ConnectionResetError:
-                tlog("\nERROR: Unable to connect to server.")
-                success = False
-                break
-            except EOFError:
+            except (ConnectionResetError, EOFError):
                 tlog("\nERROR: luser%s premature disconnection expecting:\n\n"
                      "%s\n\n"
                      "Check the end of capture_%s.log for received data."