def test_create_tree_and_rename(test_name, sd1, sd2, sd3, prefix):
    """15. Create a tree and rename parent.

    Create a directory, with one subdir, and other subdir under the later,
    and a file as a leaf (root/a/b/c.txt). Wait for nirvana. Rename the
    first subdir (a). Check.
    """
    # create the tree and wait for it to finish
    os.makedirs(os.path.join(sd1.rootdir, 'a', 'b'))
    open(os.path.join(sd1.rootdir, 'a', 'b', 'c.txt'), 'w').close()
    debug(prefix, "Dir and files created in SD1")
    yield sd1.sdt.wait_for_nirvana(.5)

    # rename the parent, wait for both to settle, and get the files in both
    os.rename(
        os.path.join(sd1.rootdir, 'a'), os.path.join(sd1.rootdir, 'nuevo'))
    debug(prefix, "Parent renamed")
    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)

    # both trees should be on both, and old 'a' on neither of them
    assert "nuevo/b/c.txt" in files1, "tree not in SD1: %s" % (files1,)
    assert "nuevo/b/c.txt" in files2, "tree not in SD2: %s" % (files2,)
    assert 'a' not in files1, "'a' should not be in SD1: %s" % (files1,)
    assert 'a' not in files2, "'a' should not be in SD1: %s" % (files2,)
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_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_create_both_sd_same_dir_diff_file(test_name, sd1, sd2, sd3, prefix):
    """14. Create different files in same dir in both SDs.

    Create at the same time on one client a directory with file A, and on
    the other client the same directory with file B. Check that both files
    are propagated ok.
    """
    # create both dirs with different files
    os.mkdir(os.path.join(sd1.rootdir, 'dir'))
    os.mkdir(os.path.join(sd2.rootdir, 'dir'))
    open(os.path.join(sd1.rootdir, 'dir', 'file1.txt'), 'w').close()
    open(os.path.join(sd2.rootdir, 'dir', 'file2.txt'), 'w').close()
    debug(prefix, "Dir and files 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(os.path.join(sd1.rootdir, 'dir'))
    files2 = walk_and_list_dir(os.path.join(sd2.rootdir, 'dir'))

    # both files should be on both
    assert "file1.txt" in files1, "file 1 should be in SD1: %s" % (files1,)
    assert "file2.txt" in files1, "file 2 should be in SD1: %s" % (files1,)
    assert "file1.txt" in files2, "file 1 should be in SD2: %s" % (files2,)
    assert "file2.txt" in files2, "file 2 should be in SD2: %s" % (files2,)
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 test_create_directory(test_name, sd1, sd2, sd3, prefix):
    """08. Create a directory. Check."""
    # create the dir in sd1 and wait
    os.mkdir(os.path.join(sd1.rootdir, 'dir'))
    debug(prefix, "Directory created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the dir is in sd2
    assert os.path.exists(os.path.join(sd2.rootdir, 'dir'))
def test_empty_file_funny_name(test_name, sd1, sd2, sd3, prefix):
    """02. Create an empty file with a non-ascii name. Check."""
    # create the file in sd1 and wait
    with open(os.path.join(sd1.rootdir, 'moño.txt'), 'w'):
        debug(prefix, "File created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2
    assert os.path.exists(os.path.join(sd2.rootdir, 'moño.txt'))
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_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_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_fast_unlink_file(test_name, sd1, sd2, sd3, prefix):
    """07. Create a file and immediately after unlink it. Check."""
    # create the file in sd1 and delete it
    open(os.path.join(sd1.rootdir, 'file.txt'), 'w').close()
    os.remove(os.path.join(sd1.rootdir, 'file.txt'))
    debug(prefix, "File created and deleted")

    # wait and check
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    assert not os.path.exists(os.path.join(sd1.rootdir, 'file.txt'))
    assert not os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))
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_sharing(udf_name, sd1, sd2, sd3, prefix):
    """Test 12: Shares inside UDF."""
    folder = yield create_udf(udf_name, sd1, prefix)
    dir1 = os.path.join(folder["path"], "a_dir")
    dir2 = os.path.join(folder["path"], "other_dir")
    os.mkdir(dir2)
    yield sd1.sdt.wait_for_nirvana(1)

    # offer one and accept it
    debug(prefix, "Offering share 1 from SD1")
    share_name_1 = "share_1_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(dir1, sd3.username, share_name_1, Share.VIEW)
    yield d_wait_share
    debug(prefix, "Received share in SD3")
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name_1][0]
    share_id = share['volume_id']
    debug(prefix, "Accepting share")
    yield sd3.sdt.accept_share(share_id)

    # offer a second one
    debug(prefix, "Offering share 2 from SD1")
    share_name_2 = "share_2_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(dir2, sd3.username, share_name_2, Share.MODIFY)
    yield d_wait_share
    debug(prefix, "Received share in SD3")

    # check the shares of sd1
    shared = yield sd1.sdt.list_shared()
    share = [x for x in shared if x['name'] == share_name_1][0]
    assert share['access_level'] == Share.VIEW, (
        "share 1 in sd1 should be View!")
    assert share['accepted'], "share 1 in sd1 should be accepted"
    share = [x for x in shared if x['name'] == share_name_2][0]
    assert share['access_level'] == Share.MODIFY, (
        "share 2 in sd1 should be Modif!")
    assert not share['accepted'], "share 2 in sd1 should NOT be accepted"

    # check the shared of sd3
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name_1][0]
    assert share['access_level'] == Share.VIEW, (
        "share 1 in sd2 should be View!")
    assert share['accepted'], "share 1 in sd2 should be accepted"
    share = [x for x in shares if x['name'] == share_name_2][0]
    assert share['access_level'] == Share.MODIFY, (
        "share 2 in sd2 should be Modif!")
    assert not share['accepted'], "share 2 in sd2 should NOT be accepted"
def create_syncdaemon(username, procnum, homedir, pidfile):
    """Creates a SD with its DBus."""
    prefix = 'Create_syncdaemon:'
    # start dbus
    debug(prefix, 'Starting DBus...')
    (dbus_pid, dbus_address) = start_DBus()
    debug(prefix, 'DBus started with (dbus_pid, dbus_address):',
          dbus_pid, dbus_address)

    # run the client
    env = dict(DBUS_SESSION_BUS_ADDRESS=dbus_address,
               PYTHONPATH=LIB_DIR,
               XDG_CACHE_HOME="tmp/xdg_cache%d" % procnum)
    value = (dbus_pid, dbus_address)
    debug(prefix, "Putting in pidfile %s values %s" % (pidfile, value))
    with open(pidfile, 'w') as f:
        f.write(' '.join(map(str, value)))
        f.write('\n')

    debug(prefix, "Launching SD with dbus", dbus_address)
    dev_launcher.launch(
        os.path.join(CLIENT_DIR, 'bin', 'ubuntuone-syncdaemon'),
        username,
        params=("--send_events_over_dbus", "--udf_autosubscribe=true"),
        environ=env, homedir=homedir, verbose=True)
def test_rename_dir_create_same_name(test_name, sd1, sd2, sd3, prefix):
    """17. Create directory, rename it and create other with same name.

    Create a directory with a file A in it. Wait for nirvana. Rename
    the directory and immediately after create other directory with same
    name, and file B in it. Check.
    """
    # create the directory, file, and wait
    os.mkdir(os.path.join(sd1.rootdir, 'direct'))
    open(os.path.join(sd1.rootdir, 'direct', 'fileA.txt'), 'w').close()
    debug(prefix, "Directory with file A created")
    yield sd1.sdt.wait_for_nirvana(.5)
    debug(prefix, "Nirvana reached")

    # rename the directory, create again, and a new file
    os.rename(
        os.path.join(sd1.rootdir, 'direct'),
        os.path.join(sd1.rootdir, 'newdir'))
    os.mkdir(os.path.join(sd1.rootdir, 'direct'))
    open(os.path.join(sd1.rootdir, 'direct', 'fileB.txt'), 'w').close()
    debug(prefix, "Directory renamed and created new one with file B")

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

    # check in sd2
    files = walk_and_list_dir(sd2.rootdir)
    shouldbe = ['direct', 'direct/fileB.txt', 'newdir', 'newdir/fileA.txt']
    assert files == shouldbe, "Bad files in SD2: %s" % (files,)
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_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_sharing(udf_name, sd1, sd2, sd3, prefix):
    """Test 12: Shares inside UDF."""
    folder = yield create_udf(udf_name, sd1, prefix)
    dir1 = os.path.join(folder["path"], "a_dir")
    dir2 = os.path.join(folder["path"], "other_dir")
    os.mkdir(dir2)
    yield sd1.sdt.wait_for_nirvana(1)

    # offer one and accept it
    debug(prefix, "Offering share 1 from SD1")
    share_name_1 = "share_1_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(dir1, sd3.username, share_name_1, Share.VIEW)
    yield d_wait_share
    debug(prefix, "Received share in SD3")
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name_1][0]
    share_id = share['volume_id']
    debug(prefix, "Accepting share")
    yield sd3.sdt.accept_share(share_id)

    # offer a second one
    debug(prefix, "Offering share 2 from SD1")
    share_name_2 = "share_2_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(dir2, sd3.username, share_name_2, Share.MODIFY)
    yield d_wait_share
    debug(prefix, "Received share in SD3")

    # check the shares of sd1
    shared = yield sd1.sdt.list_shared()
    share = [x for x in shared if x['name'] == share_name_1][0]
    assert share['access_level'] == Share.VIEW, (
        "share 1 in sd1 should be View!")
    assert share['accepted'], "share 1 in sd1 should be accepted"
    share = [x for x in shared if x['name'] == share_name_2][0]
    assert share['access_level'] == Share.MODIFY, (
        "share 2 in sd1 should be Modif!")
    assert not share['accepted'], "share 2 in sd1 should NOT be accepted"

    # check the shared of sd3
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name_1][0]
    assert share['access_level'] == Share.VIEW, (
        "share 1 in sd2 should be View!")
    assert share['accepted'], "share 1 in sd2 should be accepted"
    share = [x for x in shares if x['name'] == share_name_2][0]
    assert share['access_level'] == Share.MODIFY, (
        "share 2 in sd2 should be Modif!")
    assert not share['accepted'], "share 2 in sd2 should NOT be accepted"
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 create_syncdaemon(username, procnum, homedir, pidfile):
    """Creates a SD with its DBus."""
    prefix = 'Create_syncdaemon:'
    # start dbus
    debug(prefix, 'Starting DBus...')
    (dbus_pid, dbus_address) = start_DBus()
    debug(prefix, 'DBus started with (dbus_pid, dbus_address):', dbus_pid,
          dbus_address)

    # run the client
    env = dict(DBUS_SESSION_BUS_ADDRESS=dbus_address,
               PYTHONPATH=LIB_DIR,
               XDG_CACHE_HOME="tmp/xdg_cache%d" % procnum)
    value = (dbus_pid, dbus_address)
    debug(prefix, "Putting in pidfile %s values %s" % (pidfile, value))
    with open(pidfile, 'w') as f:
        f.write(' '.join(map(str, value)))
        f.write('\n')

    debug(prefix, "Launching SD with dbus", dbus_address)
    dev_launcher.launch(os.path.join(CLIENT_DIR, 'bin',
                                     'ubuntuone-syncdaemon'),
                        username,
                        params=("--send_events_over_dbus",
                                "--udf_autosubscribe=true"),
                        environ=env,
                        homedir=homedir,
                        verbose=True)
def test_unlink_file(test_name, sd1, sd2, sd3, prefix):
    """06. Create a file. Check. Unlink it. Check."""
    # create the file in sd1 and wait
    with open(os.path.join(sd1.rootdir, 'file.txt'), 'w'):
        debug(prefix, "File created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2
    assert os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))

    # remove the file, wait for both to settle
    os.remove(os.path.join(sd1.rootdir, 'file.txt'))
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)

    # check
    assert not os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))
def test_unsuscribe_subscribe(udf_name, sd1, sd2, sd3, prefix):
    """Test 15: unsubscribe and subscribe."""
    folder = yield create_udf(udf_name, sd1, prefix)
    folder_id = folder["volume_id"]
    debug(prefix, 'create_folder completed!', folder)
    assert folder['subscribed'], 'sd1 must be subscribed'

    # un-subscribe and check
    yield sd1.sdt.unsubscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1  # UDF was reported as expected
    assert not folders[0]['subscribed'], 'sd1 must NOT be subscribed'

    # subscribe and check
    yield sd1.sdt.subscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1  # UDF was reported as expected
    assert folders[0]['subscribed'], 'sd1 must be subscribed'
def test_unsuscribe_subscribe(udf_name, sd1, sd2, sd3, prefix):
    """Test 15: unsubscribe and subscribe."""
    folder = yield create_udf(udf_name, sd1, prefix)
    folder_id = folder["volume_id"]
    debug(prefix, 'create_folder completed!', folder)
    assert folder['subscribed'], 'sd1 must be subscribed'

    # un-subscribe and check
    yield sd1.sdt.unsubscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1  # UDF was reported as expected
    assert not folders[0]['subscribed'], 'sd1 must NOT be subscribed'

    # subscribe and check
    yield sd1.sdt.subscribe_folder(folder_id)
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 1  # UDF was reported as expected
    assert folders[0]['subscribed'], 'sd1 must be subscribed'
def test_rename_file(test_name, sd1, sd2, sd3, prefix):
    """04. Create a file. Check. Rename it. Check."""
    # create the file in sd1 and wait
    with open(os.path.join(sd1.rootdir, 'file.txt'), 'w'):
        debug(prefix, "File created")
    yield sd2.sdt.wait_for_nirvana(.5)

    # check that the file is in sd2
    assert os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))

    # rename the file, wait for both to settle
    os.rename(
        os.path.join(sd1.rootdir, 'file.txt'),
        os.path.join(sd1.rootdir, 'filenew.txt'))
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)

    # check the new file is there, and the old one isn't
    assert os.path.exists(os.path.join(sd2.rootdir, 'filenew.txt'))
    assert not os.path.exists(os.path.join(sd2.rootdir, 'file.txt'))
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 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_get_folders(udf_name, sd1, sd2, sd3, prefix):
    """Test 2: Assert folder list is correct."""
    udf_values = yield create_udf(udf_name, sd1, prefix)

    yield sd2.sdt.wait_for_nirvana(.5)

    folders = yield sd2.sdt.get_folders()
    debug(prefix, 'get_folders completed!', folders)

    assert len(folders) == 1, 'only 1 folder'

    folder = folders[0]
    assert folder['path'] == os.path.join(sd2.homedir, udf_name), \
        'path correct'
    assert folder['subscribed'], 'udf must be subscribed'
    assert folder['suggested_path'] == os.path.join('~', udf_name), \
        'suggested_path must be correct'
    assert folder['node_id'] == udf_values['node_id'], \
        'node_id mut be correct'
    assert folder['volume_id'] == udf_values['volume_id'], \
        'volume id must be correct'
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_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_get_folders(udf_name, sd1, sd2, sd3, prefix):
    """Test 2: Assert folder list is correct."""
    udf_values = yield create_udf(udf_name, sd1, prefix)

    yield sd2.sdt.wait_for_nirvana(.5)

    folders = yield sd2.sdt.get_folders()
    debug(prefix, 'get_folders completed!', folders)

    assert len(folders) == 1, 'only 1 folder'

    folder = folders[0]
    assert folder['path'] == os.path.join(sd2.homedir, udf_name), \
        'path correct'
    assert folder['subscribed'], 'udf must be subscribed'
    assert folder['suggested_path'] == os.path.join('~', udf_name), \
        'suggested_path must be correct'
    assert folder['node_id'] == udf_values['node_id'], \
        'node_id mut be correct'
    assert folder['volume_id'] == udf_values['volume_id'], \
        'volume id must be correct'
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_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_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_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_sharing_udfitself(udf_name, sd1, sd2, sd3, prefix):
    """Test 18: Sharing the UDF itself."""
    folder = yield create_udf(udf_name, sd1, prefix)

    # offer one and accept it
    debug(prefix, "Offering share 1 from SD1")
    share_name = "share_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(folder["path"], sd3.username, share_name, Share.MODIFY)
    yield d_wait_share
    debug(prefix, "Received share in SD3")
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name][0]
    share_id = share['volume_id']

    debug(prefix, "Accepting share and wait acceptance to propagate")
    yield sd3.sdt.accept_share(share_id)
    yield sd1.sdt.wait_for_nirvana(.5)

    # check the shares of sd1
    shared = yield sd1.sdt.list_shared()
    share = [x for x in shared if x['name'] == share_name][0]
    assert share['access_level'] == Share.MODIFY, (
        "share in sd1 should be Modify!")
    assert share['accepted'], "share in sd1 should be accepted"

    # check the shared of sd3
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name][0]
    assert share['access_level'] == Share.MODIFY, (
        "share in sd2 should be Modify!")
    assert share['accepted'], "share in sd2 should be accepted"
def test_sharing_udfitself(udf_name, sd1, sd2, sd3, prefix):
    """Test 18: Sharing the UDF itself."""
    folder = yield create_udf(udf_name, sd1, prefix)

    # offer one and accept it
    debug(prefix, "Offering share 1 from SD1")
    share_name = "share_" + udf_name
    d_wait_share = sd3.wait_for_event('SV_SHARE_CHANGED')
    sd1.sdt.offer_share(folder["path"], sd3.username, share_name, Share.MODIFY)
    yield d_wait_share
    debug(prefix, "Received share in SD3")
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name][0]
    share_id = share['volume_id']

    debug(prefix, "Accepting share and wait acceptance to propagate")
    yield sd3.sdt.accept_share(share_id)
    yield sd1.sdt.wait_for_nirvana(.5)

    # check the shares of sd1
    shared = yield sd1.sdt.list_shared()
    share = [x for x in shared if x['name'] == share_name][0]
    assert share['access_level'] == Share.MODIFY, (
        "share in sd1 should be Modify!")
    assert share['accepted'], "share in sd1 should be accepted"

    # check the shared of sd3
    shares = yield sd3.sdt.get_shares()
    share = [x for x in shares if x['name'] == share_name][0]
    assert share['access_level'] == Share.MODIFY, (
        "share in sd2 should be Modify!")
    assert share['accepted'], "share in sd2 should be accepted"
def test_create_both_sd_empty(test_name, sd1, sd2, sd3, prefix):
    """12. Create empty files in both SDs.

    Create at the same time on each client two empty files with the same
    name. Check.
    """
    # create two empty files in the SDs
    open(os.path.join(sd1.rootdir, 'file.txt'), 'w').close()
    open(os.path.join(sd2.rootdir, 'file.txt'), 'w').close()
    debug(prefix, "Empty files 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_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_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_renaming_the_udf_itself(udf_name, sd1, sd2, sd3, prefix):
    """Test 7: Assert correct unsubcription when the UDF is renamed."""
    folder1 = os.path.join(sd1.homedir, udf_name)
    folder2 = os.path.join(folder1, "udf_parent_dir")
    folder3 = os.path.join(folder2, "udf_dir")
    debug(prefix, 'test_create_folder using UDF at', folder3)
    os.makedirs(folder3)

    folder = yield sd1.sdt.create_folder(path=folder3)
    debug(prefix, 'create_folder completed!', folder)

    # FIXME: this signal is sometimes lost.
    events = [event['event_name'] for event in sd2.events]
    if 'VM_UDF_CREATED' not in events:
        yield sd2.wait_for_event('VM_UDF_CREATED')

    # rename and wait for nirvana
    #
    # FIXME: this will generate this message from pyinotify:
    #     ERROR: The path <folder3>  of this watch
    #     <Watch ... > must not be trusted anymore
    # this is because the "general" watch manager doesn't have a watch on the
    # parent of the UDF, so it doesn't know how it was moved; actually we
    # don't care, because the UDF is being un-subscribed...
    #
    debug(prefix, 'rename!')
    os.rename(folder3, folder3 + ".renamed")

    debug(prefix, 'wait for nirvanas')
    yield sd1.sdt.wait_for_nirvana(1)
    yield sd2.sdt.wait_for_nirvana(1)

    # both SDs should have the UDF, the first one should have it unsuscribed
    folders = yield sd1.sdt.get_folders()
    udfs = [f for f in folders if f['path'] == folder3]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert not udfs[0]['subscribed'], "The UDF of SD1 is subscribed!"

    folders = yield sd2.sdt.get_folders()
    folder_in_sd2 = os.path.join(sd2.homedir, udf_name,
                                 "udf_parent_dir", "udf_dir")
    udfs = [f for f in folders if f['path'] == folder_in_sd2]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert udfs[0]['subscribed'], "The UDF of SD1 is not subscribed!"
def test_renaming_the_udf_itself(udf_name, sd1, sd2, sd3, prefix):
    """Test 7: Assert correct unsubcription when the UDF is renamed."""
    folder1 = os.path.join(sd1.homedir, udf_name)
    folder2 = os.path.join(folder1, "udf_parent_dir")
    folder3 = os.path.join(folder2, "udf_dir")
    debug(prefix, 'test_create_folder using UDF at', folder3)
    os.makedirs(folder3)

    folder = yield sd1.sdt.create_folder(path=folder3)
    debug(prefix, 'create_folder completed!', folder)

    # FIXME: this signal is sometimes lost.
    events = [event['event_name'] for event in sd2.events]
    if 'VM_UDF_CREATED' not in events:
        yield sd2.wait_for_event('VM_UDF_CREATED')

    # rename and wait for nirvana
    #
    # FIXME: this will generate this message from pyinotify:
    #     ERROR: The path <folder3>  of this watch
    #     <Watch ... > must not be trusted anymore
    # this is because the "general" watch manager doesn't have a watch on the
    # parent of the UDF, so it doesn't know how it was moved; actually we
    # don't care, because the UDF is being un-subscribed...
    #
    debug(prefix, 'rename!')
    os.rename(folder3, folder3 + ".renamed")

    debug(prefix, 'wait for nirvanas')
    yield sd1.sdt.wait_for_nirvana(1)
    yield sd2.sdt.wait_for_nirvana(1)

    # both SDs should have the UDF, the first one should have it unsuscribed
    folders = yield sd1.sdt.get_folders()
    udfs = [f for f in folders if f['path'] == folder3]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert not udfs[0]['subscribed'], "The UDF of SD1 is subscribed!"

    folders = yield sd2.sdt.get_folders()
    folder_in_sd2 = os.path.join(sd2.homedir, udf_name, "udf_parent_dir",
                                 "udf_dir")
    udfs = [f for f in folders if f['path'] == folder_in_sd2]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert udfs[0]['subscribed'], "The UDF of SD1 is not subscribed!"
def test_no_events_from_ancestors_if_unsubsc(udf_name, sd1, sd2, sd3, prefix):
    """Test 17: Watches are removed in ancestors."""
    # structure:
    # base_dir
    #    \---parent
    #         |--- udf_dir1
    #         \--- middle
    #                \--- udf_dir2
    #
    # unsubscribing udf2 should remove the watch of "middle", but not from
    # "homedir", as the later is also an ancestor of other udf

    base_dir = os.path.join(sd1.homedir, udf_name)
    parent = os.path.join(base_dir, "parent")
    udf_dir1 = os.path.join(parent, "udf_dir1")
    middle = os.path.join(parent, "middle")
    udf_dir2 = os.path.join(middle, "udf_dir2")
    os.makedirs(udf_dir1)
    os.makedirs(udf_dir2)

    yield sd1.sdt.create_folder(path=udf_dir1)
    yield sd1.sdt.create_folder(path=udf_dir2)
    debug(prefix, 'create_folders completed!')
    yield sd1.sdt.wait_for_nirvana(.5)

    # rename udf2 and wait for nirvana
    debug(prefix, 'rename!')
    os.rename(udf_dir2, udf_dir2 + ".renamed")
    debug(prefix, 'wait for nirvana')
    yield sd1.sdt.wait_for_nirvana(1)

    # check that UDF1 ancestors still have the watches by renaming
    # 'parent' and verifying that UDF1 is unsubscribed; there's no
    # way to check that 'middle' lost its watch
    debug(prefix, 'check!')
    os.rename(parent, parent + ".renamed")
    folders = yield sd1.sdt.get_folders()
    udf = [x for x in folders if x['path'] == udf_dir1][0]
    assert not udf['subscribed'], "%s of SD1 is subscribed!" % udf
def test_renaming_ancestor(udf_name, sd1, sd2, sd3, prefix):
    """Test 6: Assert correct unsubscription when an ancestor is renamed."""
    folder1 = os.path.join(sd1.homedir, udf_name)
    folder2 = os.path.join(folder1, "udf_parent_dir")
    folder3 = os.path.join(folder2, "udf_dir")
    debug(prefix, 'test_create_folder using UDF at', folder3)
    os.makedirs(folder3)

    folder = yield sd1.sdt.create_folder(path=folder3)
    debug(prefix, 'create_folder completed!', folder)

    yield sd2.sdt.wait_for_nirvana(.5)

    # FIXME: this signal is sometimes lost.
    events = [event['event_name'] for event in sd2.events]
    if 'VM_UDF_CREATED' not in events:
        yield sd2.wait_for_event('VM_UDF_CREATED')

    # rename and wait for nirvana
    debug(prefix, 'rename!')
    os.rename(folder2, folder2 + ".renamed")
    debug(prefix, 'wait for nirvanas')
    yield sd1.sdt.wait_for_nirvana(1)
    yield sd2.sdt.wait_for_nirvana(1)

    # both SDs should have the UDF, the first one should be unsuscribed
    folders = yield sd1.sdt.get_folders()
    udfs = [f for f in folders if f['path'] == folder3]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert not udfs[0]['subscribed'], "The UDF of SD1 is subscribed!"

    folders = yield sd2.sdt.get_folders()
    folder_in_sd2 = os.path.join(sd2.homedir, udf_name,
                                 "udf_parent_dir", "udf_dir")
    udfs = [f for f in folders if f['path'] == folder_in_sd2]
    assert len(udfs) == 1, "SD1 has udfs != 1 (%d)" % len(udfs)
    assert udfs[0]['subscribed'], "The UDF of SD1 is not subscribed!"
def test_unsubscribe_no_side_effects(udf_name, sd1, sd2, sd3, prefix):
    """Test 3: Assert sd1 can unsubscribe from an UDF without side effects."""
    folder = yield create_udf(udf_name, sd1, prefix)
    assert folder['subscribed'], 'sd1 subscribed'

    yield sd2.sdt.wait_for_nirvana(.5)

    # is UDF created already?
    folders = yield sd1.sdt.get_folders()
    debug(prefix, 'folders for SD1', folders)

    fid = folder['volume_id']
    folder = yield sd1.sdt.unsubscribe_folder(fid)
    folder, = folder
    debug(prefix, 'unsubscribe_folder completed!', folder)
    assert not folder['subscribed'], 'sd1 no longer subscribed'

    folders = yield sd2.sdt.get_folders()
    debug(prefix, 'folders for SD2', folders)
    assert len(folders) == 1, 'only 1 folder'
    assert folders[0]['subscribed'], 'sd2 subscribed'
def test_renaming_ancestor_of_two(udf_name, sd1, sd2, sd3, prefix):
    """Test 16: Check behavior when an ancestor of more than one is renamed."""
    udfdir1 = os.path.join(sd1.homedir, udf_name)
    udfdir2 = os.path.join(udfdir1, "udf_parent_dir")
    os.makedirs(udfdir2)
    udfdir3 = os.path.join(udfdir2, "udf_dir1")
    udfdir4 = os.path.join(udfdir2, "udf_dir2")

    yield sd1.sdt.create_folder(path=udfdir3)
    yield sd1.sdt.create_folder(path=udfdir4)
    debug(prefix, 'create_folders completed!')

    yield sd1.sdt.wait_for_nirvana(.5)

    # FIXME: this signal is sometimes lost.
    events = [event['event_name'] for event in sd2.events]
    if 'VM_UDF_CREATED' not in events:
        yield sd2.wait_for_event('VM_UDF_CREATED')

    # rename and wait for nirvana
    debug(prefix, 'rename!')
    os.rename(udfdir2, udfdir2 + ".renamed")
    debug(prefix, 'wait for nirvanas')
    yield sd1.sdt.wait_for_nirvana(1)
    yield sd2.sdt.wait_for_nirvana(1)

    # both SDs should have UDFs, the first one "unsuscribed"
    folders = yield sd1.sdt.get_folders()
    assert len(folders) == 2, "SD1 has udfs != 2 (%d)" % len(folders)
    for udf in folders:
        assert not udf['subscribed'], "%s of SD1 is subscribed!" % udf

    folders = yield sd2.sdt.get_folders()
    assert len(folders) == 2, "SD2 has udfs != 2 (%d)" % len(folders)
    for udf in folders:
        assert udf['subscribed'], "%s of SD2 is NOT subscribed!" % udf
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 check(failure):
     """Error must have been occurred. Analyze it."""
     is_error = failure.type == tools.ErrorSignal
     debug(prefix, 'UDF creation failed. Error:', failure.type)
     assert is_error, 'failure must be a tools.ErrorSignal'
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_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)
        if skipit:
            debug(testprefix, 'Skipping test!', skipit, previous_newline=True)
            continue

        debug(testprefix, 'Starting test %d of %d' % (i + 1, len_tests),
              previous_newline=True)

        try:
            yield test(test_name, sd1, sd2, sd3, testprefix)
        except Exception, e:
            debug(testprefix, 'Crushing failure and despair, :( -- ', str(e))
            raise
        else:
            debug(testprefix, 'Test finished ok! :)')
        finally:
            debug(testprefix, 'Cleaning up.')

            # wait for SDs to finish
            yield sd1.sdt.wait_for_nirvana(.5)
            yield sd2.sdt.wait_for_nirvana(.5)
            yield sd3.sdt.wait_for_nirvana(.5)

            # clean up UDFs (removing from 1 should remove it from all)
            debug(testprefix, 'Removing old folders.')
            folders = yield sd1.sdt.get_folders()
            for udf in folders:
                vid = udf['volume_id']
                debug(testprefix, 'Deleting UDF with id:', vid)
                yield sd1.sdt.delete_folder(folder_id=vid)

            # wait for SDs to finish
 def debug(self, msg, *args):
     """Print debug messages."""
     if self.verbose:
         debug(self.prefix, msg, *args)
def execute_tests(all_tests, sd1, sd2, sd3):
    """Execute the whole suite, please."""
    prefix = 'Execute tests:'

    debug(prefix, 'Starting')
    assert os.path.exists(sd1.rootdir), sd1.rootdir + ' must exist'

    # create directory and wait for it to go all places
    dir_in_sd1 = sd1.wait_for_event('AQ_DIR_NEW_OK')
    dir_in_sd2 = sd1.wait_for_event('FS_DIR_CREATE')
    os.mkdir(os.path.join(sd1.rootdir, ".mark"))
    yield dir_in_sd1
    debug(prefix, 'AQ_DIR_NEW_OK in sd1 done.')
    yield dir_in_sd2
    debug(prefix, 'FS_DIR_CREATE in sd2 done.')

    # calm down
    yield sd1.sdt.wait_for_nirvana(.5)
    yield sd2.sdt.wait_for_nirvana(.5)
    debug(prefix, 'Nirvana reached for sd1 and sd2.')

    len_tests = len(all_tests)
    for i, test in enumerate(all_tests):
        test_name = test.func_name
        testprefix = ' '.join(("===", test_name, "==="))

        skipit = getattr(test, 'skip', None)
        if skipit:
            debug(testprefix, 'Skipping test!', skipit, previous_newline=True)
            continue

        debug(testprefix, 'Starting test %d of %d' % (i + 1, len_tests),
              previous_newline=True)

        try:
            yield test(test_name, sd1, sd2, sd3, testprefix)
        except Exception, e:
            debug(testprefix, 'Crushing failure and despair, :( -- ', str(e))
            raise
        else:
            debug(testprefix, 'Test finished ok! :)')
        finally:
def main(test_filter, repeat=False):
    """Main function."""
    all_tests = get_all_tests(test_filter)

    prefix = 'main:'
    timestamp = time.strftime("%Y%m%d%M%H%S")

    # create user
    user1 = "integtest" + timestamp
    user2 = "integotro" + timestamp
    for u in (user1, user2):
        services.make_storage_user(username=u)
        debug(prefix, 'User created:', u)

    debug(prefix, 'Content blobs created')

    sd1 = SyncDaemon(user1, 1, timestamp, verbose=True)
    debug(prefix, 'SyncDaemon 1 created.')
    sd2 = SyncDaemon(user1, 2, timestamp, verbose=True)
    debug(prefix, 'SyncDaemon 2 created.')
    sd3 = SyncDaemon(user2, 3, timestamp, verbose=True)
    debug(prefix, 'SyncDaemon 2 created.')

    yield sd1.start()
    debug(prefix, 'SyncDaemon 1 started.')
    yield sd2.start()
    debug(prefix, 'SyncDaemon 2 started.')
    yield sd3.start()
    debug(prefix, 'SyncDaemon 3 started.')

    try:
        if repeat:
            i = 0
            while True:
                i += 1
                debug(prefix, 'Executing tests, run', i)
                yield execute_tests(all_tests, sd1, sd2, sd3)
        else:
            yield execute_tests(all_tests, sd1, sd2, sd3)
            debug(prefix, 'Tests executed.')
    except Exception, e:
        print '\n', '!' * 20, 'There was a problem. Failure below.', '!' * 20
        print e
        print '!' * 20, 'There was a problem. Failure above.', '!' * 20