def test_create_both_sd_same_content(test_name, sd1, sd2, sd3, prefix):
    """13. Create files with same content in both SDs.

    Create at the same time on each client two files with same name and
    same content. Check.
    """
    # create both files with same content
    data = os.urandom(1000)
    create_file_and_add_content(
        os.path.join(sd1.rootdir, 'file.txt'), content=data)
    create_file_and_add_content(
        os.path.join(sd2.rootdir, 'file.txt'), content=data)
    debug(prefix, "Files with same content created in both SDs")

    # wait for both to settle, and get the files in both
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    files1 = walk_and_list_dir(sd1.rootdir)
    files2 = walk_and_list_dir(sd2.rootdir)

    # file.txt should be on both, and no conflict at all
    assert "file.txt" in files1, "the file should be in SD1: %s" % (files1,)
    assert "file.txt.u1conflict" not in files1, "conflict SD1: %s" % (files1,)
    assert "file.txt" in files2, "the file should be in SD2: %s" % (files2,)
    assert "file.txt.u1conflict" not in files2, "conflict SD2: %s" % (files2,)
def test_delete_tree_touched_ok(test_name, sd1, sd2, sd3, prefix):
    """19. Delete a tree on one side that has a deleted file in the other.

    Create a directory, with a subdir and a file in the later. Wait for
    nirvana. At the same time on one client unlink the file, and on the
    other client remove everything. Check that all is deleted ok.
    """
    # create the tree and wait
    os.makedirs(os.path.join(sd1.rootdir, 'dir1', 'dir2'))
    create_file_and_add_content(
        os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt'))
    yield sd1.sdt.wait_for_nirvana(.5)
    debug(prefix, "Tree created and propagated")

    # remove everything on one side, and unlink on the other
    shutil.rmtree(os.path.join(sd2.rootdir, 'dir1'))
    os.remove(os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt'))
    debug(prefix, "Deletes executed")

    # wait
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, "Nirvana reached on both")

    # check files
    files1 = walk_and_list_dir(sd1.rootdir)
    files2 = walk_and_list_dir(sd2.rootdir)
    assert files1 == [], "Bad files in SD1: %s" % (files1,)
    assert files2 == [], "Bad files in SD2: %s" % (files2,)
def test_create_tree_and_rename_parent_fast(test_name, sd1, sd2, sd3, prefix):
    """10. Create tree and rename the parent while uploading.

    Create a directory, put three files inside with data, and immediately
    after rename the directory. Check.
    """
    # create the root/a/b/c/d tree in sd1, put some files in it, rename the dir
    deepdir = os.path.join(sd1.rootdir, *'abcd')
    os.makedirs(deepdir)
    c1 = create_file_and_add_content(os.path.join(deepdir, 'file1.txt'))
    c2 = create_file_and_add_content(os.path.join(deepdir, 'file2.txt'))
    c3 = create_file_and_add_content(os.path.join(deepdir, 'file3.txt'))
    nuevo = os.path.join(sd1.rootdir, 'nuevo')
    os.rename(os.path.join(sd1.rootdir, 'a'), nuevo)
    debug(prefix, "Tree structure created and dir removed")

    # wait for both to settle, and check
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)

    with open(os.path.join(nuevo, 'b', 'c', 'd', 'file1.txt')) as f:
        assert f.read() == c1
    with open(os.path.join(nuevo, 'b', 'c', 'd', 'file2.txt')) as f:
        assert f.read() == c2
    with open(os.path.join(nuevo, 'b', 'c', 'd', 'file3.txt')) as f:
        assert f.read() == c3
def test_overwrite_file_with_content(test_name, sd1, sd2, sd3, prefix):
    """21. Create a file with data in it and overwrite it.

    Create a file 1 with content, and a file 2 with other content. Wait
    for nirvana. Move 2 into 1 (overwriting it). Check.
    """
    # create the file in sd1 and wait
    file1 = os.path.join(sd1.rootdir, 'file1.txt')
    create_file_and_add_content(file1)
    file2 = os.path.join(sd1.rootdir, 'file2.txt')
    content2 = create_file_and_add_content(file2)
    yield sd1.sdt.wait_for_nirvana(.5)
    debug(prefix, "Files created")

    # overwrite it
    os.rename(file2, file1)
    debug(prefix, "Overwritten")

    # wait propagation
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, "All changes propagated")

    # check that the file is in sd2 with correct content
    assert not os.path.exists(os.path.join(sd1.rootdir, 'file2.txt'))
    data = open(os.path.join(sd2.rootdir, 'file1.txt')).read()
    assert data == content2
def test_create_both_sd_different_content(test_name, sd1, sd2, sd3, prefix):
    """11. Create files with different content in both SDs.

    Create at the same time on each client two files with same name and
    different content. Check that one of both gets conflicted.
    """
    # create both files with content
    c1 = os.urandom(1000)
    c2 = c1[::-1]
    create_file_and_add_content(
        os.path.join(sd1.rootdir, 'file.txt'), content=c1)
    create_file_and_add_content(
        os.path.join(sd2.rootdir, 'file.txt'), content=c2)
    debug(prefix, "Files with different content created in both SDs")

    # wait for both to settle, and get the files in both
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    files1 = walk_and_list_dir(sd1.rootdir)
    debug(prefix, "Files in SD1", files1)
    files2 = walk_and_list_dir(sd2.rootdir)
    debug(prefix, "Files in SD2", files2)

    # file.txt should be on both
    assert "file.txt" in files1, "the file.txt should be in SD1"
    assert "file.txt" in files2, "the file.txt should be in SD2"

    # one of them should have a conflict, and the other should not
    conflict1 = "file.txt.u1conflict" in files1
    conflict2 = "file.txt.u1conflict" in files2
    assert conflict1 and not conflict2 or conflict2 and not conflict1, \
        "Only one of both should have conflict!"
def test_disconnect_modify_connect(udf_name, sd1, sd2, sd3, prefix):
    """Test 13: Create UDF, disconnect SD, do stuff, and then reconnect."""
    folder = yield create_udf(udf_name, sd1, prefix)
    folder_path = folder['path']
    other_dir = os.path.join(folder_path, 'other_dir')
    os.mkdir(other_dir)
    third_dir = os.path.join(folder_path, 'third_dir')
    os.mkdir(third_dir)

    yield sd1.sdt.wait_for_nirvana(.5)

    debug(prefix, 'Disconnecting SD1.')
    yield sd1.sdt.disconnect()  # disconnect SD1

    debug(prefix, 'Doing stuff in the file system of SD1.')
    # do stuff in the file system
    xyz_dir = os.path.join(folder_path, 'x', 'y', 'z')
    os.makedirs(xyz_dir)
    create_file_and_add_content(os.path.join(xyz_dir, 'new.txt'))

    # move a file within the UDF
    os.rename(os.path.join(folder_path, 'a_dir', 'a_file.txt'),
              os.path.join(xyz_dir, 'renamed_file.txt'))

    # move a folder outside the UDF to the root dir
    os.rename(os.path.join(folder_path, 'other_dir'),
              os.path.join(sd1.rootdir, udf_name + 'renamed_other_dir'))

    # move a folder outside the UDF to the home dir
    renamed_third_dir = os.path.join(sd1.homedir, 'renamed_third_dir')
    os.rename(os.path.join(folder_path, 'third_dir'),
              renamed_third_dir)

    expected = set(walk_and_list_dir(sd1.homedir))
    debug(prefix, "Expected to have", expected)

    debug(prefix, 'Re connecting SD1.')
    yield sd1.sdt.connect()  # re-connect SD1
    yield sd1.sdt.wait_for_nirvana(.5)

    debug(prefix, 'Waiting for nirvana for SD2.')
    yield sd2.sdt.wait_for_nirvana(.5)  # wait for SD2 to get all the changes

    actual = set(walk_and_list_dir(sd2.homedir))
    debug(prefix, "Currently found", actual)

    debug(prefix, 'expected sym diff actual',
          expected.symmetric_difference(actual))
    assert expected.difference(actual) == set(['renamed_third_dir']), \
        'SD1 home must have the same as SD2 except for renamed_third_dir.'
    assert actual.difference(expected) == set([]), \
        'SD2 home must have nothing extra than the SD1\'s.'
def test_disconnect_modify_connect(udf_name, sd1, sd2, sd3, prefix):
    """Test 13: Create UDF, disconnect SD, do stuff, and then reconnect."""
    folder = yield create_udf(udf_name, sd1, prefix)
    folder_path = folder['path']
    other_dir = os.path.join(folder_path, 'other_dir')
    os.mkdir(other_dir)
    third_dir = os.path.join(folder_path, 'third_dir')
    os.mkdir(third_dir)

    yield sd1.sdt.wait_for_nirvana(.5)

    debug(prefix, 'Disconnecting SD1.')
    yield sd1.sdt.disconnect()  # disconnect SD1

    debug(prefix, 'Doing stuff in the file system of SD1.')
    # do stuff in the file system
    xyz_dir = os.path.join(folder_path, 'x', 'y', 'z')
    os.makedirs(xyz_dir)
    create_file_and_add_content(os.path.join(xyz_dir, 'new.txt'))

    # move a file within the UDF
    os.rename(os.path.join(folder_path, 'a_dir', 'a_file.txt'),
              os.path.join(xyz_dir, 'renamed_file.txt'))

    # move a folder outside the UDF to the root dir
    os.rename(os.path.join(folder_path, 'other_dir'),
              os.path.join(sd1.rootdir, udf_name + 'renamed_other_dir'))

    # move a folder outside the UDF to the home dir
    renamed_third_dir = os.path.join(sd1.homedir, 'renamed_third_dir')
    os.rename(os.path.join(folder_path, 'third_dir'), renamed_third_dir)

    expected = set(walk_and_list_dir(sd1.homedir))
    debug(prefix, "Expected to have", expected)

    debug(prefix, 'Re connecting SD1.')
    yield sd1.sdt.connect()  # re-connect SD1
    yield sd1.sdt.wait_for_nirvana(.5)

    debug(prefix, 'Waiting for nirvana for SD2.')
    yield sd2.sdt.wait_for_nirvana(.5)  # wait for SD2 to get all the changes

    actual = set(walk_and_list_dir(sd2.homedir))
    debug(prefix, "Currently found", actual)

    debug(prefix, 'expected sym diff actual',
          expected.symmetric_difference(actual))
    assert expected.difference(actual) == set(['renamed_third_dir']), \
        'SD1 home must have the same as SD2 except for renamed_third_dir.'
    assert actual.difference(expected) == set([]), \
        'SD2 home must have nothing extra than the SD1\'s.'
def test_create_tree_internal_move(test_name, sd1, sd2, sd3, prefix):
    """18. Create tree and do internal move.

    Create a directory, with a subdir and a file in the later; immediately
    after move the file one dir up. Check.
    """
    # create the tree and do the move
    os.makedirs(os.path.join(sd1.rootdir, 'dir1', 'dir2'))
    content = create_file_and_add_content(
        os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt'))
    os.rename(os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt'),
              os.path.join(sd1.rootdir, 'dir1', 'file.txt'))
    debug(prefix, "Tree created and file moved")

    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, "Nirvana reached on both")

    # check files in sd2
    files = walk_and_list_dir(sd2.rootdir)
    shouldbe = ['dir1', 'dir1/dir2', 'dir1/file.txt']
    assert files == shouldbe, "Bad files in SD2: %s" % (files,)

    # check content is ok
    fname = os.path.join(sd2.rootdir, 'dir1', 'file.txt')
    with open(fname) as f:
        assert content == f.read()
def create_udf(udf_name, sd, prefix, basedir=None):
    """Create an UDF on SD's home."""
    if basedir is None:
        basedir = sd.homedir

    folderdir = os.path.join(basedir, udf_name)
    os.mkdir(folderdir)

    dirpath = os.path.join(folderdir, 'a_dir')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'a_file.txt')
    create_file_and_add_content(filepath)

    debug(prefix, 'Attempting to create folder for path %r' % folderdir)
    folder = yield sd.sdt.create_folder(path=folderdir)
    folder, = folder
    debug(prefix, 'folder created with id %s' % (folder['volume_id'],))

    yield sd.sdt.wait_for_nirvana(.5)
    defer.returnValue(folder)
def create_udf(udf_name, sd, prefix, basedir=None):
    """Create an UDF on SD's home."""
    if basedir is None:
        basedir = sd.homedir

    folderdir = os.path.join(basedir, udf_name)
    os.mkdir(folderdir)

    dirpath = os.path.join(folderdir, 'a_dir')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'a_file.txt')
    create_file_and_add_content(filepath)

    debug(prefix, 'Attempting to create folder for path %r' % folderdir)
    folder = yield sd.sdt.create_folder(path=folderdir)
    folder, = folder
    debug(prefix, 'folder created with id %s' % (folder['volume_id'], ))

    yield sd.sdt.wait_for_nirvana(.5)
    defer.returnValue(folder)
def test_file_with_content(test_name, sd1, sd2, sd3, prefix):
    """02. Create a file with data in it. Check."""
    # create the file in sd1 and wait
    filepath = os.path.join(sd1.rootdir, 'file.txt')
    content = create_file_and_add_content(filepath)
    debug(prefix, "File created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2 with correct content
    with open(os.path.join(sd2.rootdir, 'file.txt')) as f:
        data = f.read()
    assert data == content
def test_delete_tree_touched_conflict(test_name, sd1, sd2, sd3, prefix):
    """20. Delete a tree on one side that has a renamed file in the other.

    Create a directory, with a subdir and a file in the later. Wait for
    nirvana. Disconnect SD1 and remove everything in SD2. Write something
    to the file in SD1 and connect again.  Check that in SD2 all is gone,
    but in SD1 the directory is not deleted but conflicted.
    """
    # create the tree and wait
    os.makedirs(os.path.join(sd1.rootdir, 'dir1', 'dir2'))
    create_file_and_add_content(
        os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt'))
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.disconnect()
    debug(prefix, "Tree created and propagated; sd1 disconnected")

    # remove everything on one side
    shutil.rmtree(os.path.join(sd2.rootdir, 'dir1'))
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, "Delete executed")

    # change sd1 and reconnect
    fname = os.path.join(sd1.rootdir, 'dir1', 'dir2', 'file.txt')
    with open(fname, 'w') as fh:
        fh.write(os.urandom(10))
    yield sd1.sdt.connect()
    yield sd1.sdt.wait_for_nirvana(.5)
    debug(prefix, "Wrote in SD1 and reconnected")

    # check files
    files2 = walk_and_list_dir(sd2.rootdir)
    assert files2 == [], "Bad files in SD2: %s" % (files2,)

    files1 = walk_and_list_dir(sd1.rootdir)
    shouldbe = ['dir1.u1conflict', 'dir1.u1conflict/dir2.u1conflict',
                'dir1.u1conflict/dir2.u1conflict/file.txt.u1conflict']
    assert files1 == shouldbe, "Bad files in SD1: %s" % (files1,)
def test_rename_file_with_content(test_name, sd1, sd2, sd3, prefix):
    """05. Rename a file with content.

    Create a file with some data, and immediately after rename it to
    something else (it still will be in the creation/uploading process).
    Check.
    """
    # create the file in sd1 and rename
    content = create_file_and_add_content(
        os.path.join(sd1.rootdir, 'file.txt'))
    os.rename(
        os.path.join(sd1.rootdir, 'file.txt'),
        os.path.join(sd1.rootdir, 'filenew.txt'))
    debug(prefix, "File created and renamed")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2 ok (and old file is not there)
    assert not os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))
    with open(os.path.join(sd2.rootdir, 'filenew.txt')) as f:
        data = f.read()
    assert data == content
def test_create_tree_and_remove_it(test_name, sd1, sd2, sd3, prefix):
    """16. Create tree and remove it.

    Create a tree structure with some dirs and some files in some of
    them. Wait for nirvana. Remove everything as fast as possible. Check.
    """
    # create some tree structure with files
    deepdir = os.path.join(sd1.rootdir, *'abcd')
    os.makedirs(deepdir)
    create_file_and_add_content(os.path.join(deepdir, 'file1.txt'))
    create_file_and_add_content(os.path.join(deepdir, 'file2.txt'))
    open(os.path.join(deepdir, 'file2.txt'), 'w').close()

    deepdir = os.path.join(sd1.rootdir, *'abjk')
    os.makedirs(deepdir)
    create_file_and_add_content(os.path.join(deepdir, 'file3.txt'))
    open(os.path.join(deepdir, 'file4.txt'), 'w').close()

    deepdir = os.path.join(sd1.rootdir, 'a')
    create_file_and_add_content(os.path.join(deepdir, 'file5.txt'))
    open(os.path.join(deepdir, 'file6.txt'), 'w').close()
    debug(prefix, "Tree structure created with files in it")

    # wait for both to settle, and remove everything
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    shutil.rmtree(os.path.join(sd1.rootdir, 'a'))
    debug(prefix, "rmtree finished")

    # wait for everything to finish, get both files list and check
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    files1 = walk_and_list_dir(sd1.rootdir)
    files2 = walk_and_list_dir(sd2.rootdir)
    assert files1 == [], "bad info in SD1: %s" % (files1,)
    assert files2 == [], "bad info in SD1: %s" % (files2,)
def test_file_with_content_changing(test_name, sd1, sd2, sd3, prefix):
    """03. Create a file with data. Check. Modify file's content. Check."""
    # create the file in sd1 and wait
    filepath = os.path.join(sd1.rootdir, 'file.txt')
    content = create_file_and_add_content(filepath)
    debug(prefix, "File created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2 with correct content
    with open(os.path.join(sd2.rootdir, 'file.txt')) as f:
        data = f.read()
    assert data == content

    # change the content in sd2, and wait for both to settle
    newcontent = os.urandom(1000)
    with open(os.path.join(sd2.rootdir, 'file.txt'), 'w') as fh:
        fh.write(newcontent)
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.wait_for_nirvana(.5)

    # check that the file in sd1 has the correct content
    with open(os.path.join(sd1.rootdir, 'file.txt')) as f:
        data = f.read()
    assert data == newcontent
def test_merge_directories_with_overlap(udf_name, sd1, sd2, sd3, prefix):
    """Test 5: Assert directories are correctly merge with overlapping."""

    # Structure to start
    #
    #   client 1:
    #     .../a
    #     .../a/conflict.txt   (content random)
    #     .../a/noconflict.txt (same content that 2)
    #     .../a/bar.txt
    #     .../b
    #
    #   client 2:
    #     .../a
    #     .../a/conflict.txt   (content random)
    #     .../a/noconflict.txt (same content that 1)
    #     .../a/beer.txt
    #     .../c
    #
    # Result after UDF creation and merge:
    #
    #  .../a/bar.txt and .../b are synced to client 2
    #  .../a/beer.txt and .../c are synced to client 1
    #  .../a/conflict.txt stays the same in one client, and in the other it
    #      goes to conflict (depending on which got first to the server)
    #  .../a/noconflict.txt stays ok in both clients
    #
    folderdir1 = os.path.join(sd1.homedir, udf_name)
    folderdir2 = os.path.join(sd2.homedir, udf_name)

    os.mkdir(folderdir1)
    # add folders and files to folderdir1
    dirpath = os.path.join(folderdir1, 'a')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'conflict.txt')
    create_file_and_add_content(filepath, content='content from SD1')

    filepath = os.path.join(dirpath, 'noconflict.txt')
    with open(filepath, "w") as fh:
        fh.write("same content")

    filepath = os.path.join(dirpath, 'bar.txt')
    create_file_and_add_content(filepath)

    dirpath = os.path.join(folderdir1, 'b')
    os.makedirs(dirpath)

    os.mkdir(folderdir2)

    # add folders and files to folderdir2
    dirpath = os.path.join(folderdir2, 'a')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'conflict.txt')
    create_file_and_add_content(filepath, content='content from SD2')

    filepath = os.path.join(dirpath, 'noconflict.txt')
    with open(filepath, "w") as fh:
        fh.write("same content")

    filepath = os.path.join(dirpath, 'beer.txt')
    create_file_and_add_content(filepath)

    dirpath = os.path.join(folderdir1, 'c')
    os.makedirs(dirpath)

    # wait for all changes to settle down
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.wait_for_nirvana(.5)

    # prepare the info to compare
    expected_no_conflict = ['a', 'b', 'c',
                            os.path.join('a', 'bar.txt'),
                            os.path.join('a', 'beer.txt'),
                            os.path.join('a', 'noconflict.txt'),
                            os.path.join('a', 'conflict.txt')]
    expected_no_conflict.sort()
    debug(prefix, 'expected without conflict', expected_no_conflict)

    expected_with_conflict = copy(expected_no_conflict)
    expected_with_conflict.append(os.path.join('a', 'conflict.txt.u1conflict'))
    expected_with_conflict.sort()
    debug(prefix, 'expected with conflict', expected_with_conflict)

    # create the UDF and wait everything to stop
    yield sd1.sdt.create_folder(path=folderdir1)
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.wait_for_nirvana(.5)

    actual1 = walk_and_list_dir(folderdir1)
    debug(prefix, 'actual content from SD1', actual1)
    actual2 = walk_and_list_dir(folderdir2)
    debug(prefix, 'actual content from SD2', actual2)

    # we don't know which client will enter in conflict, so we
    # tested both ways.
    if actual1 != expected_no_conflict:
        assert actual1 == expected_with_conflict, \
            'directory merge must be correct for SD1'
        assert actual2 == expected_no_conflict, \
            'directory merge must be correct for SD2'
    else:
        assert actual1 == expected_no_conflict, \
            'directory merge must be correct for SD1'
        assert actual2 == expected_with_conflict, \
            'directory merge must be correct for SD2'
def test_merge_directories_with_overlap(udf_name, sd1, sd2, sd3, prefix):
    """Test 5: Assert directories are correctly merge with overlapping."""

    # Structure to start
    #
    #   client 1:
    #     .../a
    #     .../a/conflict.txt   (content random)
    #     .../a/noconflict.txt (same content that 2)
    #     .../a/bar.txt
    #     .../b
    #
    #   client 2:
    #     .../a
    #     .../a/conflict.txt   (content random)
    #     .../a/noconflict.txt (same content that 1)
    #     .../a/beer.txt
    #     .../c
    #
    # Result after UDF creation and merge:
    #
    #  .../a/bar.txt and .../b are synced to client 2
    #  .../a/beer.txt and .../c are synced to client 1
    #  .../a/conflict.txt stays the same in one client, and in the other it
    #      goes to conflict (depending on which got first to the server)
    #  .../a/noconflict.txt stays ok in both clients
    #
    folderdir1 = os.path.join(sd1.homedir, udf_name)
    folderdir2 = os.path.join(sd2.homedir, udf_name)

    os.mkdir(folderdir1)
    # add folders and files to folderdir1
    dirpath = os.path.join(folderdir1, 'a')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'conflict.txt')
    create_file_and_add_content(filepath, content='content from SD1')

    filepath = os.path.join(dirpath, 'noconflict.txt')
    with open(filepath, "w") as fh:
        fh.write("same content")

    filepath = os.path.join(dirpath, 'bar.txt')
    create_file_and_add_content(filepath)

    dirpath = os.path.join(folderdir1, 'b')
    os.makedirs(dirpath)

    os.mkdir(folderdir2)

    # add folders and files to folderdir2
    dirpath = os.path.join(folderdir2, 'a')
    os.makedirs(dirpath)

    filepath = os.path.join(dirpath, 'conflict.txt')
    create_file_and_add_content(filepath, content='content from SD2')

    filepath = os.path.join(dirpath, 'noconflict.txt')
    with open(filepath, "w") as fh:
        fh.write("same content")

    filepath = os.path.join(dirpath, 'beer.txt')
    create_file_and_add_content(filepath)

    dirpath = os.path.join(folderdir1, 'c')
    os.makedirs(dirpath)

    # wait for all changes to settle down
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.wait_for_nirvana(.5)

    # prepare the info to compare
    expected_no_conflict = [
        'a', 'b', 'c',
        os.path.join('a', 'bar.txt'),
        os.path.join('a', 'beer.txt'),
        os.path.join('a', 'noconflict.txt'),
        os.path.join('a', 'conflict.txt')
    ]
    expected_no_conflict.sort()
    debug(prefix, 'expected without conflict', expected_no_conflict)

    expected_with_conflict = copy(expected_no_conflict)
    expected_with_conflict.append(os.path.join('a', 'conflict.txt.u1conflict'))
    expected_with_conflict.sort()
    debug(prefix, 'expected with conflict', expected_with_conflict)

    # create the UDF and wait everything to stop
    yield sd1.sdt.create_folder(path=folderdir1)
    yield sd2.sdt.wait_for_nirvana(.5)
    yield sd1.sdt.wait_for_nirvana(.5)

    actual1 = walk_and_list_dir(folderdir1)
    debug(prefix, 'actual content from SD1', actual1)
    actual2 = walk_and_list_dir(folderdir2)
    debug(prefix, 'actual content from SD2', actual2)

    # we don't know which client will enter in conflict, so we
    # tested both ways.
    if actual1 != expected_no_conflict:
        assert actual1 == expected_with_conflict, \
            'directory merge must be correct for SD1'
        assert actual2 == expected_no_conflict, \
            'directory merge must be correct for SD2'
    else:
        assert actual1 == expected_no_conflict, \
            'directory merge must be correct for SD1'
        assert actual2 == expected_with_conflict, \
            'directory merge must be correct for SD2'