]> arthur.barton.de Git - bup.git/commitdiff
tests: tclient: fix buffering behaviour in the test
authorJohannes Berg <johannes@sipsolutions.net>
Thu, 13 Aug 2020 13:20:33 +0000 (15:20 +0200)
committerRob Browning <rlb@defaultvalue.org>
Sat, 15 Aug 2020 01:14:22 +0000 (20:14 -0500)
If the objects we write are small enough to be at least
partially buffered instead of written out to the server
connection, the test will hang in the loop as the data
hasn't made it to the server yet, which therefore can't
make a suggestion yet.

In normal non-testing scenarios this isn't an issue as
the connection is flushed before every new read(), and
thus if the client actually needs to wait for something
from the server, it'll have flushed before. Here, we're
directly poking at the internals by using has_input(),
and nothing causes a flush, causing the above scenario.

Fix this by some more ugly poking at the internals and
flush the connection before we go into the loop.

While at it, also avoid hanging there forever and break
out of the loop if one second passed without receiving
anything from the server - that should be long enough
for it to hash the two objects and respond. Also, add a
time.sleep() there to avoid busy spinning which takes
CPU cycles from the server that needs to be hashing the
object.

Reported-by: Robert Edmonds <edmonds@debian.org>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
lib/bup/t/tclient.py

index afbb09f07564373cd7db54735053d54da7003a4e..2eca440bccce6fdb6bd7e92f3e994b3f0e237bad 100644 (file)
@@ -64,11 +64,39 @@ def test_multiple_suggestions():
             s1sha = rw.new_blob(s1)
             WVPASS(rw.exists(s1sha))
             s2sha = rw.new_blob(s2)
+
             # This is a little hacky, but ensures that we test the
-            # code under test
+            # code under test. First, flush to ensure that we've
+            # actually sent all the command ('receive-objects-v2')
+            # and their data to the server. This may be needed if
+            # the output buffer size is bigger than the data (both
+            # command and objects) we're writing. To see the need
+            # for this, change the object sizes at the beginning
+            # of this file to be very small (e.g. 10 instead of 10k)
+            c.conn.outp.flush()
+
+            # Then, check if we've already received the idx files.
+            # This may happen if we're preempted just after writing
+            # the data, then the server runs and suggests, and only
+            # then we continue in PackWriter_Remote::_raw_write()
+            # and check the has_input(), in that case we'll receive
+            # the idx still in the rw.new_blob() calls above.
+            #
+            # In most cases though, that doesn't happen, and we'll
+            # get past the has_input() check before the server has
+            # a chance to respond - it has to actually hash the new
+            # object here, so it takes some time. So also break out
+            # of the loop if the server has sent something on the
+            # connection.
+            #
+            # Finally, abort this after a little while (about one
+            # second) just in case something's actually broken.
+            n = 0
             while (len(glob.glob(c.cachedir+IDX_PAT)) < 2 and
-                   not c.conn.has_input()):
-                pass
+                   not c.conn.has_input() and n < 10):
+                time.sleep(0.1)
+                n += 1
+            WVPASS(len(glob.glob(c.cachedir+IDX_PAT)) == 2 or c.conn.has_input())
             rw.new_blob(s2)
             WVPASS(rw.objcache.exists(s1sha))
             WVPASS(rw.objcache.exists(s2sha))