#!/bin/sh test_description='handling of promisor remote advertisement' . ./test-lib.sh if ! test_have_prereq PERL_TEST_HELPERS then skip_all='skipping promisor remote capabilities tests; Perl not available' test_done fi GIT_TEST_MULTI_PACK_INDEX=0 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0 # Setup the repository with three commits, this way HEAD is always # available and we can hide commit 1 or 2. test_expect_success 'setup: create "template" repository' ' git init template && test_commit -C template 1 && test_commit -C template 2 && test_commit -C template 3 && test-tool genrandom foo 10240 >template/foo && git -C template add foo && git -C template commit -m foo ' # A bare repo will act as a server repo with unpacked objects. test_expect_success 'setup: create bare "server" repository' ' git clone --bare --no-local template server && mv server/objects/pack/pack-* . && packfile=$(ls pack-*.pack) && git -C server unpack-objects --strict <"$packfile" ' check_missing_objects () { git -C "$1" rev-list --objects --all --missing=print > all.txt && perl -ne 'print if s/^[?]//' all.txt >missing.txt && test_line_count = "$2" missing.txt && if test "$2" -lt 2 then test "$3" = "$(cat missing.txt)" else test -f "$3" && sort <"$3" >expected_sorted && sort actual_sorted && test_cmp expected_sorted actual_sorted fi } initialize_server () { count="$1" missing_oids="$2" # Repack everything first git -C server -c repack.writebitmaps=false repack -a -d && # Remove promisor file in case they exist, useful when reinitializing rm -rf server/objects/pack/*.promisor && # Repack without the largest object and create a promisor pack on server git -C server -c repack.writebitmaps=false repack -a -d \ --filter=blob:limit=5k --filter-to="$(pwd)/pack" && promisor_file=$(ls server/objects/pack/*.pack | sed "s/\.pack/.promisor/") && >"$promisor_file" && # Check objects missing on the server check_missing_objects server "$count" "$missing_oids" } copy_to_lop () { oid_path="$(test_oid_to_path $1)" && path="server/objects/$oid_path" && path2="lop/objects/$oid_path" && mkdir -p $(dirname "$path2") && cp "$path" "$path2" } test_expect_success "setup for testing promisor remote advertisement" ' # Create another bare repo called "lop" (for Large Object Promisor) git init --bare lop && # Copy the largest object from server to lop obj="HEAD:foo" && oid="$(git -C server rev-parse $obj)" && copy_to_lop "$oid" && initialize_server 1 "$oid" && # Configure lop as promisor remote for server git -C server remote add lop "file://$(pwd)/lop" && git -C server config remote.lop.promisor true && git -C lop config uploadpack.allowFilter true && git -C lop config uploadpack.allowAnySHA1InWant true && git -C server config uploadpack.allowFilter true && git -C server config uploadpack.allowAnySHA1InWant true ' test_expect_success "clone with promisor.advertise set to 'true'" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=All \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with promisor.advertise set to 'false'" ' git -C server config promisor.advertise false && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=All \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is not missing on the server check_missing_objects server 0 "" && # Reinitialize server so that the largest object is missing again initialize_server 1 "$oid" ' test_expect_success "clone with promisor.acceptfromserver set to 'None'" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=None \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is not missing on the server check_missing_objects server 0 "" && # Reinitialize server so that the largest object is missing again initialize_server 1 "$oid" ' test_expect_success "init + fetch with promisor.advertise set to 'true'" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && mkdir client && git -C client init && git -C client config remote.lop.promisor true && git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" && git -C client config remote.lop.url "file://$(pwd)/lop" && git -C client config remote.server.url "file://$(pwd)/server" && git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" && git -C client config promisor.acceptfromserver All && GIT_NO_LAZY_FETCH=0 git -C client fetch --filter="blob:limit=5k" server && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with promisor.acceptfromserver set to 'KnownName'" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=KnownName \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with 'KnownName' and different remote names" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.serverTwo.promisor=true \ -c remote.serverTwo.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.serverTwo.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=KnownName \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is not missing on the server check_missing_objects server 0 "" && # Reinitialize server so that the largest object is missing again initialize_server 1 "$oid" ' test_expect_success "clone with 'KnownName' and missing URL in the config" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client # Lazy fetching by the client from the LOP will fail because of the # missing URL in the client config, so the server will have to lazy # fetch from the LOP. GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c promisor.acceptfromserver=KnownName \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is not missing on the server check_missing_objects server 0 "" && # Reinitialize server so that the largest object is missing again initialize_server 1 "$oid" ' test_expect_success "clone with promisor.acceptfromserver set to 'KnownUrl'" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=KnownUrl \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with 'KnownUrl' and different remote urls" ' ln -s lop serverTwo && git -C server config promisor.advertise true && test_when_finished "rm -rf client" && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/serverTwo" \ -c promisor.acceptfromserver=KnownUrl \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is not missing on the server check_missing_objects server 0 "" && # Reinitialize server so that the largest object is missing again initialize_server 1 "$oid" ' test_expect_success "clone with 'KnownUrl' and url not configured on the server" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" && git -C server config unset remote.lop.url && # Clone from server to create a client # It should fail because the client will reject the LOP as URLs are # different, and the server cannot lazy fetch as the LOP URL is # missing, so the remote name will be used instead which will fail. test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=KnownUrl \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" ' git -C server config promisor.advertise true && test_when_finished "rm -rf client" && test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" && git -C server config set remote.lop.url "" && # Clone from server to create a client # It should fail because the client will reject the LOP as an empty URL is # not advertised, and the server cannot lazy fetch as the LOP URL is empty, # so the remote name will be used instead which will fail. test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=KnownUrl \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "clone with promisor.advertise set to 'true' but don't delete the client" ' git -C server config promisor.advertise true && # Clone from server to create a client GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \ -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ -c remote.lop.url="file://$(pwd)/lop" \ -c promisor.acceptfromserver=All \ --no-local --filter="blob:limit=5k" server client && # Check that the largest object is still missing on the server check_missing_objects server 1 "$oid" ' test_expect_success "setup for subsequent fetches" ' # Generate new commit with large blob test-tool genrandom bar 10240 >template/bar && git -C template add bar && git -C template commit -m bar && # Fetch new commit with large blob git -C server fetch origin && git -C server update-ref HEAD FETCH_HEAD && git -C server rev-parse HEAD >expected_head && # Repack everything twice and remove .promisor files before # each repack. This makes sure everything gets repacked # into a single packfile. The second repack is necessary # because the first one fetches from lop and creates a new # packfile and its associated .promisor file. rm -f server/objects/pack/*.promisor && git -C server -c repack.writebitmaps=false repack -a -d && rm -f server/objects/pack/*.promisor && git -C server -c repack.writebitmaps=false repack -a -d && # Unpack everything rm pack-* && mv server/objects/pack/pack-* . && packfile=$(ls pack-*.pack) && git -C server unpack-objects --strict <"$packfile" && # Copy new large object to lop obj_bar="HEAD:bar" && oid_bar="$(git -C server rev-parse $obj_bar)" && copy_to_lop "$oid_bar" && # Reinitialize server so that the 2 largest objects are missing printf "%s\n" "$oid" "$oid_bar" >expected_missing.txt && initialize_server 2 expected_missing.txt && # Create one more client cp -r client client2 ' test_expect_success "subsequent fetch from a client when promisor.advertise is true" ' git -C server config promisor.advertise true && GIT_NO_LAZY_FETCH=0 git -C client pull origin && git -C client rev-parse HEAD >actual && test_cmp expected_head actual && cat client/bar >/dev/null && check_missing_objects server 2 expected_missing.txt ' test_expect_success "subsequent fetch from a client when promisor.advertise is false" ' git -C server config promisor.advertise false && GIT_NO_LAZY_FETCH=0 git -C client2 pull origin && git -C client2 rev-parse HEAD >actual && test_cmp expected_head actual && cat client2/bar >/dev/null && check_missing_objects server 1 "$oid" ' test_done