Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions acceptance/cmd/fs/cp/file-to-nonexistent-dir/foo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cloud = true
109 changes: 109 additions & 0 deletions acceptance/cmd/fs/cp/file-to-nonexistent-dir/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

=== foo.txt -> local
>>> [CLI] fs cp foo.txt local/existing-from-local/
foo.txt -> local/existing-from-local/foo.txt

>>> [CLI] fs cp foo.txt local/nonexistent/mydir/
Error: no such directory: local/nonexistent/mydir

Exit code: 1

=== foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-local/
foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-local/foo.txt

>>> [CLI] fs cp foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-local/
foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-local/foo.txt

>>> [CLI] fs cp foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> local
>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt local/existing-from-dbfs/
dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> local/existing-from-dbfs/foo.txt

>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt local/nonexistent/mydir/
Error: no such directory: local/nonexistent/mydir

Exit code: 1

=== dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/
dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/foo.txt

>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/
dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/foo.txt

>>> [CLI] fs cp dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> local
>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt local/existing-from-volume/
dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> local/existing-from-volume/foo.txt

>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt local/nonexistent/mydir/
Error: no such directory: local/nonexistent/mydir

Exit code: 1

=== dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/
dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/foo.txt

>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /tmp/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]
>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/
dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt -> dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/foo.txt

>>> [CLI] fs cp dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/src/foo.txt dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent/mydir/
Error: no such directory: /Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/nonexistent

Exit code: 1

=== Copies landed in the existing directories
>>> cat local/existing-from-local/foo.txt
abc

>>> [CLI] fs cat dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-local/foo.txt
abc

>>> [CLI] fs cat dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-local/foo.txt
abc

>>> cat local/existing-from-dbfs/foo.txt
abc

>>> [CLI] fs cat dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/foo.txt
abc

>>> [CLI] fs cat dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-dbfs/foo.txt
abc

>>> cat local/existing-from-volume/foo.txt
abc

>>> [CLI] fs cat dbfs:/tmp/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/foo.txt
abc

>>> [CLI] fs cat dbfs:/Volumes/main/default/fs-cp-test-[UNIQUE_NAME]/existing-from-volume/foo.txt
abc
46 changes: 46 additions & 0 deletions acceptance/cmd/fs/cp/file-to-nonexistent-dir/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# A trailing slash on the target means "copy into this directory": it works when the directory
# exists and fails with "no such directory" when it does not. Covers local, DBFS and UC Volume
# sources and targets.
CATALOG_NAME="main"
SCHEMA_NAME="default"
VOLUME_NAME="fs-cp-test-${UNIQUE_NAME}"
VOLUME="dbfs:/Volumes/${CATALOG_NAME}/${SCHEMA_NAME}/${VOLUME_NAME}"
DBFS="dbfs:/tmp/fs-cp-test-${UNIQUE_NAME}"

cleanup() {
$CLI volumes delete "${CATALOG_NAME}.${SCHEMA_NAME}.${VOLUME_NAME}" 2>/dev/null || true
$CLI fs rm -r ${DBFS} 2>/dev/null || true
}
trap cleanup EXIT

$CLI volumes create "${CATALOG_NAME}" "${SCHEMA_NAME}" "${VOLUME_NAME}" MANAGED >/dev/null
for root in ${VOLUME} ${DBFS}; do
$CLI fs mkdir $root/src
$CLI fs cp foo.txt $root/src/foo.txt >/dev/null
done

for src_kind in local dbfs volume; do
case $src_kind in
local) src=foo.txt ;;
dbfs) src=${DBFS}/src/foo.txt ;;
volume) src=${VOLUME}/src/foo.txt ;;
esac
# Separate existing directory per source, so later copies are not skipped as already existing.
existing="existing-from-$src_kind"
mkdir -p local/$existing
$CLI fs mkdir ${DBFS}/$existing
$CLI fs mkdir ${VOLUME}/$existing
for dst in local ${DBFS} ${VOLUME}; do
title "$src -> $dst"
trace $CLI fs cp $src $dst/$existing/
errcode trace $CLI fs cp $src $dst/nonexistent/mydir/
done
done

title "Copies landed in the existing directories"
for existing in existing-from-local existing-from-dbfs existing-from-volume; do
trace cat local/$existing/foo.txt
trace $CLI fs cat ${DBFS}/$existing/foo.txt
trace $CLI fs cat ${VOLUME}/$existing/foo.txt
done
rm -rf local
6 changes: 6 additions & 0 deletions acceptance/cmd/fs/cp/file-to-nonexistent-dir/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Cloud = true

# Local paths in errors use the OS separator.
[[Repls]]
Old = 'local\\nonexistent\\mydir'
New = 'local/nonexistent/mydir'
1 change: 1 addition & 0 deletions acceptance/cmd/fs/dbfs/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cloud = true
51 changes: 51 additions & 0 deletions acceptance/cmd/fs/dbfs/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

=== Create a directory and write a file in it
>>> [CLI] fs mkdir dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir

>>> [CLI] fs cp big.bin dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin
big.bin -> dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin

=== Read the file back
>>> cmp big.bin big.back
contents match

=== Writing over an existing file needs --overwrite
>>> [CLI] fs cp big.bin dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin
big.bin -> dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin (skipped; already exists)

>>> [CLI] fs cp --overwrite big.bin dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin
big.bin -> dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin

=== Writing into a directory that does not exist fails
>>> [CLI] fs cp big.bin dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/missing/big.bin
Error: no such directory: /tmp/fs-dbfs-[UNIQUE_NAME]/missing

Exit code: 1

=== List a directory, then a file
>>> [CLI] fs ls dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir
big.bin

>>> [CLI] fs ls dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin
Error: not a directory: /tmp/fs-dbfs-[UNIQUE_NAME]/dir/big.bin

Exit code: 1

=== cat a directory fails
>>> [CLI] fs cat dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir
Error: not a file: /tmp/fs-dbfs-[UNIQUE_NAME]/dir

Exit code: 1

=== rm a non-empty directory needs -r
>>> [CLI] fs rm dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir
Error: directory not empty: /tmp/fs-dbfs-[UNIQUE_NAME]/dir

Exit code: 1

>>> [CLI] fs rm -r dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir

>>> [CLI] fs ls dbfs:/tmp/fs-dbfs-[UNIQUE_NAME]/dir
Error: no such directory: /tmp/fs-dbfs-[UNIQUE_NAME]/dir

Exit code: 1
38 changes: 38 additions & 0 deletions acceptance/cmd/fs/dbfs/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# fs commands against DBFS: the filer's error mapping for DBFS-specific responses, and a file over
# the 1 MB DBFS block size so writes and reads are split into several API calls.
DBFS="dbfs:/tmp/fs-dbfs-${UNIQUE_NAME}"

cleanup() {
$CLI fs rm -r ${DBFS} 2>/dev/null || true
rm -f big.bin big.back
}
trap cleanup EXIT

python3 -c 'import sys; sys.stdout.buffer.write(bytes(range(256)) * 6000)' > big.bin

title "Create a directory and write a file in it"
trace $CLI fs mkdir ${DBFS}/dir
trace $CLI fs cp big.bin ${DBFS}/dir/big.bin

title "Read the file back"
$CLI fs cp ${DBFS}/dir/big.bin big.back > /dev/null
trace cmp big.bin big.back && echo "contents match"

title "Writing over an existing file needs --overwrite"
trace $CLI fs cp big.bin ${DBFS}/dir/big.bin
trace $CLI fs cp --overwrite big.bin ${DBFS}/dir/big.bin

title "Writing into a directory that does not exist fails"
errcode trace $CLI fs cp big.bin ${DBFS}/missing/big.bin

title "List a directory, then a file"
trace $CLI fs ls ${DBFS}/dir
errcode trace $CLI fs ls ${DBFS}/dir/big.bin

title "cat a directory fails"
errcode trace $CLI fs cat ${DBFS}/dir

title "rm a non-empty directory needs -r"
errcode trace $CLI fs rm ${DBFS}/dir
trace $CLI fs rm -r ${DBFS}/dir
errcode trace $CLI fs ls ${DBFS}/dir
1 change: 1 addition & 0 deletions acceptance/cmd/fs/dbfs/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cloud = true
31 changes: 0 additions & 31 deletions integration/cmd/fs/cp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,37 +369,6 @@ func TestFsCpSourceIsDirectoryButTargetIsFile(t *testing.T) {
}
}

func TestFsCpFileToNonExistentDir(t *testing.T) {
t.Parallel()

for _, testCase := range copyTests() {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()

ctx := t.Context()
sourceFiler, sourceDir := testCase.setupSource(t)
targetFiler, targetDir := testCase.setupTarget(t)
setupSourceFile(t, ctx, sourceFiler)

// Create a directory in the target
err := targetFiler.Mkdir(ctx, "existingdir")
require.NoError(t, err)

// Copy file to existing directory with trailing slash - should succeed
existingDir := path.Join(targetDir, "existingdir") + "/"
testcli.RequireSuccessfulRun(t, ctx, "fs", "cp", path.Join(sourceDir, "foo.txt"), existingDir)
assertTargetFile(t, ctx, targetFiler, "existingdir/foo.txt")

// Try to copy file to a non-existent directory with trailing slash - should fail
nonExistentDir := path.Join(targetDir, "nonexistent", "mydir") + "/"
_, _, err = testcli.RequireErrorRun(t, ctx, "fs", "cp", path.Join(sourceDir, "foo.txt"), nonExistentDir)
assert.Error(t, err)
assert.Contains(t, err.Error(), "directory")
assert.Contains(t, err.Error(), "no such directory")
})
}
}

func TestFsCpFileToNonExistentDirWindowsPaths(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("Skipping test on non-windows OS")
Expand Down
Loading
Loading