git-lfs/t/t-unlock.sh
Chris Darroch d003b9dd95 t/t-unlock.sh: test unlock by path without refspec
As described in a previous commit in this PR, since PR #2773 the
lfstest-gitserver.go test server can mimic a Git LFS locking API
service which either does or does not read a "refspec" query parameter
and use it to filter results when searching for a lock matching a specific
file path.

Four tests of the "git lfs unlock" command were added or modified in
that PR which all require the test server to check for a "refspec" query
parameter when responding to a request to list matching locks.  These
tests signal the test server to perform the "refspec" argument check
by using test repository names that contain the special keyword suffix
"branch-required".  (However, these tests did not exercise that test
server behaviour because they all passed the --id option to the "git lfs
unlock" command, thus causing it to make no lock listing requests to
the test server.)

In the previous commit in this PR where we described these tests and
their history, we corrected them and added two more of the same kind
which also require the test server to filter search results using
the "refspec" query parameter.

However, no tests were added in PR #2773 which explicitly test the
"git lfs unlock" command against an API service that did not require
the "refspec" query parameter when searching for matching locks.  Some
tests, such as the "unlocking a lock (--json)" test, do so implicitly,
but none check all aspects of the expected behaviour in this case.

We therefore add a pair of tests, the first of which simply performs a
"git lfs unlock" command using a file path argument and confirming
it succeeds when the test server emulates an older API service that
does not check the "refspec" query argument in lock listing requests.
This test is akin to others, like the "unlocking a lock (--json)" test,
but explicitly named to make its intent clear.

The second new test we add checks that a "git lfs unlock" command which
uses a file path argument succeeds and removes a lock even if it passes
a "refspec" query parameter to the server that does not match the ref
name sent in the original lock request, so long as the test server
is emulating an older API service and does not recognize or check the
"refspec" argument in lock listing requests.  Note that this new
"unlocking a lock by path with bad ref without a ref required" test
is similar to the "unlocking a lock by path with bad ref" test, but
because it configures the test server to behave like an older API
service, it succeeds in removing the lock, whereas the "unlocking a
lock by path with bad ref" test expects to not remove the lock due to
the mismatched refs in its lock and unlock requests.
2023-10-04 10:26:45 -07:00

561 lines
13 KiB
Bash
Executable File

#!/usr/bin/env bash
. "$(dirname "$0")/testlib.sh"
setup_repo () {
setup_remote_repo_with_file "$1" "$2"
git lfs track --lockable "*.dat"
git add -u
git commit -m 'Mark files lockable'
}
begin_test "unlocking a lock by path without a ref required"
(
set -e
reponame="unlock-by-path-main-branch-not-required"
setup_repo "$reponame" "c.dat"
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/main"
git lfs unlock "c.dat"
refute_server_lock "$reponame" "$id" "refs/heads/main"
)
end_test
begin_test "unlocking a lock by path with good ref"
(
set -e
reponame="unlock-by-path-main-branch-required"
setup_repo "$reponame" "c.dat"
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/main"
git lfs unlock "c.dat"
refute_server_lock "$reponame" "$id" "refs/heads/main"
)
end_test
begin_test "unlocking a lock by id with good ref"
(
set -e
reponame="unlock-by-id-main-branch-required"
setup_repo "$reponame" "c.dat"
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/main"
git lfs unlock --id="$id"
refute_server_lock "$reponame" "$id" "refs/heads/main"
)
end_test
begin_test "unlocking a lock by path with tracked ref"
(
set -e
reponame="unlock-by-path-tracked-branch-required"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "c" > c.dat
git add .gitattributes c.dat
git commit -m "add c.dat"
git config push.default upstream
git config branch.main.merge refs/heads/tracked
git config branch.main.remote origin
git push origin main
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/tracked"
git lfs unlock "c.dat"
refute_server_lock "$reponame" "$id" "refs/heads/tracked"
)
end_test
begin_test "unlocking a lock by id with tracked ref"
(
set -e
reponame="unlock-by-id-tracked-branch-required"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "c" > c.dat
git add .gitattributes c.dat
git commit -m "add c.dat"
git config push.default upstream
git config branch.main.merge refs/heads/tracked
git config branch.main.remote origin
git push origin main
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/tracked"
git lfs unlock --id="$id"
refute_server_lock "$reponame" "$id" "refs/heads/tracked"
)
end_test
begin_test "unlocking a lock by path with bad ref without a ref required"
(
set -e
reponame="unlock-by-path-other-branch-not-required"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "c" > c.dat
git add .gitattributes c.dat
git commit -m "add c.dat"
git push origin main:other
git checkout -b other
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/other"
git checkout main
git lfs unlock "c.dat"
refute_server_lock "$reponame" "$id" "refs/heads/other"
)
end_test
begin_test "unlocking a lock by path with bad ref"
(
set -e
reponame="unlock-by-path-other-branch-required"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "c" > c.dat
git add .gitattributes c.dat
git commit -m "add c.dat"
git push origin main:other
git checkout -b other
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/other"
git checkout main
git lfs unlock "c.dat" 2>&1 | tee unlock.log
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to fail"
exit 1
fi
assert_server_lock "$reponame" "$id" "refs/heads/other"
grep 'Expected ref "refs/heads/other", got "refs/heads/main"' unlock.log
)
end_test
begin_test "unlocking a lock by id with bad ref"
(
set -e
reponame="unlock-by-id-other-branch-required"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "c" > c.dat
git add .gitattributes c.dat
git commit -m "add c.dat"
git push origin main:other
git checkout -b other
git lfs lock --json "c.dat" | tee lock.log
id=$(assert_lock lock.log c.dat)
assert_server_lock "$reponame" "$id" "refs/heads/other"
git checkout main
git lfs unlock --id="$id" 2>&1 | tee unlock.log
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to fail"
exit 1
fi
assert_server_lock "$reponame" "$id" "refs/heads/other"
grep 'Expected ref "refs/heads/other", got "refs/heads/main"' unlock.log
)
end_test
begin_test "unlock multiple files"
(
set -e
reponame="unlock-multiple-files"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "a" > a.dat
echo "b" > b.dat
git add .gitattributes a.dat b.dat
git commit -m "add dat files"
git push origin main:other
git lfs lock a.dat
git lfs lock b.dat
git lfs unlock *.dat >log 2>&1
grep "Exactly one of --id or a set of paths must be provided" log && exit 1
true
)
end_test
begin_test "unlock multiple files (JSON)"
(
set -e
reponame="unlock-multiple-files-json"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "a" > a.dat
echo "b" > b.dat
git add .gitattributes a.dat b.dat
git commit -m "add dat files"
git push origin main:other
git lfs lock a.dat
git lfs lock b.dat
git lfs unlock --json *.dat | tee lock.json
grep -F '[{"path":"a.dat","unlocked":true},{"path":"b.dat","unlocked":true}]' lock.json
)
end_test
begin_test "unlocking a file makes it readonly"
(
set -e
reponame="unlock_set_readonly"
setup_repo "$reponame" "c.dat"
git lfs lock --json "c.dat"
assert_file_writeable c.dat
git lfs unlock "c.dat"
refute_file_writeable c.dat
)
end_test
begin_test "unlocking a file ignores readonly"
(
set -e
reponame="unlock_set_readonly_ignore"
setup_repo "$reponame" "c.dat"
git lfs lock --json "c.dat"
assert_file_writeable c.dat
git -c lfs.setlockablereadonly=false lfs unlock "c.dat"
assert_file_writeable c.dat
)
end_test
begin_test "unlocking lock removed file"
(
set -e
reponame="unlock-removed-file"
setup_repo "$reponame" "a.dat"
git lfs lock --json "a.dat" | tee lock.log
id=$(assert_lock lock.log a.dat)
assert_server_lock "$reponame" "$id"
git rm a.dat
git commit -m "a.dat"
rm *.log *.json # ensure clean git status
git status
git lfs unlock --force "a.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking nonexistent file"
(
set -e
reponame="unlock-nonexistent-file"
setup_repo "$reponame" "a.dat"
git lfs lock --json "b.dat" | tee lock.log
id=$(assert_lock lock.log b.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock --force "b.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking unlockable file"
(
set -e
reponame="unlock-unlockable-file"
# Try with lockable patterns.
setup_repo "$reponame" "a.dat"
touch README.md
git add README.md
git commit -m 'Add README'
git lfs lock --json "README.md" | tee lock.log
id=$(assert_lock lock.log README.md)
assert_server_lock "$reponame" "$id"
assert_file_writeable "README.md"
git lfs unlock --force "README.md" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
assert_file_writeable "README.md"
cd "$TRASHDIR"
# Try without any lockable patterns.
setup_remote_repo_with_file "$reponame-2" "a.dat"
touch README.md
git add README.md
git commit -m 'Add README'
git lfs lock --json "README.md" | tee lock.log
id=$(assert_lock lock.log README.md)
assert_server_lock "$reponame-2" "$id"
assert_file_writeable "README.md"
git lfs unlock --force "README.md" 2>&1 | tee unlock.log
refute_server_lock "$reponame-2" "$id"
assert_file_writeable "README.md"
)
end_test
begin_test "unlocking a lock (--json)"
(
set -e
reponame="unlock_by_path_json"
setup_repo "$reponame" "c_json.dat"
git lfs lock --json "c_json.dat" | tee lock.log
id=$(assert_lock lock.log c_json.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock --json "c_json.dat" 2>&1 | tee unlock.log
grep "\"unlocked\":true" unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock by id"
(
set -e
reponame="unlock_by_id"
setup_repo "$reponame" "d.dat"
git lfs lock --json "d.dat" | tee lock.log
assert_file_writeable d.dat
id=$(assert_lock lock.log d.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock --id="$id"
refute_file_writeable d.dat
)
end_test
begin_test "unlocking a lock by id (--json)"
(
set -e
reponame="unlock_by_id_json"
setup_repo "$reponame" "c_json.dat"
git lfs lock --json "c_json.dat" | tee lock.log
id=$(assert_lock lock.log c_json.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock --json --id="$id" 2>&1 | tee unlock.log
grep "\"unlocked\":true" unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock without sufficient info"
(
set -e
reponame="unlock_ambiguous"
setup_repo "$reponame" "e.dat"
git lfs lock --json "e.dat" | tee lock.log
id=$(assert_lock lock.log e.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock 2>&1 | tee unlock.log
grep "Exactly one of --id or a set of paths must be provided" unlock.log
assert_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock while uncommitted"
(
set -e
reponame="unlock_modified"
setup_repo "$reponame" "mod.dat"
git lfs lock --json "mod.dat" | tee lock.log
id=$(assert_lock lock.log mod.dat)
assert_server_lock "$reponame" "$id"
echo "\nSomething" >> mod.dat
git lfs unlock "mod.dat" 2>&1 | tee unlock.log
[ ${PIPESTATUS[0]} -ne "0" ]
grep "Cannot unlock file with uncommitted changes" unlock.log
assert_server_lock "$reponame" "$id"
# should allow after discard
git checkout mod.dat
git lfs unlock "mod.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock with ambiguous arguments"
(
set -e
reponame="unlock_ambiguous_args"
setup_repo "$reponame" "a.dat"
git lfs lock --json "a.dat" | tee lock.log
id=$(assert_lock lock.log a.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock --id "$id" a.dat 2>&1 | tee unlock.log
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
echo >&2 "expected ambiguous \`git lfs unlock\` command to exit, didn't"
exit 1
fi
grep "Exactly one of --id or a set of paths must be provided" unlock.log
assert_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock while uncommitted with --force"
(
set -e
reponame="unlock_modified_force"
setup_repo "$reponame" "modforce.dat"
git lfs lock --json "modforce.dat" | tee lock.log
id=$(assert_lock lock.log modforce.dat)
assert_server_lock "$reponame" "$id"
echo "\nSomething" >> modforce.dat
# should allow with --force
git lfs unlock --force "modforce.dat" 2>&1 | tee unlock.log
grep "warning: unlocking with uncommitted changes" unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking a lock while untracked"
(
set -e
reponame="unlock_untracked"
setup_repo "$reponame" "notrelevant.dat"
git lfs track "*.dat"
# Create file but don't add it to git
# Shouldn't be able to unlock it
echo "something" > untracked.dat
git lfs lock --json "untracked.dat" | tee lock.log
id=$(assert_lock lock.log untracked.dat)
assert_server_lock "$reponame" "$id"
git lfs unlock "untracked.dat" 2>&1 | tee unlock.log
[ ${PIPESTATUS[0]} -ne "0" ]
grep "Cannot unlock file with uncommitted changes" unlock.log
assert_server_lock "$reponame" "$id"
# should allow after add/commit
git add untracked.dat
git commit -m "Added untracked"
git lfs unlock "untracked.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlock with git-lfs-transfer"
(
set -e
setup_pure_ssh
reponame="unlock-git-lfs-transfer"
setup_remote_repo_with_file "$reponame" "f.dat"
clone_repo "$reponame" "$reponame"
sshurl=$(ssh_remote "$reponame")
git config lfs.url "$sshurl"
GIT_TRACE_PACKET=1 git lfs lock --json "f.dat" | tee lock.log
id=$(assert_lock lock.log f.dat)
assert_server_lock_ssh "$reponame" "$id" "refs/heads/main"
git lfs unlock --id "$id"
refute_server_lock_ssh "$reponame" "$id" "refs/heads/main"
)
end_test