diff --git a/src/crystal/tests/test_shell.py b/src/crystal/tests/test_shell.py index eb6d3be1..fa94e6e8 100644 --- a/src/crystal/tests/test_shell.py +++ b/src/crystal/tests/test_shell.py @@ -789,6 +789,9 @@ def _read_until( try: delta_time = 0.0 while True: + # 1. Wait for stream to be ready to read or hit EOF + # 2. Read stream (if became ready) + # 3. Look for an acceptable `stop_suffix` at the end of everything read so far remaining_time = hard_timeout - delta_time assert remaining_time > 0 (rlist_ready, _, xlist_ready) = select( @@ -797,17 +800,27 @@ def _read_until( [stream], remaining_time) did_time_out = (len(rlist_ready) + len(xlist_ready) == 0) - if not did_time_out: - # NOTE: Quadratic performance. + if did_time_out: + # Look for an acceptable "stop suffix" + # Special case: '' is always an acceptable `stop_suffix` + if '' in stop_suffix_bytes_choices: + found_stop_suffix = '' + else: + # Read stream + # NOTE: Append uses quadratic performance. # Not using for large amounts of text so I don't care. read_buffer += stream.buffer.read1(1024) # type: ignore[attr-defined] # arbitrary + # Look for an acceptable "stop suffix" for (i, s_bytes) in enumerate(stop_suffix_bytes_choices): if read_buffer.endswith(s_bytes): found_stop_suffix = stop_suffix[i] break - if found_stop_suffix is not None: - break + if found_stop_suffix is not None: + # Done + break + + # If hard timeout exceeded then raise delta_time = time.time() - start_time if did_time_out or delta_time >= hard_timeout: hard_timeout_exceeded = True @@ -818,7 +831,7 @@ def _read_until( f'Read so far: {read_so_far!r}', read_so_far) finally: - # Warn if soft timeout exceeded + # If soft timeout exceeded then warn before returning if not hard_timeout_exceeded: delta_time = time.time() - start_time if delta_time > soft_timeout: