[tor-commits] [stem/master] Adding separate funtion for launching tor with tmp torrc

atagar at torproject.org atagar at torproject.org
Sun May 20 22:15:45 UTC 2012


commit 4d6c8c8943d9540d5fcc6c39c503ca523e4683d3
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun May 20 14:49:31 2012 -0700

    Adding separate funtion for launching tor with tmp torrc
    
    Like Vidalia, adding a function that creates a torrc, launches tor with it,
    then removes it from disk. This is preferable to using the commandline
    arguments since the those shouldn't be used for substantial data nor the hashed
    password.
    
    This replaces launch_tor()'s options argument, though I added a more genral
    args replacement that can be used to do the same if the user wants.
---
 stem/process.py       |   52 ++++++++++++++++++++++++++++++++++++++++--------
 test/integ/process.py |   26 ++++++-----------------
 test/runner.py        |    2 +
 3 files changed, 52 insertions(+), 28 deletions(-)

diff --git a/stem/process.py b/stem/process.py
index 32bf1a7..a65c124 100644
--- a/stem/process.py
+++ b/stem/process.py
@@ -1,7 +1,8 @@
 """
 Helper functions for working with tor as a process.
 
-launch_tor - starts up a tor process
+launch_tor             - starts up a tor process
+launch_tor_with_config - starts a tor process with a custom torrc
 """
 
 import re
@@ -18,7 +19,7 @@ DEFAULT_INIT_TIMEOUT = 90
 
 NO_TORRC = "<no torrc>"
 
-def launch_tor(tor_cmd = "tor", options = None, torrc_path = None, completion_percent = 100, init_msg_handler = None, timeout = DEFAULT_INIT_TIMEOUT):
+def launch_tor(tor_cmd = "tor", args = None, torrc_path = None, completion_percent = 100, init_msg_handler = None, timeout = DEFAULT_INIT_TIMEOUT):
   """
   Initializes a tor process. This blocks until initialization completes or we
   error out.
@@ -30,7 +31,7 @@ def launch_tor(tor_cmd = "tor", options = None, torrc_path = None, completion_pe
   
   Arguments:
     tor_cmd (str)              - command for starting tor
-    options (dict)             - configuration options, such as ("ControlPort": "9051")
+    args (list)                - additional arguments for tor
     torrc_path (str)           - location of the torrc for us to use
     completion_percent (int)   - percent of bootstrap completion at which
                                  this'll return
@@ -53,18 +54,15 @@ def launch_tor(tor_cmd = "tor", options = None, torrc_path = None, completion_pe
   
   # starts a tor subprocess, raising an OSError if it fails
   runtime_args, temp_file = [tor_cmd], None
+  if args: runtime_args += args
+  
   if torrc_path:
     if torrc_path == NO_TORRC:
-      temp_file = tempfile.mkstemp("-empty-torrc", text = True)[1]
+      temp_file = tempfile.mkstemp(prefix = "empty-torrc-", text = True)[1]
       runtime_args += ["-f", temp_file]
     else:
       runtime_args += ["-f", torrc_path]
   
-  if options:
-    for key, value in options.items():
-      value = value.replace('"', '\\"')
-      runtime_args += ["--%s" % key.lower(), value]
-  
   tor_process = subprocess.Popen(runtime_args, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
   
   if timeout:
@@ -112,3 +110,39 @@ def launch_tor(tor_cmd = "tor", options = None, torrc_path = None, completion_pe
         if ": " in msg: msg = msg.split(": ")[-1].strip()
         last_problem = msg
 
+def launch_tor_with_config(config, tor_cmd = "tor", completion_percent = 100, init_msg_handler = None, timeout = DEFAULT_INIT_TIMEOUT):
+  """
+  Initializes a tor process, like launch_tor(), but with a customized
+  configuration. This writes a temporary torrc to disk, launches tor, then
+  deletes the torrc.
+  
+  Arguments:
+    config (dict)              - configuration options, such as ("ControlPort": "9051")
+    tor_cmd (str)              - command for starting tor
+    completion_percent (int)   - percent of bootstrap completion at which
+                                 this'll return
+    init_msg_handler (functor) - optional functor that will be provided with
+                                 tor's initialization stdout as we get it
+    timeout (int)              - time after which the attempt to start tor is
+                                 aborted, no timeouts are applied if None
+  
+  Returns:
+    subprocess.Popen instance for the tor subprocess
+  
+  Raises:
+    OSError if we either fail to create the tor process or reached a timeout
+    without success
+  """
+  
+  torrc_path = tempfile.mkstemp(prefix = "torrc-", text = True)[1]
+  
+  try:
+    with open(torrc_path, "w") as torrc_file:
+      for key, value in config.items():
+        torrc_file.write("%s %s\n" % (key, value))
+    
+    return launch_tor(tor_cmd, None, torrc_path, completion_percent, init_msg_handler, timeout)
+  finally:
+    try: os.remove(torrc_path)
+    except: pass
+
diff --git a/test/integ/process.py b/test/integ/process.py
index f189f46..b7e5040 100644
--- a/test/integ/process.py
+++ b/test/integ/process.py
@@ -9,26 +9,19 @@ import stem.socket
 import stem.process
 import test.runner
 
-# Tests are target independent. Only run once even if there's multiple targets.
-
-RAN_TESTS = []
-
 class TestProcess(unittest.TestCase):
-  def test_launch_tor_options(self):
+  def test_launch_tor_with_config(self):
     """
-    Runs launch_tor with options specified via the commandline rather than the
-    torrc.
+    Exercises launch_tor_with_config.
     """
     
-    test_name = 'test_launch_tor_options'
-    if test_name in RAN_TESTS: self.skipTest("(already ran)")
+    test.runner.only_run_once(self, "test_launch_tor_with_config")
     
     # Launch tor without a torrc, but with a control port. Confirms that this
     # works by checking that we're still able to access the new instance.
     
-    tor_process = stem.process.launch_tor(
-      options = {'SocksPort': '2777', 'ControlPort': '2778'},
-      torrc_path = stem.process.NO_TORRC,
+    tor_process = stem.process.launch_tor_with_config(
+      config = {'SocksPort': '2777', 'ControlPort': '2778'},
       completion_percent = 5
     )
     
@@ -45,21 +38,16 @@ class TestProcess(unittest.TestCase):
     finally:
       if control_socket: control_socket.close()
       tor_process.kill()
-    
-    RAN_TESTS.append(test_name)
   
   def test_launch_tor_with_timeout(self):
     """
     Runs launch_tor where it times out before completing.
     """
     
-    test_name = 'test_launch_tor_with_timeout'
-    if test_name in RAN_TESTS: self.skipTest("(already ran)")
+    test.runner.only_run_once(self, "test_launch_tor_with_timeout")
     
     start_time = time.time()
-    self.assertRaises(OSError, stem.process.launch_tor, "tor", {'SocksPort': '2777'}, stem.process.NO_TORRC, 100, None, 2)
+    self.assertRaises(OSError, stem.process.launch_tor_with_config, {'SocksPort': '2777'}, "tor", 100, None, 2)
     runtime = time.time() - start_time
     self.assertTrue(runtime > 2 and runtime < 3)
-    
-    RAN_TESTS.append(test_name)
 
diff --git a/test/runner.py b/test/runner.py
index 2dc0cbb..286d4a8 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -123,6 +123,8 @@ def require_version(test_case, req_version):
 def only_run_once(test_case, test_name):
   """
   Skips the test if it has ran before. If it hasn't then flags it as being ran.
+  This is useful to prevent lengthy tests that are independent of integ targets
+  from being run repeatedly with RUN_ALL.
   
   Arguments:
     test_case (unittest.TestCase) - test being ran





More information about the tor-commits mailing list