Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SVCS-479] Raise exception for copy/move replace folder that orphans itself. #333

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
153 changes: 117 additions & 36 deletions tests/core/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from unittest import mock
from waterbutler.core import metadata
from waterbutler.core import exceptions
from waterbutler.core.path import WaterButlerPath


@pytest.fixture
Expand Down Expand Up @@ -37,6 +38,48 @@ def test_cant_intra_move(self, provider1):
def test_can_intra_move(self, provider2):
assert provider2.can_intra_move(provider2) is True

@pytest.mark.asyncio
async def test_will_orphan_dest_is_file(self, provider1):
src_path = WaterButlerPath(
'/folder1/folder1/',
_ids=['root', 'folder', 'Folder'],
folder=True
)
dest_path = WaterButlerPath(
'/folder1/',
_ids=['root','folder'],
folder=False
)
assert provider1.replace_will_orphan(src_path, dest_path) == False

@pytest.mark.asyncio
async def test_will_orphan_dest_different_names(self, provider1):
src_path = WaterButlerPath(
'/folder1/folder1/',
_ids=['root', 'folder', 'Folder'],
folder=True
)
dest_path = WaterButlerPath(
'/folder2/',
_ids=['root','folder'],
folder=True
)
assert provider1.replace_will_orphan(src_path, dest_path) == False

@pytest.mark.asyncio
async def test_will_orphan_dest_different_branch(self, provider1):
src_path = WaterButlerPath(
'/other_folder/folder1/',
_ids=['root', 'other_folder', 'Folder'],
folder=True
)
dest_path = WaterButlerPath(
'/folder1/',
_ids=['root','folder'],
folder=True
)
assert provider1.replace_will_orphan(src_path, dest_path) == False

@pytest.mark.asyncio
async def test_exists(self, provider1):
ret = await provider1.exists('somepath')
Expand Down Expand Up @@ -172,7 +215,7 @@ async def test_no_problem(self, provider1):
dest_path = await provider1.validate_path('/test/path/')
provider1.exists = utils.MockCoroutine(return_value=False)

handled = await provider1.handle_naming(src_path, dest_path)
handled = await provider1.handle_conflicts(provider1, src_path, dest_path)

assert handled == src_path.child('path', folder=True)
assert handled.is_dir is True
Expand All @@ -185,7 +228,7 @@ async def test_rename_via_path(self, provider1):
dest_path = await provider1.validate_path('/test/name2')
provider1.exists = utils.MockCoroutine(return_value=False)

handled = await provider1.handle_naming(src_path, dest_path)
handled = await provider1.handle_conflicts(provider1, src_path, dest_path)

assert handled.name == 'name2'
assert handled.is_file is True
Expand All @@ -196,24 +239,11 @@ async def test_rename_explicit(self, provider1):
src_path = await provider1.validate_path('/test/name1')
provider1.exists = utils.MockCoroutine(return_value=False)

handled = await provider1.handle_naming(src_path, dest_path, rename='name2')
handled = await provider1.handle_conflicts(provider1, src_path, dest_path, rename='name2')

assert handled.name == 'name2'
assert handled.is_file is True

@pytest.mark.asyncio
async def test_no_problem_file(self, provider1):
src_path = await provider1.validate_path('/test/path')
dest_path = await provider1.validate_path('/test/path')
provider1.exists = utils.MockCoroutine(return_value=False)

handled = await provider1.handle_naming(src_path, dest_path)

assert handled == dest_path # == not is
assert handled.is_file is True
assert len(handled.parts) == 3 # Includes root
assert handled.name == 'path'


class TestCopy:

Expand All @@ -222,22 +252,23 @@ async def test_handles_naming_false(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.copy(provider1, src_path, dest_path, handle_naming=False)
await provider1.copy(provider1, src_path, dest_path, handle_conflicts=False)

assert provider1.handle_naming.called is False
assert provider1.handle_conflicts.called is False

@pytest.mark.asyncio
async def test_handles_naming(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.copy(provider1, src_path, dest_path)

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename=None,
Expand All @@ -249,11 +280,12 @@ async def test_passes_on_conflict(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.copy(provider1, src_path, dest_path, conflict='keep')

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename=None,
Expand All @@ -265,17 +297,27 @@ async def test_passes_on_rename(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.copy(provider1, src_path, dest_path, rename='Baz')

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename='Baz',
conflict='replace',
)

@pytest.mark.asyncio
async def test_copy_will_self_overwrite(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/')
provider1.will_self_overwrite = utils.MockCoroutine()

with pytest.raises(exceptions.OverwriteSelfError):
await provider1.copy(provider1, src_path, dest_path)

@pytest.mark.asyncio
async def test_checks_can_intra_copy(self, provider1):
provider1.can_intra_copy = mock.Mock(return_value=False)
Expand All @@ -300,6 +342,19 @@ async def test_calls_intra_copy(self, provider1):
provider1.can_intra_copy.assert_called_once_with(provider1, src_path)
provider1.intra_copy.assert_called_once_with(provider1, src_path, dest_path)

@pytest.mark.asyncio
@pytest.mark.aiohttpretty
async def test_intra_copy_folder_orphan(self, provider1):
src_path = await provider1.validate_path('/folder1/folder1/')
dest_path = await provider1.validate_path('/')

provider1.can_intra_copy = mock.Mock(return_value=True)

with pytest.raises(exceptions.OrphanSelfError) as exc:
await provider1.copy(provider1, src_path, dest_path)
assert exc.value.code == 400
assert exc.typename == 'OrphanSelfError'

@pytest.mark.asyncio
async def test_calls_folder_op_on_dir(self, provider1):
src_path = await provider1.validate_path('/source/path/')
Expand Down Expand Up @@ -339,22 +394,23 @@ async def test_handles_naming_false(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.move(provider1, src_path, dest_path, handle_naming=False)
await provider1.move(provider1, src_path, dest_path, handle_conflicts=False)

assert provider1.handle_naming.called is False
assert provider1.handle_conflicts.called is False

@pytest.mark.asyncio
async def test_handles_naming(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.move(provider1, src_path, dest_path)

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename=None,
Expand All @@ -366,11 +422,12 @@ async def test_passes_on_conflict(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.move(provider1, src_path, dest_path, conflict='keep')

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename=None,
Expand All @@ -382,17 +439,27 @@ async def test_passes_on_rename(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/path')

provider1.handle_naming = utils.MockCoroutine()
provider1.handle_conflicts = utils.MockCoroutine()

await provider1.move(provider1, src_path, dest_path, rename='Baz')

provider1.handle_naming.assert_called_once_with(
provider1.handle_conflicts.assert_called_once_with(
provider1,
src_path,
dest_path,
rename='Baz',
conflict='replace',
)

@pytest.mark.asyncio
async def test_move_will_self_overwrite(self, provider1):
src_path = await provider1.validate_path('/source/path')
dest_path = await provider1.validate_path('/destination/')
provider1.will_self_overwrite = utils.MockCoroutine()

with pytest.raises(exceptions.OverwriteSelfError):
await provider1.move(provider1, src_path, dest_path)

@pytest.mark.asyncio
async def test_checks_can_intra_move(self, provider1):
provider1.can_intra_move = mock.Mock(return_value=False)
Expand All @@ -417,6 +484,20 @@ async def test_calls_intra_move(self, provider1):
provider1.can_intra_move.assert_called_once_with(provider1, src_path)
provider1.intra_move.assert_called_once_with(provider1, src_path, dest_path)

@pytest.mark.asyncio
@pytest.mark.aiohttpretty
async def test_intra_move_folder_orphan(self, provider1):
src_path = await provider1.validate_path('/folder1/folder1/')
dest_path = await provider1.validate_path('/')

provider1.can_intra_move = mock.Mock(return_value=True)

with pytest.raises(exceptions.OrphanSelfError) as exc:
await provider1.move(provider1, src_path, dest_path)

assert exc.value.code == 400
assert exc.typename == 'OrphanSelfError'

@pytest.mark.asyncio
async def test_calls_folder_op_on_dir_and_delete(self, provider1):
src_path = await provider1.validate_path('/source/path/')
Expand Down Expand Up @@ -453,7 +534,7 @@ async def test_calls_copy_and_delete(self, provider1):
provider1,
src_path,
dest_path,
handle_naming=False
handle_conflicts=False
)

@pytest.mark.asyncio
Expand All @@ -473,7 +554,7 @@ async def test_no_delete_on_copy_error(self, provider1):
provider1,
src_path,
dest_path,
handle_naming=False
handle_conflicts=False
)

def test_build_range_header(self, provider1):
Expand Down
Loading