def test_remove_udf(udf_name, sd1, sd2, sd3, prefix):
    """Test 8: Remove an UDF, assert correct deletion on both clients."""
    yield create_udf(udf_name, sd1, prefix)
    yield sd2.sdt.wait_for_nirvana(.5)

    assert os.path.exists(os.path.join(sd2.homedir, udf_name))
    actual1 = walk_and_list_dir(os.path.join(sd1.homedir, udf_name))
    actual2 = walk_and_list_dir(os.path.join(sd2.homedir, udf_name))
    debug(prefix, "contents for SD1", actual1)
    assert actual1 == actual2

    debug(prefix, "Removing the UDF:", udf_name)
    shutil.rmtree(os.path.join(sd1.homedir, udf_name))

    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)

    events = [event['event_name'] for event in sd2.events]
    assert 'VM_VOLUME_DELETED' in events, 'VM_UDF_DELETED in sd2.events'
    debug(prefix, "VM_VOLUME_DELETED found on SD2")

    msg = 'UDF\'s contents must be deleted from file system on SD2.'
    udf_content = os.listdir(os.path.join(sd2.homedir, udf_name))
    debug(prefix, 'contents for SD2', udf_content)
    assert udf_content == [], msg
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_unsuscribe_delete_subscribe(udf_name, sd1, sd2, sd3, prefix):
    """Test 14: unsubscribe and subsc., removing everything in the middle."""
    # create udf
    folder = yield create_udf(udf_name, sd1, prefix)
    folder_id = folder["volume_id"]
    udf_path = folder["path"]
    debug(prefix, 'create_folder completed!', folder)
    assert folder['subscribed'], 'sd1 must be subscribed'
    yield sd1.sdt.wait_for_nirvana(.5)

    # un-subscribe and check
    yield sd1.sdt.unsubscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1, "SD1 has udfs != 1 (%d)" % len(folders)
    assert not folders[0]['subscribed'], 'sd1 must NOT be subscribed'
    debug(prefix, 'unsubscribed!')

    # remove everything
    shutil.rmtree(udf_path)
    debug(prefix, 'everything removed from disk')
    yield sd1.sdt.wait_for_nirvana(.5)

    # subscribe and wait
    yield sd1.sdt.subscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1, "SD1 has udfs != 1 (%d)" % len(folders)
    assert folders[0]['subscribed'], 'sd1 must be subscribed'
    yield sd1.sdt.wait_for_nirvana(.5)
    debug(prefix, 'subscribed!')

    # check stuff in disk for sd1
    in_disk = walk_and_list_dir(udf_path)
    expected = ['a_dir', os.path.join('a_dir', 'a_file.txt')]
    assert in_disk == expected, \
        "Wrong stuff in disk: %s (expected: %s)" % (in_disk, expected)
def test_merge_directories_no_overlap(udf_name, sd1, sd2, sd3, prefix):
    """Test 4: Assert directories are correctly merged if no overlapping."""
    folderdir1 = os.path.join(sd1.homedir, udf_name)
    folderdir2 = os.path.join(sd2.homedir, udf_name)
    expected = []

    os.mkdir(folderdir1)
    # add folders and files to folderdir1
    on_sd1 = []
    for d in ('a', 'b', 'c'):
        dirpath = os.path.join(folderdir1, d)
        os.makedirs(dirpath)
        expected.append(d)
        for f in ('foo1.txt', 'bar1.txt', 'syncdaemon1.log'):
            # flip a coin
            if random.random() < 0.5:
                filepath = os.path.join(dirpath, f)
                open(filepath, 'w').close()
                on_sd1.append(os.path.join(d, f))
    debug(prefix, "created in sd1", on_sd1)
    expected.extend(on_sd1)

    os.mkdir(folderdir2)
    on_sd2 = []
    # add folders and files to folderdir2
    for d in ('z', 'y', 'x'):
        dirpath = os.path.join(folderdir2, d)
        os.makedirs(dirpath)
        expected.append(d)
        for f in ('foo2.txt', 'bar2.txt', 'syncdaemon2.log'):
            # flip a coin
            if random.random() < 0.5:
                filepath = os.path.join(dirpath, f)
                open(filepath, 'w').close()
                on_sd2.append(os.path.join(d, f))
    debug(prefix, "created in sd2", on_sd2)
    expected.extend(on_sd2)

    expected.sort()
    debug(prefix, "Expected", expected)

    # create the folder on sd1 and wait sd2 to finish working
    yield sd1.sdt.create_folder(path=folderdir1)
    yield sd1.sdt.wait_for_nirvana(.5)

    folders = yield sd1.sdt.get_folders()
    debug(prefix, 'get_folders completed!', folders)
    assert len(folders) == 1  # UDF was reported as expected

    yield sd2.sdt.wait_for_nirvana(.5)

    actual = walk_and_list_dir(folderdir2)
    debug(prefix, 'Found in SD2', actual)

    assert expected == actual, 'directory merge successful'
def test_create_folder(udf_name, sd1, sd2, sd3, prefix):
    """Test 1: Assert correct folder creation."""
    wait_for_udf_created = sd2.wait_for_event('VM_UDF_CREATED')

    yield create_udf(udf_name, sd1, prefix)
    yield wait_for_udf_created
    yield sd2.sdt.wait_for_nirvana(.5)

    folderdir1 = os.path.join(sd1.homedir, udf_name)
    folderdir2 = os.path.join(sd2.homedir, udf_name)
    expected = walk_and_list_dir(folderdir1)
    actual = walk_and_list_dir(folderdir2)
    debug(prefix, 'expected', expected)
    debug(prefix, 'actual', actual)
    assert expected == actual, 'UDF must be replicated correctly'

    with open(os.path.join(folderdir1, expected[-1])) as fd:
        content1 = fd.read()
    with open(os.path.join(folderdir1, actual[-1])) as fd:
        content2 = fd.read()
    assert content1 == content2, 'file content macth'
def test_unsusc_lotofchanges_subsc(udf_name, sd1, sd2, sd3, prefix):
    """Test 19: Merge should be done correctly."""
    # some dirs and files
    udf_dir = os.path.join(sd1.homedir, udf_name)
    dir_a = os.path.join(udf_dir, "a")
    file_1 = os.path.join(dir_a, "file1")
    file_2 = os.path.join(dir_a, "file2")
    file_3 = os.path.join(dir_a, "file3")
    dir_b = os.path.join(udf_dir, "b")
    dir_c = os.path.join(udf_dir, "c")
    dir_d = os.path.join(udf_dir, "d")

    # we create an UDF and put:
    #  - dir_a, with:
    #  -     file_1
    #  -     file_2
    #  - dir_b
    #  - dir_c
    folder, = yield sd1.sdt.create_folder(path=udf_dir)
    folder_id = folder["volume_id"]
    for d in (dir_a, dir_b, dir_c):
        os.mkdir(d)
    for f in (file_1, file_2):
        open(f, "w").close()
    debug(prefix, 'initial UDF completed!')
    yield sd1.sdt.wait_for_nirvana(.5)

    # unsubscribe
    yield sd1.sdt.unsubscribe_folder(folder_id)
    debug(prefix, 'unsubscribed!')

    # some changes:
    os.rmdir(dir_c)
    os.mkdir(dir_d)
    os.remove(file_2)
    open(file_3, "w").close()
    debug(prefix, 'changes made!')
    yield sd1.sdt.wait_for_nirvana(1)

    # subscribe again
    yield sd1.sdt.subscribe_folder(folder_id)
    debug(prefix, 'subscribed!')

    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, 'changes propagated')

    # what the merge should do:
    #  - dir_c is back from the server
    #  - dir_d uploaded
    #  - file_2 is back from the server
    #  - file_3 uploaded to the server
    #  - the rest should remain unchanged

    # to check, we verify everything in both clients
    expected = ['a', 'a/file1', 'a/file2', 'a/file3', 'b', 'c', 'd']
    for which, sd in enumerate((sd1, sd2)):
        debug(prefix, 'check SD', sd)
        udf_dir = os.path.join(sd.homedir, udf_name)
        in_disk = walk_and_list_dir(udf_dir)
        assert in_disk == expected, "sd %s has bad stuff in "\
                                    "disk: %s" % (which, in_disk)
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'