Git fork
at reftables-rust 507 lines 15 kB view raw
1#!/bin/sh 2# 3# Copyright (c) 2020 Jiang Xin 4# 5test_description='Test git push porcelain output' 6 7. ./test-lib.sh 8 9# Create commits in <repo> and assign each commit's oid to shell variables 10# given in the arguments (A, B, and C). E.g.: 11# 12# create_commits_in <repo> A B C 13# 14# NOTE: Never calling this function from a subshell since variable 15# assignments will disappear when subshell exits. 16create_commits_in () { 17 repo="$1" && test -d "$repo" || 18 error "Repository $repo does not exist." 19 shift && 20 while test $# -gt 0 21 do 22 name=$1 && 23 shift && 24 test_commit -C "$repo" --no-tag "$name" && 25 eval $name=$(git -C "$repo" rev-parse HEAD) 26 done 27} 28 29get_abbrev_oid () { 30 oid=$1 && 31 suffix=${oid#???????} && 32 oid=${oid%$suffix} && 33 if test -n "$oid" 34 then 35 echo "$oid" 36 else 37 echo "undefined-oid" 38 fi 39} 40 41# Format the output of git-push, git-show-ref and other commands to make a 42# user-friendly and stable text. We can easily prepare the expect text 43# without having to worry about future changes of the commit ID and spaces 44# of the output. 45make_user_friendly_and_stable_output () { 46 sed \ 47 -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \ 48 -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \ 49 -e "s/$ZERO_OID/<ZERO-OID>/g" \ 50 -e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#" 51} 52 53format_and_save_expect () { 54 sed -e 's/^> //' -e 's/Z$//' >expect 55} 56 57create_upstream_template () { 58 git init --bare upstream-template.git && 59 git clone upstream-template.git tmp_work_dir && 60 create_commits_in tmp_work_dir A B && 61 ( 62 cd tmp_work_dir && 63 git push origin \ 64 $B:refs/heads/main \ 65 $A:refs/heads/foo \ 66 $A:refs/heads/bar \ 67 $A:refs/heads/baz 68 ) && 69 rm -rf tmp_work_dir 70} 71 72setup_upstream () { 73 if test $# -ne 1 74 then 75 BUG "location of upstream repository is not provided" 76 fi && 77 rm -rf "$1" && 78 if ! test -d upstream-template.git 79 then 80 create_upstream_template 81 fi && 82 git clone --mirror upstream-template.git "$1" && 83 # The upstream repository provides services using the HTTP protocol. 84 if ! test "$1" = "upstream.git" 85 then 86 git -C "$1" config http.receivepack true 87 fi 88} 89 90setup_upstream_and_workbench () { 91 if test $# -ne 1 92 then 93 BUG "location of upstream repository is not provided" 94 fi 95 upstream="$1" 96 97 # Upstream after setup: main(B) foo(A) bar(A) baz(A) 98 # Workbench after setup: main(A) baz(A) next(A) 99 test_expect_success "setup upstream repository and workbench" ' 100 setup_upstream "$upstream" && 101 rm -rf workbench && 102 git clone "$upstream" workbench && 103 ( 104 cd workbench && 105 git update-ref refs/heads/main $A && 106 git update-ref refs/heads/baz $A && 107 git update-ref refs/heads/next $A && 108 # Try to make a stable fixed width for abbreviated commit ID, 109 # this fixed-width oid will be replaced with "<OID>". 110 git config core.abbrev 7 && 111 git config advice.pushUpdateRejected false 112 ) && 113 # The upstream repository provides services using the HTTP protocol. 114 if ! test "$upstream" = "upstream.git" 115 then 116 git -C workbench remote set-url origin "$HTTPD_URL/smart/upstream.git" 117 fi 118 ' 119} 120 121run_git_push_porcelain_output_test() { 122 case $1 in 123 http) 124 PROTOCOL="HTTP protocol" 125 URL_PREFIX="http://.*" 126 ;; 127 file) 128 PROTOCOL="builtin protocol" 129 URL_PREFIX=".*" 130 ;; 131 esac 132 133 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 134 # Refs of workbench: main(A) baz(A) next(A) 135 # git-push : main(A) NULL (B) baz(A) next(A) 136 test_expect_success ".. git-push --porcelain ($PROTOCOL)" ' 137 test_when_finished "setup_upstream \"$upstream\"" && 138 test_must_fail git -C workbench push --porcelain origin \ 139 main \ 140 :refs/heads/foo \ 141 $B:bar \ 142 baz \ 143 next >out && 144 make_user_friendly_and_stable_output <out >actual && 145 format_and_save_expect <<-\EOF && 146 > To <URL/of/upstream.git> 147 > = refs/heads/baz:refs/heads/baz [up to date] 148 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 149 > - :refs/heads/foo [deleted] 150 > * refs/heads/next:refs/heads/next [new branch] 151 > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 152 > Done 153 EOF 154 test_cmp expect actual && 155 156 git -C "$upstream" show-ref >out && 157 make_user_friendly_and_stable_output <out >actual && 158 cat >expect <<-EOF && 159 <COMMIT-B> refs/heads/bar 160 <COMMIT-A> refs/heads/baz 161 <COMMIT-B> refs/heads/main 162 <COMMIT-A> refs/heads/next 163 EOF 164 test_cmp expect actual 165 ' 166 167 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 168 # Refs of workbench: main(A) baz(A) next(A) 169 # git-push : main(A) NULL (B) baz(A) next(A) 170 test_expect_success ".. git-push --porcelain --force ($PROTOCOL)" ' 171 test_when_finished "setup_upstream \"$upstream\"" && 172 git -C workbench push --porcelain --force origin \ 173 main \ 174 :refs/heads/foo \ 175 $B:bar \ 176 baz \ 177 next >out && 178 make_user_friendly_and_stable_output <out >actual && 179 format_and_save_expect <<-EOF && 180 > To <URL/of/upstream.git> 181 > = refs/heads/baz:refs/heads/baz [up to date] 182 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 183 > - :refs/heads/foo [deleted] 184 > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 185 > * refs/heads/next:refs/heads/next [new branch] 186 > Done 187 EOF 188 test_cmp expect actual && 189 190 git -C "$upstream" show-ref >out && 191 make_user_friendly_and_stable_output <out >actual && 192 cat >expect <<-EOF && 193 <COMMIT-B> refs/heads/bar 194 <COMMIT-A> refs/heads/baz 195 <COMMIT-A> refs/heads/main 196 <COMMIT-A> refs/heads/next 197 EOF 198 test_cmp expect actual 199 ' 200 201 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 202 # Refs of workbench: main(A) baz(A) next(A) 203 # git-push : main(A) NULL (B) baz(A) next(A) 204 test_expect_success ".. git push --porcelain --atomic ($PROTOCOL)" ' 205 test_when_finished "setup_upstream \"$upstream\"" && 206 test_must_fail git -C workbench push --porcelain --atomic origin \ 207 main \ 208 :refs/heads/foo \ 209 $B:bar \ 210 baz \ 211 next >out && 212 make_user_friendly_and_stable_output <out >actual && 213 format_and_save_expect <<-EOF && 214 > To <URL/of/upstream.git> 215 > = refs/heads/baz:refs/heads/baz [up to date] 216 > ! <COMMIT-B>:refs/heads/bar [rejected] (atomic push failed) 217 > ! (delete):refs/heads/foo [rejected] (atomic push failed) 218 > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 219 > ! refs/heads/next:refs/heads/next [rejected] (atomic push failed) 220 > Done 221 EOF 222 test_cmp expect actual && 223 224 git -C "$upstream" show-ref >out && 225 make_user_friendly_and_stable_output <out >actual && 226 cat >expect <<-EOF && 227 <COMMIT-A> refs/heads/bar 228 <COMMIT-A> refs/heads/baz 229 <COMMIT-A> refs/heads/foo 230 <COMMIT-B> refs/heads/main 231 EOF 232 test_cmp expect actual 233 ' 234 235 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 236 # Refs of workbench: main(A) baz(A) next(A) 237 # git-push : main(A) NULL (B) baz(A) next(A) 238 test_expect_success ".. pre-receive hook declined ($PROTOCOL)" ' 239 test_when_finished "rm -f \"$upstream/hooks/pre-receive\" && 240 setup_upstream \"$upstream\"" && 241 test_hook --setup -C "$upstream" pre-receive <<-EOF && 242 exit 1 243 EOF 244 test_must_fail git -C workbench push --porcelain --force origin \ 245 main \ 246 :refs/heads/foo \ 247 $B:bar \ 248 baz \ 249 next >out && 250 make_user_friendly_and_stable_output <out >actual && 251 format_and_save_expect <<-EOF && 252 > To <URL/of/upstream.git> 253 > = refs/heads/baz:refs/heads/baz [up to date] 254 > ! <COMMIT-B>:refs/heads/bar [remote rejected] (pre-receive hook declined) 255 > ! :refs/heads/foo [remote rejected] (pre-receive hook declined) 256 > ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined) 257 > ! refs/heads/next:refs/heads/next [remote rejected] (pre-receive hook declined) 258 > Done 259 EOF 260 test_cmp expect actual && 261 262 git -C "$upstream" show-ref >out && 263 make_user_friendly_and_stable_output <out >actual && 264 cat >expect <<-EOF && 265 <COMMIT-A> refs/heads/bar 266 <COMMIT-A> refs/heads/baz 267 <COMMIT-A> refs/heads/foo 268 <COMMIT-B> refs/heads/main 269 EOF 270 test_cmp expect actual 271 ' 272 273 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 274 # Refs of workbench: main(A) baz(A) next(A) 275 # git-push : main(A) next(A) 276 test_expect_success ".. non-fastforward push ($PROTOCOL)" ' 277 test_when_finished "setup_upstream \"$upstream\"" && 278 ( 279 cd workbench && 280 test_must_fail git push --porcelain origin \ 281 main \ 282 next 283 ) >out && 284 make_user_friendly_and_stable_output <out >actual && 285 format_and_save_expect <<-EOF && 286 > To <URL/of/upstream.git> 287 > * refs/heads/next:refs/heads/next [new branch] 288 > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 289 > Done 290 EOF 291 test_cmp expect actual && 292 293 git -C "$upstream" show-ref >out && 294 make_user_friendly_and_stable_output <out >actual && 295 cat >expect <<-EOF && 296 <COMMIT-A> refs/heads/bar 297 <COMMIT-A> refs/heads/baz 298 <COMMIT-A> refs/heads/foo 299 <COMMIT-B> refs/heads/main 300 <COMMIT-A> refs/heads/next 301 EOF 302 test_cmp expect actual 303 ' 304 305 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 306 # Refs of workbench: main(A) baz(A) next(A) 307 # git-push : main(A) NULL (B) baz(A) next(A) 308 test_expect_success ".. git push --porcelain --atomic --force ($PROTOCOL)" ' 309 git -C workbench push --porcelain --atomic --force origin \ 310 main \ 311 :refs/heads/foo \ 312 $B:bar \ 313 baz \ 314 next >out && 315 make_user_friendly_and_stable_output <out >actual && 316 format_and_save_expect <<-\EOF && 317 > To <URL/of/upstream.git> 318 > = refs/heads/baz:refs/heads/baz [up to date] 319 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 320 > - :refs/heads/foo [deleted] 321 > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 322 > * refs/heads/next:refs/heads/next [new branch] 323 > Done 324 EOF 325 test_cmp expect actual && 326 327 git -C "$upstream" show-ref >out && 328 make_user_friendly_and_stable_output <out >actual && 329 cat >expect <<-EOF && 330 <COMMIT-B> refs/heads/bar 331 <COMMIT-A> refs/heads/baz 332 <COMMIT-A> refs/heads/main 333 <COMMIT-A> refs/heads/next 334 EOF 335 test_cmp expect actual 336 ' 337} 338 339run_git_push_dry_run_porcelain_output_test() { 340 case $1 in 341 http) 342 PROTOCOL="HTTP protocol" 343 URL_PREFIX="http://.*" 344 ;; 345 file) 346 PROTOCOL="builtin protocol" 347 URL_PREFIX=".*" 348 ;; 349 esac 350 351 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 352 # Refs of workbench: main(A) baz(A) next(A) 353 # git-push : main(A) NULL (B) baz(A) next(A) 354 test_expect_success ".. git-push --porcelain --dry-run ($PROTOCOL)" ' 355 test_must_fail git -C workbench push --porcelain --dry-run origin \ 356 main \ 357 :refs/heads/foo \ 358 $B:bar \ 359 baz \ 360 next >out && 361 make_user_friendly_and_stable_output <out >actual && 362 format_and_save_expect <<-EOF && 363 > To <URL/of/upstream.git> 364 > = refs/heads/baz:refs/heads/baz [up to date] 365 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 366 > - :refs/heads/foo [deleted] 367 > * refs/heads/next:refs/heads/next [new branch] 368 > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 369 > Done 370 EOF 371 test_cmp expect actual && 372 373 git -C "$upstream" show-ref >out && 374 make_user_friendly_and_stable_output <out >actual && 375 cat >expect <<-EOF && 376 <COMMIT-A> refs/heads/bar 377 <COMMIT-A> refs/heads/baz 378 <COMMIT-A> refs/heads/foo 379 <COMMIT-B> refs/heads/main 380 EOF 381 test_cmp expect actual 382 ' 383 384 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 385 # Refs of workbench: main(A) baz(A) next(A) 386 # push : main(A) NULL (B) baz(A) next(A) 387 test_expect_success ".. git-push --porcelain --dry-run --force ($PROTOCOL)" ' 388 git -C workbench push --porcelain --dry-run --force origin \ 389 main \ 390 :refs/heads/foo \ 391 $B:bar \ 392 baz \ 393 next >out && 394 make_user_friendly_and_stable_output <out >actual && 395 format_and_save_expect <<-EOF && 396 > To <URL/of/upstream.git> 397 > = refs/heads/baz:refs/heads/baz [up to date] 398 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 399 > - :refs/heads/foo [deleted] 400 > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 401 > * refs/heads/next:refs/heads/next [new branch] 402 > Done 403 EOF 404 test_cmp expect actual && 405 406 git -C "$upstream" show-ref >out && 407 make_user_friendly_and_stable_output <out >actual && 408 cat >expect <<-EOF && 409 <COMMIT-A> refs/heads/bar 410 <COMMIT-A> refs/heads/baz 411 <COMMIT-A> refs/heads/foo 412 <COMMIT-B> refs/heads/main 413 EOF 414 test_cmp expect actual 415 ' 416 417 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 418 # Refs of workbench: main(A) baz(A) next(A) 419 # git-push : main(A) NULL (B) baz(A) next(A) 420 test_expect_success ".. git-push --porcelain --dry-run --atomic ($PROTOCOL)" ' 421 test_must_fail git -C workbench push --porcelain --dry-run --atomic origin \ 422 main \ 423 :refs/heads/foo \ 424 $B:bar \ 425 baz \ 426 next >out && 427 make_user_friendly_and_stable_output <out >actual && 428 format_and_save_expect <<-EOF && 429 > To <URL/of/upstream.git> 430 > = refs/heads/baz:refs/heads/baz [up to date] 431 > ! <COMMIT-B>:refs/heads/bar [rejected] (atomic push failed) 432 > ! (delete):refs/heads/foo [rejected] (atomic push failed) 433 > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 434 > ! refs/heads/next:refs/heads/next [rejected] (atomic push failed) 435 > Done 436 EOF 437 test_cmp expect actual && 438 439 git -C "$upstream" show-ref >out && 440 make_user_friendly_and_stable_output <out >actual && 441 cat >expect <<-EOF && 442 <COMMIT-A> refs/heads/bar 443 <COMMIT-A> refs/heads/baz 444 <COMMIT-A> refs/heads/foo 445 <COMMIT-B> refs/heads/main 446 EOF 447 test_cmp expect actual 448 ' 449 450 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 451 # Refs of workbench: main(A) baz(A) next(A) 452 # push : main(A) NULL (B) baz(A) next(A) 453 test_expect_success ".. git-push --porcelain --dry-run --atomic --force ($PROTOCOL)" ' 454 git -C workbench push --porcelain --dry-run --atomic --force origin \ 455 main \ 456 :refs/heads/foo \ 457 $B:bar \ 458 baz \ 459 next >out && 460 make_user_friendly_and_stable_output <out >actual && 461 format_and_save_expect <<-EOF && 462 > To <URL/of/upstream.git> 463 > = refs/heads/baz:refs/heads/baz [up to date] 464 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 465 > - :refs/heads/foo [deleted] 466 > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 467 > * refs/heads/next:refs/heads/next [new branch] 468 > Done 469 EOF 470 test_cmp expect actual && 471 472 git -C "$upstream" show-ref >out && 473 make_user_friendly_and_stable_output <out >actual && 474 cat >expect <<-EOF && 475 <COMMIT-A> refs/heads/bar 476 <COMMIT-A> refs/heads/baz 477 <COMMIT-A> refs/heads/foo 478 <COMMIT-B> refs/heads/main 479 EOF 480 test_cmp expect actual 481 ' 482} 483 484setup_upstream_and_workbench upstream.git 485 486run_git_push_porcelain_output_test file 487 488setup_upstream_and_workbench upstream.git 489 490run_git_push_dry_run_porcelain_output_test file 491 492ROOT_PATH="$PWD" 493. "$TEST_DIRECTORY"/lib-gpg.sh 494. "$TEST_DIRECTORY"/lib-httpd.sh 495. "$TEST_DIRECTORY"/lib-terminal.sh 496start_httpd 497setup_askpass_helper 498 499setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" 500 501run_git_push_porcelain_output_test http 502 503setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" 504 505run_git_push_dry_run_porcelain_output_test http 506 507test_done