WIP on final version of accepted INFOCOM paper.
[quix0rs-apt-p2p.git] / test.py
diff --git a/test.py b/test.py
index 5468a1d28e62bd65277ef5494cdc35dfb1b81ae5..ac7892ad7cbae233e00b8a94bdd79ac82b4bf4ff 100755 (executable)
--- a/test.py
+++ b/test.py
@@ -1,9 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/python
 
-"""Automated tests of the apt-dht functionality.
+"""Automated tests of the apt-p2p functionality.
 
 This script runs several automatic tests of some of the functionality in
-the apt-dht program.
+the apt-p2p program.
 
 @type tests: C{dictionary}
 @var tests: all of the tests that can be run.
@@ -14,12 +14,12 @@ the apt-dht program.
     and the apt-get commands to run (C{list}).
     
     The bootstrap nodes keys are integers, which must be in the range 1-9.
-    The values are the dictionary of string formatting values for creating
-    the apt-dht configuration file (see L{apt_dht_conf_template} below).
+    The values are the dictionary of keyword options to pass to the function
+    that starts the bootstrap node (see L{start_bootstrap} below).
     
     The downloaders keys are also integers in the range 1-99. The values are
-    the dictionary of string formatting values for creating the apt-dht
-    configuration file (see L{apt_dht_conf_template} below).
+    the dictionary of keyword options to pass to the function
+    that starts the downloader node (see L{start_downloader} below).
     
     The apt-get commands' list elements are tuples with 2 elements: the
     downloader to run the command on, and the list of command-line
@@ -29,7 +29,8 @@ the apt-dht program.
 @var CWD: the working directory the script was run from
 @type apt_conf_template: C{string}
 @var apt_conf_template: the template to use for the apt.conf file
-
+@type apt_p2p_conf_template: C{string}
+@var apt_p2p_conf_template: the template to use for the apt-p2p.conf file
 """
 
 from time import sleep, time
@@ -47,11 +48,9 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
               (1, ['install', 'ada-reference-manual']),
               (1, ['install', 'aspectj-doc']),
               (1, ['install', 'fop-doc']),
-              (1, ['install', 'jswat-doc']),
               (1, ['install', 'asis-doc']),
               (1, ['install', 'bison-doc']),
               (1, ['install', 'crash-whitepaper']),
-              (1, ['install', 'doc-iana']),
               ]),
 
          '2': ('Start a single bootstrap and 2 downloaders to test downloading from a peer.',
@@ -65,13 +64,11 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
                 (1, ['install', 'aap-doc']),
                 (1, ['install', 'ada-reference-manual']),
                 (1, ['install', 'fop-doc']),
-                (1, ['install', 'jswat-doc']),
                 (1, ['install', 'bison-doc']),
                 (1, ['install', 'crash-whitepaper']),
                 (2, ['install', 'aap-doc']),
                 (2, ['install', 'ada-reference-manual']),
                 (2, ['install', 'fop-doc']),
-                (2, ['install', 'jswat-doc']),
                 (2, ['install', 'bison-doc']),
                 (2, ['install', 'crash-whitepaper']),
                 ]),
@@ -89,32 +86,32 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
                 (1, ['install', 'aboot-base']),
                 (1, ['install', 'ada-reference-manual']),
                 (1, ['install', 'fop-doc']),
-                (1, ['install', 'doc-iana']),
+                (1, ['install', 'crash-whitepaper']),
                 (2, ['update']),
                 (2, ['install', 'aboot-base']),
                 (2, ['install', 'ada-reference-manual']),
                 (2, ['install', 'fop-doc']),
-                (2, ['install', 'doc-iana']),
+                (2, ['install', 'crash-whitepaper']),
                 (3, ['update']),
                 (3, ['install', 'aboot-base']),
                 (3, ['install', 'ada-reference-manual']),
                 (3, ['install', 'fop-doc']),
-                (3, ['install', 'doc-iana']),
+                (3, ['install', 'crash-whitepaper']),
                 (4, ['update']),
                 (4, ['install', 'aboot-base']),
                 (4, ['install', 'ada-reference-manual']),
                 (4, ['install', 'fop-doc']),
-                (4, ['install', 'doc-iana']),
+                (4, ['install', 'crash-whitepaper']),
                 (5, ['update']),
                 (5, ['install', 'aboot-base']),
                 (5, ['install', 'ada-reference-manual']),
                 (5, ['install', 'fop-doc']),
-                (5, ['install', 'doc-iana']),
+                (5, ['install', 'crash-whitepaper']),
                 (6, ['update']),
                 (6, ['install', 'aboot-base']),
                 (6, ['install', 'ada-reference-manual']),
                 (6, ['install', 'fop-doc']),
-                (6, ['install', 'doc-iana']),
+                (6, ['install', 'crash-whitepaper']),
                 ]),
 
          '4': ('Start a single bootstrap and 1 downloader, requesting the same' +
@@ -125,17 +122,17 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
                 (1, ['install', 'aboot-base']),
                 (1, ['install', 'ada-reference-manual']),
                 (1, ['install', 'fop-doc']),
-                (1, ['install', 'doc-iana']),
+                (1, ['install', 'crash-whitepaper']),
                 (1, ['update']),
                 (1, ['install', 'aboot-base']),
                 (1, ['install', 'ada-reference-manual']),
                 (1, ['install', 'fop-doc']),
-                (1, ['install', 'doc-iana']),
+                (1, ['install', 'crash-whitepaper']),
                 (1, ['update']),
                 (1, ['install', 'aboot-base']),
                 (1, ['install', 'ada-reference-manual']),
                 (1, ['install', 'fop-doc']),
-                (1, ['install', 'doc-iana']),
+                (1, ['install', 'crash-whitepaper']),
                 ]),
                 
          '5': ('Start a single bootstrap and 6 downloaders, update all to test' +
@@ -169,12 +166,12 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
              {1: {}},
              [(1, ['update']), 
               (1, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               ]),
 
@@ -188,57 +185,179 @@ tests = {'1': ('Start a single bootstrap and downloader, test updating and downl
               6: {}},
              [(1, ['update']), 
               (1, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               (2, ['update']), 
               (2, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               (3, ['update']), 
               (3, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               (4, ['update']), 
               (4, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               (5, ['update']), 
               (5, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               (6, ['update']), 
               (6, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
-                   'aspectj-doc', 'fop-doc', 'jswat-doc', 'asis-doc',
-                   'bison-doc', 'crash-whitepaper', 'doc-iana',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              ]),
+
+         '9': ('Start a single bootstrap and 6 downloaders and test downloading' +
+               ' a very large file.',
+               {1: {}},
+               {1: {},
+                2: {},
+                3: {},
+                4: {},
+                5: {},
+                6: {}},
+               [(1, ['update']),
+                (1, ['install', 'kde-icons-oxygen']),
+                (2, ['update']),
+                (2, ['install', 'kde-icons-oxygen']),
+                (3, ['update']),
+                (3, ['install', 'kde-icons-oxygen']),
+                (4, ['update']),
+                (4, ['install', 'kde-icons-oxygen']),
+                (5, ['update']),
+                (5, ['install', 'kde-icons-oxygen']),
+                (6, ['update']),
+                (6, ['install', 'kde-icons-oxygen']),
+                ]),
+
+        'a': ('Test pipelining and caching, can also interrupt or restart to test resuming.',
+             {1: {'clean': False}},
+             {1: {'clean': False},
+              2: {'clean': False}},
+            [(1, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              (1, ['update']), 
+              (1, ['update']), 
+              (1, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              (1, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              (2, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              (2, ['update']), 
+              (2, ['update']), 
+              (2, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              (2, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
+                   'bash-doc', 'apt-howto-common', 'autotools-dev',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
+                   ]),
+              ]),
+
+         'b': ('Start 2 downloaders and test source downloads.',
+               {1: {}},
+               {1: {'types': ['deb-src']},
+                2: {'types': ['deb-src']}},
+               [(1, ['update']),
+                (2, ['update']),
+                (1, ['source', 'aboot-base']),
+                (2, ['source', 'aboot-base']),
+                (1, ['source', 'aap-doc']),
+                (1, ['source', 'ada-reference-manual']),
+                (1, ['source', 'fop-doc']),
+                (1, ['source', 'bison-doc']),
+                (1, ['source', 'crash-whitepaper']),
+                (2, ['source', 'aap-doc']),
+                (2, ['source', 'ada-reference-manual']),
+                (2, ['source', 'fop-doc']),
+                (2, ['source', 'bison-doc']),
+                (2, ['source', 'crash-whitepaper']),
+                ]),
+                
+        'c': ('Test downloading from peers and just a mirror.',
+             {1: {}},
+             {1: {},
+              2: {}},
+             [(1, ['update']), 
+              (1, ['install', 'aboot-base', 'ada-reference-manual',
+                   'fop-doc', 'bison-doc', 'crash-whitepaper',
+                   'apt-howto-common', 'aptitude-doc-en', 'asr-manpages',
+                   'alcovebook-sgml-doc', 'airstrike-common',
+                   ]),
+              (2, ['update']), 
+              (2, ['install', 'aboot-base', 'aap-doc', 'ada-reference-manual',
+                   'aspectj-doc', 'fop-doc', 'asis-doc',
+                   'bison-doc', 'crash-whitepaper',
                    'bash-doc', 'apt-howto-common', 'autotools-dev',
-                   'aptitude-doc-en', 'armagetron-common', 'asr-manpages',
-                   'atomix-data', 'alcovebook-sgml-doc', 'alamin-doc',
-                   'aegis-doc', 'afbackup-common', 'airstrike-common',
+                   'aptitude-doc-en', 'asr-manpages',
+                   'atomix-data', 'alcovebook-sgml-doc',
+                   'afbackup-common', 'airstrike-common',
                    ]),
               ]),
 
@@ -305,19 +424,28 @@ Debug
   NoLocking "false";
   Acquire::Ftp "false";    // Show ftp command traffic
   Acquire::Http "false";   // Show http command traffic
-  Acquire::Debtorrent "false";   // Show http command traffic
   Acquire::gpgv "false";   // Show the gpgv traffic
   aptcdrom "false";        // Show found package files
   IdentCdrom "false";
 
 }
 """
-apt_dht_conf_template = """
+apt_p2p_conf_template = """
 [DEFAULT]
 
 # Port to listen on for all requests (TCP and UDP)
 PORT = %(PORT)s
     
+# The rate to limit sending data to peers to, in KBytes/sec.
+# Set this to 0 to not limit the upload bandwidth.
+UPLOAD_LIMIT = 100
+
+# The minimum number of peers before the mirror is not used.
+# If there are fewer peers than this for a file, the mirror will also be
+# used to speed up the download. Set to 0 to never use the mirror if
+# there are peers.
+MIN_DOWNLOAD_PEERS = 3
+
 # Directory to store the downloaded files in
 CACHE_DIR = %(CACHE_DIR)s
     
@@ -326,12 +454,12 @@ CACHE_DIR = %(CACHE_DIR)s
 #          for everybody to download
 # OTHER_DIRS = 
     
-# User name to try and run as
-# USERNAME = 
-
 # Whether it's OK to use an IP addres from a known local/private range
 LOCAL_OK = yes
 
+# Whether a remote peer can access the statistics page
+REMOTE_STATS = yes
+
 # Unload the packages cache after an interval of inactivity this long.
 # The packages cache uses a lot of memory, and only takes a few seconds
 # to reload when a new request arrives.
@@ -339,37 +467,42 @@ UNLOAD_PACKAGES_CACHE = 5m
 
 # Refresh the DHT keys after this much time has passed.
 # This should be a time slightly less than the DHT's KEY_EXPIRE value.
-KEY_REFRESH = 57m
+KEY_REFRESH = 2.5h
+
+# The user name to try and run as (leave blank to run as current user)
+USERNAME = 
 
 # Which DHT implementation to use.
 # It must be possile to do "from <DHT>.DHT import DHT" to get a class that
 # implements the IDHT interface.
-DHT = apt_dht_Khashmir
+DHT = apt_p2p_Khashmir
 
 # Whether to only run the DHT (for providing only a bootstrap node)
 DHT-ONLY = %(DHT-ONLY)s
 
-[apt_dht_Khashmir]
+[apt_p2p_Khashmir]
 # bootstrap nodes to contact to join the DHT
 BOOTSTRAP = %(BOOTSTRAP)s
 
 # whether this node is a bootstrap node
 BOOTSTRAP_NODE = %(BOOTSTRAP_NODE)s
 
-# Kademlia "K" constant, this should be an even number
-K = 8
-
-# SHA1 is 160 bits long
-HASH_LENGTH = 160
-
 # checkpoint every this many seconds
 CHECKPOINT_INTERVAL = 5m
 
 # concurrent xmlrpc calls per find node/value request!
-CONCURRENT_REQS = 4
+CONCURRENT_REQS = 8
 
 # how many hosts to post to
-STORE_REDUNDANCY = 3
+STORE_REDUNDANCY = 6
+
+# How many values to attempt to retrieve from the DHT.
+# Setting this to 0 will try and get all values (which could take a while if
+# a lot of nodes have values). Setting it negative will try to get that
+# number of results from only the closest STORE_REDUNDANCY nodes to the hash.
+# The default is a large negative number so all values from the closest
+# STORE_REDUNDANCY nodes will be retrieved.
+RETRIEVE_VALUES = -10000
 
 # how many times in a row a node can fail to respond before it's booted from the routing table
 MAX_FAILURES = 3
@@ -380,8 +513,24 @@ MIN_PING_INTERVAL = 15m
 # refresh buckets that haven't been touched in this long
 BUCKET_STALENESS = 1h
 
+# Whether it's OK to add nodes to the routing table that use an IP
+# address from a known local/private range.
+# If not specified here, the LOCAL_OK value in the DEFAULT section will be used.
+LOCAL_OK = yes
+
 # expire entries older than this
-KEY_EXPIRE = 1h
+KEY_EXPIRE = 3h
+
+# Timeout KRPC requests to nodes after this time.
+KRPC_TIMEOUT = 9s
+
+# KRPC requests are resent using exponential backoff starting with this delay.
+# The request will first be resent after the delay set here.
+# The request will be resent again after twice the delay set here. etc.
+# e.g. if TIMEOUT is 9 sec., and INITIAL_DELAY is 2 sec., then requests will
+# be resent at times 0, 2 (2 sec. later), and 6 (4 sec. later), and then will
+# timeout at 9.
+KRPC_INITIAL_DELAY = 2s
 
 # whether to spew info about the requests/responses in the protocol
 SPEW = yes
@@ -453,6 +602,8 @@ def start(cmd, args, work_dir = None):
     """
     
     new_cmd = [cmd] + args
+    if work_dir:
+        os.chdir(work_dir)
     pid = os.spawnvp(os.P_NOWAIT, new_cmd[0], new_cmd)
     return pid
 
@@ -514,11 +665,15 @@ def apt_get(num_down, cmd):
     
     """
     
+    downloader_dir = down_dir(num_down)
+    rmrf(join([downloader_dir, 'var', 'cache', 'apt', 'archives']))
+    makedirs([downloader_dir, 'var', 'cache', 'apt', 'archives', 'partial'])
+
     print '*************** apt-get (' + str(num_down) + ') ' + ' '.join(cmd) + ' ****************'
     apt_conf = join([down_dir(num_down), 'etc', 'apt', 'apt.conf'])
     dpkg_status = join([down_dir(num_down), 'var', 'lib', 'dpkg', 'status'])
     args = ['-d', '-c', apt_conf, '-o', 'Dir::state::status='+dpkg_status] + cmd
-    pid = start('apt-get', args)
+    pid = start('apt-get', args, downloader_dir)
     return pid
 
 def bootstrap_address(num_boot):
@@ -558,7 +713,7 @@ def boot_dir(num_boot):
     return os.path.join(CWD,'bootstrap' + str(num_boot))
 
 def start_downloader(bootstrap_addresses, num_down, options = {},
-                     mirror = 'ftp.us.debian.org/debian', 
+                     types = ['deb'], mirror = 'ftp.us.debian.org/debian', 
                      suites = 'main contrib non-free', clean = True):
     """Initialize a new downloader process.
 
@@ -571,8 +726,11 @@ def start_downloader(bootstrap_addresses, num_down, options = {},
     @param num_down: the number of the downloader to use
     @type options: C{dictionary}
     @param options: the dictionary of string formatting values for creating
-        the apt-dht configuration file (see L{apt_dht_conf_template} above).
+        the apt-p2p configuration file (see L{apt_p2p_conf_template} above).
         (optional, defaults to only using the default arguments)
+    @type types: C{list} of C{string}
+    @param types: the type of sources.list line to add
+        (optional, defaults to only 'deb')
     @type mirror: C{string}
     @param mirror: the Debian mirror to use
         (optional, defaults to 'ftp.us.debian.org/debian')
@@ -599,21 +757,25 @@ def start_downloader(bootstrap_addresses, num_down, options = {},
         except:
             pass
     
-        # Create the directory structure needed by apt
-        makedirs([downloader_dir, 'etc', 'apt', 'apt.conf.d'])
-        makedirs([downloader_dir, 'var', 'lib', 'apt', 'lists', 'partial'])
-        makedirs([downloader_dir, 'var', 'lib', 'dpkg'])
-        makedirs([downloader_dir, 'var', 'cache', 'apt', 'archives', 'partial'])
-        touch([downloader_dir, 'var', 'lib', 'apt', 'lists', 'lock'])
-        touch([downloader_dir, 'var', 'lib', 'dpkg', 'lock'])
-        touch([downloader_dir, 'var', 'lib', 'dpkg', 'status'])
-        touch([downloader_dir, 'var', 'cache', 'apt', 'archives', 'lock'])
-
+    # Create the directory structure needed by apt
+    makedirs([downloader_dir, 'etc', 'apt', 'apt.conf.d'])
+    makedirs([downloader_dir, 'var', 'lib', 'apt', 'lists', 'partial'])
+    makedirs([downloader_dir, 'var', 'lib', 'dpkg'])
+    rmrf(join([downloader_dir, 'var', 'cache', 'apt', 'archives']))
+    makedirs([downloader_dir, 'var', 'cache', 'apt', 'archives', 'partial'])
+    touch([downloader_dir, 'var', 'lib', 'apt', 'lists', 'lock'])
+    touch([downloader_dir, 'var', 'lib', 'dpkg', 'lock'])
+    touch([downloader_dir, 'var', 'lib', 'dpkg', 'status'])
+    touch([downloader_dir, 'var', 'cache', 'apt', 'archives', 'lock'])
+
+    if not exists(join([downloader_dir, 'etc', 'apt', 'sources.list'])):
         # Create apt's config files
         f = open(join([downloader_dir, 'etc', 'apt', 'sources.list']), 'w')
-        f.write('deb http://localhost:1%02d77/%s/ stable %s\n' % (num_down, mirror, suites))
+        for type in types:
+            f.write('%s http://localhost:1%02d77/%s/ unstable %s\n' % (type, num_down, mirror, suites))
         f.close()
 
+    if not exists(join([downloader_dir, 'etc', 'apt', 'apt.conf'])):
         f = open(join([downloader_dir, 'etc', 'apt', 'apt.conf']), 'w')
         f.write('Dir "' + downloader_dir + '"')
         f.write(apt_conf_template)
@@ -627,20 +789,20 @@ def start_downloader(bootstrap_addresses, num_down, options = {},
 
     for k in options:
         defaults[k] = options[k]
-    f = open(join([downloader_dir, 'apt-dht.conf']), 'w')
-    f.write(apt_dht_conf_template % defaults)
+    f = open(join([downloader_dir, 'apt-p2p.conf']), 'w')
+    f.write(apt_p2p_conf_template % defaults)
     f.close()
     
-    pid = start('python', [join([sys.path[0], 'apt-dht.py']),
-                           '--config-file=' + join([downloader_dir, 'apt-dht.conf']),
-                           '--log-file=' + join([downloader_dir, 'apt-dht.log']),],
+    pid = start('python', [join([sys.path[0], 'apt-p2p.py']),
+                           '--config-file=' + join([downloader_dir, 'apt-p2p.conf']),
+                           '--log-file=' + join([downloader_dir, 'apt-p2p.log']),],
                 downloader_dir)
     return pid
 
 def start_bootstrap(bootstrap_addresses, num_boot, options = [], clean = True):
     """Initialize a new bootstrap node process.
 
-    The default arguments specified to the apt-dht invocation are
+    The default arguments specified to the apt-p2p invocation are
     the state file and port to use. Any additional arguments needed 
     should be specified by L{options}.
     
@@ -679,13 +841,13 @@ def start_bootstrap(bootstrap_addresses, num_boot, options = [], clean = True):
 
     for k in options:
         defaults[k] = options[k]
-    f = open(join([bootstrap_dir, 'apt-dht.conf']), 'w')
-    f.write(apt_dht_conf_template % defaults)
+    f = open(join([bootstrap_dir, 'apt-p2p.conf']), 'w')
+    f.write(apt_p2p_conf_template % defaults)
     f.close()
     
-    pid = start('python', [join([sys.path[0], 'apt-dht.py']),
-                           '--config-file=' + join([bootstrap_dir, 'apt-dht.conf']),
-                           '--log-file=' + join([bootstrap_dir, 'apt-dht.log']),],
+    pid = start('python', [join([sys.path[0], 'apt-p2p.py']),
+                           '--config-file=' + join([bootstrap_dir, 'apt-p2p.conf']),
+                           '--log-file=' + join([bootstrap_dir, 'apt-p2p.log']),],
                 bootstrap_dir)
 
     return pid
@@ -719,12 +881,12 @@ def run_test(bootstraps, downloaders, apt_get_queue):
             bootstrap_addresses += '\n      ' + bootstrap_address(boot_keys[i])
             
         for k, v in bootstraps.items():
-            running_bootstraps[k] = start_bootstrap(bootstrap_addresses, k, v)
+            running_bootstraps[k] = start_bootstrap(bootstrap_addresses, k, **v)
         
         sleep(5)
         
         for k, v in downloaders.items():
-            running_downloaders[k] = start_downloader(bootstrap_addresses, k, v)
+            running_downloaders[k] = start_downloader(bootstrap_addresses, k, **v)
     
         sleep(5)