1#!/bin/sh
2
3test_description='git p4 tests'
4
5GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8. ./lib-git-p4.sh
9
10test_expect_success 'start p4d' '
11	start_p4d
12'
13
14test_expect_success 'add p4 files' '
15	(
16		cd "$cli" &&
17		echo file1 >file1 &&
18		p4 add file1 &&
19		p4 submit -d "file1" &&
20		echo file2 >file2 &&
21		p4 add file2 &&
22		p4 submit -d "file2"
23	)
24'
25
26test_expect_success 'basic git p4 clone' '
27	git p4 clone --dest="$git" //depot &&
28	test_when_finished cleanup_git &&
29	(
30		cd "$git" &&
31		git log --oneline >lines &&
32		test_line_count = 1 lines
33	)
34'
35
36test_expect_success 'depot typo error' '
37	test_must_fail git p4 clone --dest="$git" /depot 2>errs &&
38	grep "Depot paths must start with" errs
39'
40
41test_expect_success 'git p4 clone @all' '
42	git p4 clone --dest="$git" //depot@all &&
43	test_when_finished cleanup_git &&
44	(
45		cd "$git" &&
46		git log --oneline >lines &&
47		test_line_count = 2 lines
48	)
49'
50
51test_expect_success 'git p4 sync uninitialized repo' '
52	test_create_repo "$git" &&
53	test_when_finished cleanup_git &&
54	(
55		cd "$git" &&
56		test_must_fail git p4 sync 2>errs &&
57		test_i18ngrep "Perhaps you never did" errs
58	)
59'
60
61#
62# Create a git repo by hand.  Add a commit so that HEAD is valid.
63# Test imports a new p4 repository into a new git branch.
64#
65test_expect_success 'git p4 sync new branch' '
66	test_create_repo "$git" &&
67	test_when_finished cleanup_git &&
68	(
69		cd "$git" &&
70		test_commit head &&
71		git p4 sync --branch=refs/remotes/p4/depot //depot@all &&
72		git log --oneline p4/depot >lines &&
73		test_line_count = 2 lines
74	)
75'
76
77test_expect_success 'clone two dirs' '
78	(
79		cd "$cli" &&
80		mkdir sub1 sub2 &&
81		echo sub1/f1 >sub1/f1 &&
82		echo sub2/f2 >sub2/f2 &&
83		p4 add sub1/f1 &&
84		p4 submit -d "sub1/f1" &&
85		p4 add sub2/f2 &&
86		p4 submit -d "sub2/f2"
87	) &&
88	git p4 clone --dest="$git" //depot/sub1 //depot/sub2 &&
89	test_when_finished cleanup_git &&
90	(
91		cd "$git" &&
92		git ls-files >lines &&
93		test_line_count = 2 lines &&
94		git log --oneline p4/master >lines &&
95		test_line_count = 1 lines
96	)
97'
98
99test_expect_success 'clone two dirs, @all' '
100	(
101		cd "$cli" &&
102		echo sub1/f3 >sub1/f3 &&
103		p4 add sub1/f3 &&
104		p4 submit -d "sub1/f3"
105	) &&
106	git p4 clone --dest="$git" //depot/sub1@all //depot/sub2@all &&
107	test_when_finished cleanup_git &&
108	(
109		cd "$git" &&
110		git ls-files >lines &&
111		test_line_count = 3 lines &&
112		git log --oneline p4/master >lines &&
113		test_line_count = 3 lines
114	)
115'
116
117test_expect_success 'clone two dirs, @all, conflicting files' '
118	(
119		cd "$cli" &&
120		echo sub2/f3 >sub2/f3 &&
121		p4 add sub2/f3 &&
122		p4 submit -d "sub2/f3"
123	) &&
124	git p4 clone --dest="$git" //depot/sub1@all //depot/sub2@all &&
125	test_when_finished cleanup_git &&
126	(
127		cd "$git" &&
128		git ls-files >lines &&
129		test_line_count = 3 lines &&
130		git log --oneline p4/master >lines &&
131		test_line_count = 4 lines &&
132		echo sub2/f3 >expected &&
133		test_cmp expected f3
134	)
135'
136
137test_expect_success 'clone two dirs, each edited by submit, single git commit' '
138	(
139		cd "$cli" &&
140		echo sub1/f4 >sub1/f4 &&
141		p4 add sub1/f4 &&
142		echo sub2/f4 >sub2/f4 &&
143		p4 add sub2/f4 &&
144		p4 submit -d "sub1/f4 and sub2/f4"
145	) &&
146	git p4 clone --dest="$git" //depot/sub1@all //depot/sub2@all &&
147	test_when_finished cleanup_git &&
148	(
149		cd "$git" &&
150		git ls-files >lines &&
151		test_line_count = 4 lines &&
152		git log --oneline p4/master >lines &&
153		test_line_count = 5 lines
154	)
155'
156
157revision_ranges="2000/01/01,#head \
158		 1,2080/01/01 \
159		 2000/01/01,2080/01/01 \
160		 2000/01/01,1000 \
161		 1,1000"
162
163test_expect_success 'clone using non-numeric revision ranges' '
164	test_when_finished cleanup_git &&
165	for r in $revision_ranges
166	do
167		rm -fr "$git" &&
168		test ! -d "$git" &&
169		git p4 clone --dest="$git" //depot@$r &&
170		(
171			cd "$git" &&
172			git ls-files >lines &&
173			test_line_count = 8 lines
174		)
175	done
176'
177
178test_expect_success 'clone with date range, excluding some changes' '
179	test_when_finished cleanup_git &&
180	before=$(date +%Y/%m/%d:%H:%M:%S) &&
181	sleep 2 &&
182	(
183		cd "$cli" &&
184		:>date_range_test &&
185		p4 add date_range_test &&
186		p4 submit -d "Adding file"
187	) &&
188	git p4 clone --dest="$git" //depot@1,$before &&
189	(
190		cd "$git" &&
191		test_path_is_missing date_range_test
192	)
193'
194
195test_expect_success 'exit when p4 fails to produce marshaled output' '
196	mkdir badp4dir &&
197	test_when_finished "rm badp4dir/p4 && rmdir badp4dir" &&
198	cat >badp4dir/p4 <<-EOF &&
199	#!$SHELL_PATH
200	exit 1
201	EOF
202	chmod 755 badp4dir/p4 &&
203	(
204		PATH="$TRASH_DIRECTORY/badp4dir:$PATH" &&
205		export PATH &&
206		test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1
207	) &&
208	test_i18ngrep ! Traceback errs
209'
210
211# Hide a file from p4d, make sure we catch its complaint.  This won't fail in
212# p4 changes, files, or describe; just in p4 print.  If P4CLIENT is unset, the
213# message will include "Librarian checkout".
214test_expect_success 'exit gracefully for p4 server errors' '
215	test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" &&
216	mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden &&
217	test_when_finished cleanup_git &&
218	test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err &&
219	test_i18ngrep "Error from p4 print" err
220'
221
222test_expect_success 'clone --bare should make a bare repository' '
223	rm -rf "$git" &&
224	git p4 clone --dest="$git" --bare //depot &&
225	test_when_finished cleanup_git &&
226	(
227		cd "$git" &&
228		test_path_is_missing .git &&
229		git config --get --bool core.bare true &&
230		git rev-parse --verify refs/remotes/p4/master &&
231		git rev-parse --verify refs/remotes/p4/HEAD &&
232		git rev-parse --verify refs/heads/main &&
233		git rev-parse --verify HEAD
234	)
235'
236
237# Sleep a bit so that the top-most p4 change did not happen "now".  Then
238# import the repo and make sure that the initial import has the same time
239# as the top-most change.
240test_expect_success 'initial import time from top change time' '
241	p4change=$(p4 -G changes -m 1 //depot/... | marshal_dump change) &&
242	p4time=$(p4 -G changes -m 1 //depot/... | marshal_dump time) &&
243	sleep 3 &&
244	git p4 clone --dest="$git" //depot &&
245	test_when_finished cleanup_git &&
246	(
247		cd "$git" &&
248		gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
249		echo $p4time $gittime &&
250		test $p4time = $gittime
251	)
252'
253
254test_expect_success 'unresolvable host in P4PORT should display error' '
255	test_when_finished cleanup_git &&
256	git p4 clone --dest="$git" //depot &&
257	(
258		cd "$git" &&
259		P4PORT=nosuchhost:65537 &&
260		export P4PORT &&
261		test_expect_code 1 git p4 sync >out 2>err &&
262		grep "connect to nosuchhost" err
263	)
264'
265
266# Test following scenarios:
267#   - Without ".git/hooks/p4-pre-submit" , submit should continue
268#   - With the hook returning 0, submit should continue
269#   - With the hook returning 1, submit should abort
270test_expect_success 'run hook p4-pre-submit before submit' '
271	test_when_finished cleanup_git &&
272	git p4 clone --dest="$git" //depot &&
273	(
274		cd "$git" &&
275		echo "hello world" >hello.txt &&
276		git add hello.txt &&
277		git commit -m "add hello.txt" &&
278		git config git-p4.skipSubmitEdit true &&
279		git p4 submit --dry-run >out &&
280		grep "Would apply" out &&
281		mkdir -p .git/hooks &&
282		write_script .git/hooks/p4-pre-submit <<-\EOF &&
283		exit 0
284		EOF
285		git p4 submit --dry-run >out &&
286		grep "Would apply" out &&
287		write_script .git/hooks/p4-pre-submit <<-\EOF &&
288		exit 1
289		EOF
290		test_must_fail git p4 submit --dry-run >errs 2>&1 &&
291		! grep "Would apply" errs
292	)
293'
294
295test_expect_success 'submit from detached head' '
296	test_when_finished cleanup_git &&
297	git p4 clone --dest="$git" //depot &&
298	(
299		cd "$git" &&
300		git checkout p4/master &&
301		>detached_head_test &&
302		git add detached_head_test &&
303		git commit -m "add detached_head" &&
304		git config git-p4.skipSubmitEdit true &&
305		git p4 submit &&
306		git p4 rebase &&
307		git log p4/master | grep detached_head
308	)
309'
310
311test_expect_success 'submit from worktree' '
312	test_when_finished cleanup_git &&
313	git p4 clone --dest="$git" //depot &&
314	(
315		cd "$git" &&
316		git worktree add ../worktree-test
317	) &&
318	(
319		cd "$git/../worktree-test" &&
320		test_commit "worktree-commit" &&
321		git config git-p4.skipSubmitEdit true &&
322		git p4 submit
323	) &&
324	(
325		cd "$cli" &&
326		p4 sync &&
327		test_path_is_file worktree-commit.t
328	)
329'
330
331test_done
332