(command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:test_description) op: assign_op.Equal rhs: {(SQ <'test fetching over git protocol'>)} spids: [4] ) ] ) (C {<.>} {<'./test-lib.sh'>}) (C {<.>} {(DQ ($ Id.VSub_DollarName '$TEST_DIRECTORY')) <'/lib-git-daemon.sh'>}) (C {<start_git_daemon>}) (command.ShFunction name: check_verbose_connect body: (BraceGroup children: [ (command.AndOr ops: [Id.Op_DAmp Id.Op_DAmp] children: [ (C {<grep>} {<-F>} {(DQ <'Looking up 127.0.0.1 ...'>)} {<stderr>}) (C {<grep>} {<-F>} {(DQ <'Connecting to 127.0.0.1 (port '>)} {<stderr>}) (C {<grep>} {<-F>} {(DQ <done.>)} {<stderr>}) ] ) ] ) ) (C {<test_expect_success>} {(SQ <'setup repository'>)} { (SQ <'\n'> <'\tgit config push.default matching &&\n'> <'\techo content >file &&\n'> <'\tgit add file &&\n'> <'\tgit commit -m one\n'> ) } ) (C {<test_expect_success>} {(SQ <'create git-accessible bare repository'>)} { (SQ <'\n'> <'\tmkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&\n'> <'\t(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&\n'> <'\t git --bare init &&\n'> <'\t : >git-daemon-export-ok\n'> <'\t) &&\n'> <'\tgit remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&\n'> <'\tgit push public master:master\n'> ) } ) (C {<test_expect_success>} {(SQ <'clone git repository'>)} { (SQ <'\n'> <'\tgit clone -v "$GIT_DAEMON_URL/repo.git" clone 2>stderr &&\n'> <'\tcheck_verbose_connect &&\n'> <'\ttest_cmp file clone/file\n'> ) } ) (C {<test_expect_success>} {(SQ <'fetch changes via git protocol'>)} { (SQ <'\n'> <'\techo content >>file &&\n'> <'\tgit commit -a -m two &&\n'> <'\tgit push public &&\n'> <'\t(cd clone && git pull -v) 2>stderr &&\n'> <'\tcheck_verbose_connect &&\n'> <'\ttest_cmp file clone/file\n'> ) } ) (C {<test_expect_success>} {(SQ <'no-op fetch -v stderr is as expected'>)} {(SQ <'\n'> <'\t(cd clone && git fetch -v) 2>stderr &&\n'> <'\tcheck_verbose_connect\n'>)} ) (C {<test_expect_success>} {(SQ <'no-op fetch without "-v" is quiet'>)} {(SQ <'\n'> <'\t(cd clone && git fetch) 2>stderr &&\n'> <'\t! test -s stderr\n'>)} ) (C {<test_expect_success>} {(SQ <'remote detects correct HEAD'>)} { (SQ <'\n'> <'\tgit push public master:other &&\n'> <'\t(cd clone &&\n'> <'\t git remote set-head -d origin &&\n'> <'\t git remote set-head -a origin &&\n'> <'\t git symbolic-ref refs/remotes/origin/HEAD > output &&\n'> <'\t echo refs/remotes/origin/master > expect &&\n'> <'\t test_cmp expect output\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'prepare pack objects'>)} { (SQ <'\n'> < '\tcp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&\n' > <'\t(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git &&\n'> <'\t git --bare repack -a -d\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'fetch notices corrupt pack'>)} { (SQ <'\n'> < '\tcp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&\n' > <'\t(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git &&\n'> <'\t p=$(ls objects/pack/pack-*.pack) &&\n'> <'\t chmod u+w $p &&\n'> <'\t printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc\n'> <'\t) &&\n'> <'\tmkdir repo_bad1.git &&\n'> <'\t(cd repo_bad1.git &&\n'> <'\t git --bare init &&\n'> <'\t test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" &&\n'> <'\t test 0 = $(ls objects/pack/pack-*.pack | wc -l)\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'fetch notices corrupt idx'>)} { (SQ <'\n'> < '\tcp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&\n' > <'\t(cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git &&\n'> <'\t p=$(ls objects/pack/pack-*.idx) &&\n'> <'\t chmod u+w $p &&\n'> <'\t printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc\n'> <'\t) &&\n'> <'\tmkdir repo_bad2.git &&\n'> <'\t(cd repo_bad2.git &&\n'> <'\t git --bare init &&\n'> <'\t test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" &&\n'> <'\t test 0 = $(ls objects/pack | wc -l)\n'> <'\t)\n'> ) } ) (command.ShFunction name: test_remote_error body: (BraceGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:do_export) op: assign_op.Equal rhs: {<YesPlease>} spids: [248] ) ] ) (command.WhileUntil keyword: <Id.KW_While while> cond: [(C {<test>} {($ Id.VSub_Pound '$#')} {<-gt>} {<0>})] body: (command.DoGroup children: [ (command.Case to_match: {($ Id.VSub_Number '$1')} arms: [ (case_arm pat_list: [{<-x>}] action: [ (C {<shift>}) (C {<chmod>} {<-x>} { (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/repo.git'> ) } ) ] spids: [273 274 290 -1] ) (case_arm pat_list: [{<-n>}] action: [ (C {<shift>}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:do_export) op: assign_op.Equal rhs: (word.Empty) spids: [300] ) ] ) ] spids: [293 294 303 -1] ) (case_arm pat_list: [{<Id.Lit_Star '*'>}] action: [(command.ControlFlow token:<Id.ControlFlow_Break break>)] spids: [306 307 -1 313] ) ] ) ] ) ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:msg) op: assign_op.Equal rhs: {($ Id.VSub_Number '$1')} spids: [320] ) ] ) (C {<shift>}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:cmd) op: assign_op.Equal rhs: {($ Id.VSub_Number '$1')} spids: [327] ) ] ) (C {<shift>}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:repo) op: assign_op.Equal rhs: {($ Id.VSub_Number '$1')} spids: [334] ) ] ) (command.AndOr ops: [Id.Op_DPipe] children: [(C {<shift>}) (C {<error>} {(DQ <'invalid number of arguments'>)})] ) (command.If arms: [ (if_arm cond: [ (C {<test>} {<-x>} { (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/'> ($ Id.VSub_DollarName '$repo') ) } ) ] action: [ (command.If arms: [ (if_arm cond: [(C {<test>} {<-n>} {(DQ ($ Id.VSub_DollarName '$do_export'))})] action: [ (command.Simple words: [{<Id.Lit_Colon ':'>}] redirects: [ (redir op: <Id.Redir_Great '>'> loc: (redir_loc.Fd fd:1) arg: { (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/'> ($ Id.VSub_DollarName '$repo') <'/git-daemon-export-ok'> ) } ) ] do_fork: T ) ] spids: [366 377] ) ] else_action: [ (C {<rm>} {<-f>} { (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/'> ($ Id.VSub_DollarName '$repo') <'/git-daemon-export-ok'> ) } ) ] ) ] spids: [350 363] ) ] ) (command.AndOr ops: [Id.Op_DAmp Id.Op_DAmp] children: [ (command.Simple words: [ {<test_must_fail>} {<git>} {(DQ ($ Id.VSub_DollarName '$cmd'))} { (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_URL') <'/'> ($ Id.VSub_DollarName '$repo')) } {(DQ ($ Id.VSub_At '$@'))} ] redirects: [(redir op:<Id.Redir_Great '2>'> loc:(redir_loc.Fd fd:2) arg:{<output>})] do_fork: T ) (C {<test_i18ngrep>} { (DQ <'fatal: remote error: '> ($ Id.VSub_DollarName '$msg') <': /'> ($ Id.VSub_DollarName '$repo') ) } {<output>} ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:ret) op: assign_op.Equal rhs: {($ Id.VSub_QMark '$?')} spids: [451] ) ] ) ] ) (C {<chmod>} {<Id.Lit_Other '+'> <x>} {(DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/repo.git'>)} ) (command.Subshell child: (command.ControlFlow token: <Id.ControlFlow_Exit exit> arg_word: {($ Id.VSub_DollarName '$ret')} ) ) ] ) ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:msg) op: assign_op.Equal rhs: {(DQ <'access denied or repository not exported'>)} spids: [475] ) ] ) (C {<test_expect_success>} {(SQ <'clone non-existent'>)} {(DQ <'test_remote_error \''> ($ Id.VSub_DollarName '$msg') <'\' clone nowhere.git '>)} ) (C {<test_expect_success>} {(SQ <'push disabled'>)} {(DQ <'test_remote_error \''> ($ Id.VSub_DollarName '$msg') <'\' push repo.git master'>)} ) (C {<test_expect_success>} {(SQ <'read access denied'>)} {(DQ <'test_remote_error -x \''> ($ Id.VSub_DollarName '$msg') <'\' fetch repo.git '>)} ) (C {<test_expect_success>} {(SQ <'not exported'>)} {(DQ <'test_remote_error -n \''> ($ Id.VSub_DollarName '$msg') <'\' fetch repo.git '>)} ) (C {<stop_git_daemon>}) (C {<start_git_daemon>} {<--informative-errors>}) (C {<test_expect_success>} {(SQ <'clone non-existent'>)} {(DQ <'test_remote_error \'no such repository\' clone nowhere.git '>)} ) (C {<test_expect_success>} {(SQ <'push disabled'>)} {(DQ <'test_remote_error \'service not enabled\' push repo.git master'>)} ) (C {<test_expect_success>} {(SQ <'read access denied'>)} {(DQ <'test_remote_error -x \'no such repository\' fetch repo.git '>)} ) (C {<test_expect_success>} {(SQ <'not exported'>)} {(DQ <'test_remote_error -n \'repository not exported\' fetch repo.git '>)} ) (C {<stop_git_daemon>}) (C {<start_git_daemon>} {<--interpolated-path> <Id.Lit_Equals '='> (DQ ($ Id.VSub_DollarName '$GIT_DAEMON_DOCUMENT_ROOT_PATH') <'/%H%D'>) } ) (C {<test_expect_success>} {(SQ <'access repo via interpolated hostname'>)} { (SQ <'\n'> <'\trepo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/localhost/interp.git" &&\n'> <'\tgit init --bare "$repo" &&\n'> <'\tgit push "$repo" HEAD &&\n'> <'\t>"$repo"/git-daemon-export-ok &&\n'> <'\trm -rf tmp.git &&\n'> <'\tGIT_OVERRIDE_VIRTUAL_HOST=localhost \\\n'> <'\t\tgit clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git &&\n'> <'\trm -rf tmp.git &&\n'> <'\tGIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \\\n'> <'\t\tgit clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git\n'> ) } ) (C {<test_expect_success>} {(SQ <'hostname cannot break out of directory'>)} { (SQ <'\n'> <'\trm -rf tmp.git &&\n'> <'\trepo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" &&\n'> <'\tgit init --bare "$repo" &&\n'> <'\tgit push "$repo" HEAD &&\n'> <'\t>"$repo"/git-daemon-export-ok &&\n'> <'\ttest_must_fail \\\n'> <'\t\tenv GIT_OVERRIDE_VIRTUAL_HOST=.. \\\n'> <'\t\tgit clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git\n'> ) } ) (C {<stop_git_daemon>}) (C {<test_done>}) ] )