tahoe_fuse: system test: Attempt to create a dirnode to place in <basedir>/private...
authornejucomo <nejucomo@gmail.com>
Mon, 21 Jan 2008 01:47:47 +0000 (18:47 -0700)
committernejucomo <nejucomo@gmail.com>
Mon, 21 Jan 2008 01:47:47 +0000 (18:47 -0700)
This patch also factors out the "polling_operation" pattern.

contrib/fuse/runtests.py

index 4a32f095a5f25ba566ee3014c3aeea324c6e6e67..af7ef760714b2b68800497e7907a950d82de468b 100644 (file)
@@ -6,7 +6,8 @@ Note: The API design of the python-fuse library makes unit testing much
 of tahoe-fuse.py tricky business.
 '''
 
-import sys, os, shutil, unittest, subprocess, tempfile, re, time, signal
+import sys, os, shutil, unittest, subprocess
+import tempfile, re, time, signal, random, httplib
 
 import tahoe_fuse
 
@@ -48,6 +49,7 @@ class SystemTest (object):
         self.cliexec = None
         self.introbase = None
         self.clientbase = None
+        self.clientport = None
         self.mountpoint = None
 
     ## Top-level flow control:
@@ -138,28 +140,19 @@ class SystemTest (object):
     def configure_client_layer(self):
         print 'Configuring client.'
 
-        introfurl = os.path.join(self.introbase, 'introducer.furl')
-
-        # FIXME: Is there a better way to handle this race condition?
-        timeout = 10.0 # Timeout seconds.
-        pollinterval = 0.2
-        totalattempts = int(timeout / pollinterval)
+        self.clientport = random.randrange(1024, 2**15)
 
-        for attempts in range(totalattempts):
-            if os.path.isfile(introfurl):
-                tmpl = '(It took around %.2f seconds before introducer.furl was created.)'
-                print tmpl % ((attempts + 1) * pollinterval,)
-                shutil.copy(introfurl, self.clientbase)
+        f = open(os.path.join(self.clientbase, 'webport'), 'w')
+        f.write('tcp:%d:interface=127.0.0.1\n' % self.clientport)
+        f.close()
 
-                self.launch_client_layer()
-                return # skip the timeout failure.
+        introfurl = os.path.join(self.introbase, 'introducer.furl')
 
-            else:
-                time.sleep(pollinterval)
+        # FIXME: Is there a better way to handle this race condition?
+        self.polling_operation(lambda : os.path.isfile(introfurl))
+        shutil.copy(introfurl, self.clientbase)
 
-        tmpl = 'Timeout after waiting for creation of introducer.furl.\n'
-        tmpl += 'Waited %.2f seconds (%d polls).'
-        raise self.SetupFailure(tmpl, timeout, totalattempts)
+        self.launch_client_layer()
 
     def launch_client_layer(self):
         print 'Launching client.'
@@ -170,7 +163,7 @@ class SystemTest (object):
             pat = r'^STARTING (.*?)\nclient node probably started\s*$'
             self.check_tahoe_output(output, pat, self.clientbase)
 
-            self.mount_fuse_layer()
+            self.create_test_dirnode_layer()
             
         finally:
             print 'Stopping client node.'
@@ -181,6 +174,30 @@ class SystemTest (object):
                 print output
                 print 'Ignoring cleanup exception: %r' % (e,)
         
+    def create_test_dirnode_layer(self):
+        print 'Creating test dirnode.'
+        targeturl = 'http://127.0.0.1:%d/uri?t=mkdir' % (self.clientport,)
+
+        def make_dirnode():
+            conn = httplib.HTTPConnection('127.0.0.1', self.clientport)
+            conn.request('PUT', '/uri?t=mkdir')
+            resp = conn.getresponse()
+            if resp.status == '200':
+                return resp.read().strip()
+            else:
+                # FIXME: This output can be excessive!
+                print 'HTTP %s reponse while attempting to make node.' % resp.status
+                print resp.read()
+                return False # make another polling attempt...
+            
+        cap = self.polling_operation(make_dirnode)
+
+        f = open(os.path.join(self.clientbase, 'private', 'root_dir.cap'), 'w')
+        f.write(cap)
+        f.close()
+
+        self.mount_fuse_layer()
+        
     def mount_fuse_layer(self):
         print 'Mounting fuse interface.'
         self.mountpoint = tempfile.mkdtemp(prefix='tahoe_fuse_mp_')
@@ -191,7 +208,9 @@ class SystemTest (object):
             try:
                 proc = subprocess.Popen([fusescript, self.mountpoint, '-f'])
                 # FIXME: Verify the mount somehow?
-                # FIXME: Now do tests!
+
+                self.run_test_layer()
+                
             finally:
                 if proc.poll() is None:
                     print 'Killing fuse interface.'
@@ -201,6 +220,8 @@ class SystemTest (object):
         finally:
             self.cleanup_dir(self.mountpoint)
             
+    def run_test_layer(self):
+        raise NotImplementedError()
         
 
     # Utilities:
@@ -241,6 +262,45 @@ class SystemTest (object):
             print 'Exception removing test directory: %r' % (path,)
             print 'Ignoring cleanup exception: %r' % (e,)
 
+    def polling_operation(self, operation, timeout = 10.0, pollinterval = 0.2):
+        totaltime = timeout # Fudging for edge-case SetupFailure description...
+        
+        totalattempts = int(timeout / pollinterval)
+
+        starttime = time.time()
+        for attempt in range(totalattempts):
+            opstart = time.time()
+
+            try:
+                result = operation()
+            except KeyboardInterrupt, e:
+                raise
+            except Exception, e:
+                result = False
+
+            totaltime = time.time() - starttime
+
+            if result is not False:
+                tmpl = '(Polling for this condition took over %.2f seconds.)'
+                print tmpl % (totaltime,)
+                return result
+
+            elif totaltime > timeout:
+                break
+            
+            else:
+                opdelay = time.time() - opstart
+                realinterval = max(0., pollinterval - opdelay)
+                
+                #tmpl = '(Poll attempt %d failed after %.2f seconds, sleeping %.2f seconds.)'
+                #print tmpl % (attempt+1, opdelay, realinterval)
+                time.sleep(realinterval)
+
+        tmpl = 'Timeout after waiting for creation of introducer.furl.\n'
+        tmpl += 'Waited %.2f seconds (%d polls).'
+        raise self.SetupFailure(tmpl, totaltime, attempt+1)
+
+
     # SystemTest Exceptions:
     class Failure (Exception):
         pass