def __init__(self, config_dir, output_dir, output_path, volume_name, **kw ):
     threading.Thread.__init__(self)
     self.read_gateway_name = testlib.add_test_gateway( config_dir, volume_name, "UG", **kw )
     read_gateway_info = testlib.read_gateway( config_dir, self.read_gateway_name )
     self.read_gateway_id = read_gateway_info['g_id']
     
     volume_info = testlib.read_volume( config_dir, volume_name )
     self.volume_id = volume_info['volume_id']
     self.config_dir = config_dir
     self.volume_name = volume_name
     self.output_path = output_path
     self.output_dir = output_dir
     self.exitcode = 0
     self.errormsg = ""
     self.errors = False
    def __init__(self, config_dir, output_dir, output_path, volume_name, **kw):
        threading.Thread.__init__(self)
        self.read_gateway_name = testlib.add_test_gateway(
            config_dir, volume_name, "UG", **kw)
        read_gateway_info = testlib.read_gateway(config_dir,
                                                 self.read_gateway_name)
        self.read_gateway_id = read_gateway_info['g_id']

        volume_info = testlib.read_volume(config_dir, volume_name)
        self.volume_id = volume_info['volume_id']
        self.config_dir = config_dir
        self.volume_name = volume_name
        self.output_path = output_path
        self.output_dir = output_dir
        self.exitcode = 0
        self.errormsg = ""
        self.errors = False
    file_id_line = filter( lambda l: l.startswith("file_id: "), out_lines)

    assert len(file_id_line) == 1, "Missing 'file_id:' in output"
    assert len(file_version_line) == 1, "Missing 'version': in output"

    file_version = int(file_version_line[0].split(" ")[-1])
    file_id_hex = file_id_line[0].split(" ")[-1]
    if len(file_id_hex) != 16:
        file_id_hex = ("0" * (16 - len(file_id_hex))) + file_id_hex

    file_id_hex_parts = []
    for i in xrange(0, 4):
        file_id_hex_parts.append( file_id_hex[4*i] + file_id_hex[4*i+1] + file_id_hex[4*i+2] + file_id_hex[4*i+3] )

    # expected built-in attr for cached file data
    gateway_info = testlib.read_gateway( config_dir, gateway_name )
    getxattr_gateway_info = testlib.read_gateway( config_dir, getxattr_gateway_name )
    gateway_coord_id = gateway_info['g_id']
    getxattr_gateway_id = getxattr_gateway_info['g_id']
    volume_info = testlib.read_volume( config_dir, volume_name )
    file_cache_path = os.path.join( testlib.cache_dir( config_dir, volume_info['volume_id'], getxattr_gateway_id ), "/".join(file_id_hex_parts)) + "." + file_id_hex + "." + str(file_version)
    builtin_xattr_expected_values["user.syndicate_coordinator"] = gateway_name
    builtin_xattr_expected_values["user.syndicate_cached_file_path"] = file_cache_path

    # leave this gateway running, so it can answer xattr queries 
    ug_proc, ug_out_path = testlib.start_gateway( config_dir, COORD_PATH, testconf.SYNDICATE_ADMIN, volume_name, gateway_name, path, valgrind=True ) 
    time.sleep(5)

    # get built-in xattrs, individually, with the getxattr gateway
    for builtin_xattr in builtin_xattrs:
        exitcode, out = testlib.run( GETXATTR_PATH, '-d2', '-f', '-c', os.path.join(config_dir, 'syndicate.conf'),
    expected_data = local_fd.read()
    local_fd.close()

    # start up AG
    AG_gateway_name = testlib.add_test_gateway( config_dir, volume_name, "AG", caps="ALL", email=testconf.SYNDICATE_ADMIN )
    testlib.update_gateway( config_dir, AG_gateway_name, "port=31112", "driver=%s" % AG_DRIVER )

    ag_proc, ag_out_path = testlib.start_gateway( config_dir, AG_PATH, testconf.SYNDICATE_ADMIN, volume_name, AG_gateway_name, valgrind=True )
    time.sleep(30)
    if not testlib.gateway_ping( 31112, 15 ):
        raise Exception("%s exited %s" % (AG_PATH, ag_proc.poll()))

    # should cause the AG to get updated that there's a new gateway 
    read_gateway_name = testlib.add_test_gateway( config_dir, volume_name, "UG", caps="ALL", email=testconf.SYNDICATE_ADMIN )

    read_gateway_info = testlib.read_gateway( config_dir, read_gateway_name )
    read_gateway_id = read_gateway_info['g_id']

    volume_info = testlib.read_volume( config_dir, volume_name )
    volume_id = volume_info['volume_id']

    # try reading various ranges (these are (start, end) absolute ranges, not offset/length)
    ranges = [
        (1, 200),
        (0, 4096),  # 1 block, aligned
        (0, 8192),  # 2 blocks, aligned
        (0, 1000),  # 1 block, tail unaligned
        (0, 6000),  # 2 blocks, tail unaligned
        (100, 4000), # 1 block, head unaligned
        (5000, 10000), # 2 blocks, head and tail unaligned
        (4096, 10000), # 2 blocks, tail unaligned
        raise Exception("%s exited %s" % (RG_PATH, rg_proc.poll()))

    # should cause the RG to get updated that there's a new gateway
    gateway_name = testlib.add_test_gateway(config_dir,
                                            volume_name,
                                            "UG",
                                            caps="ALL",
                                            email=testconf.SYNDICATE_ADMIN)
    cat_gateway_name = testlib.add_test_gateway(config_dir,
                                                volume_name,
                                                "UG",
                                                caps="ALL",
                                                email=testconf.SYNDICATE_ADMIN)

    # look up reader gateway
    cat_gateway_info = testlib.read_gateway(config_dir, cat_gateway_name)
    cat_gateway_id = cat_gateway_info['g_id']

    # look up RG
    rg_gateway_info = testlib.read_gateway(config_dir, RG_gateway_name)
    rg_gateway_id = rg_gateway_info['g_id']

    volume_info = testlib.read_volume(config_dir, volume_name)
    volume_id = volume_info['volume_id']

    random_part = hex(random.randint(0, 2**32 - 1))[2:]
    output_paths = []

    # make target directory
    exitcode, out = testlib.run(MKDIR_PATH,
                                '-d2',
    config_dir, output_dir = testlib.test_setup()
    volume_name = testlib.add_test_volume( config_dir, blocksize=1024 )

    RG_gateway_name = testlib.add_test_gateway( config_dir, volume_name, "RG", caps="NONE", email=testconf.SYNDICATE_ADMIN )
    testlib.update_gateway( config_dir, RG_gateway_name, "port=31112", "driver=%s" % RG_DRIVER )

    rg_proc, rg_out_path = testlib.start_gateway( config_dir, RG_PATH, testconf.SYNDICATE_ADMIN, volume_name, RG_gateway_name, valgrind=True )
    if not testlib.gateway_ping( 31112, 15 ):
        raise Exception("%s exited %s" % (RG_PATH, rg_proc.poll()))

    # should cause the RG to get updated that there's a new gateway 
    gateway_name = testlib.add_test_gateway( config_dir, volume_name, "UG", caps="ALL", email=testconf.SYNDICATE_ADMIN )
    cat_gateway_name = testlib.add_test_gateway( config_dir, volume_name, "UG", caps="ALL", email=testconf.SYNDICATE_ADMIN )

    # look up reader gateway
    cat_gateway_info = testlib.read_gateway( config_dir, cat_gateway_name )
    cat_gateway_id = cat_gateway_info['g_id']

    # look up RG 
    rg_gateway_info = testlib.read_gateway( config_dir, RG_gateway_name )
    rg_gateway_id = rg_gateway_info['g_id']

    volume_info = testlib.read_volume( config_dir, volume_name )
    volume_id = volume_info['volume_id']

    random_part = hex(random.randint(0, 2**32-1))[2:]
    output_paths = []

    for i in xrange(0, NUM_FILES):
        output_path = "/put-%s-%s" % (random_part, i)
        output_paths.append(output_path)
    assert len(file_id_line) == 1, "Missing 'file_id:' in output"
    assert len(file_version_line) == 1, "Missing 'version': in output"

    file_version = int(file_version_line[0].split(" ")[-1])
    file_id_hex = file_id_line[0].split(" ")[-1]
    if len(file_id_hex) != 16:
        file_id_hex = ("0" * (16 - len(file_id_hex))) + file_id_hex

    file_id_hex_parts = []
    for i in xrange(0, 4):
        file_id_hex_parts.append(file_id_hex[4 * i] + file_id_hex[4 * i + 1] +
                                 file_id_hex[4 * i + 2] +
                                 file_id_hex[4 * i + 3])

    # expected built-in attr for cached file data
    gateway_info = testlib.read_gateway(config_dir, gateway_name)
    getxattr_gateway_info = testlib.read_gateway(config_dir,
                                                 getxattr_gateway_name)
    gateway_coord_id = gateway_info['g_id']
    getxattr_gateway_id = getxattr_gateway_info['g_id']
    volume_info = testlib.read_volume(config_dir, volume_name)
    file_cache_path = os.path.join(
        testlib.cache_dir(config_dir, volume_info['volume_id'],
                          getxattr_gateway_id), "/".join(file_id_hex_parts)
    ) + "." + file_id_hex + "." + str(file_version)
    builtin_xattr_expected_values["user.syndicate_coordinator"] = gateway_name
    builtin_xattr_expected_values[
        "user.syndicate_cached_file_path"] = file_cache_path

    # leave this gateway running, so it can answer xattr queries
    ug_proc, ug_out_path = testlib.start_gateway(config_dir,