about summary refs log tree commit diff
path: root/t/t1060-object-corruption.sh
blob: bc89371f53436dbf3427f231f560ef1b1f8683f6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/bin/sh

test_description='see how we handle various forms of corruption'
. ./test-lib.sh

# convert "1234abcd" to ".git/objects/12/34abcd"
obj_to_file() {
	echo "$(git rev-parse --git-dir)/objects/$(git rev-parse "$1" | sed 's,..,&/,')"
}

# Convert byte at offset "$2" of object "$1" into '\0'
corrupt_byte() {
	obj_file=$(obj_to_file "$1") &&
	chmod +w "$obj_file" &&
	printf '\0' | dd of="$obj_file" bs=1 seek="$2" conv=notrunc
}

test_expect_success 'setup corrupt repo' '
	git init bit-error &&
	(
		cd bit-error &&
		test_commit content &&
		corrupt_byte HEAD:content.t 10
	) &&
	git init no-bit-error &&
	(
		# distinct commit from bit-error, but containing a
		# non-corrupted version of the same blob
		cd no-bit-error &&
		test_tick &&
		test_commit content
	)
'

test_expect_success 'setup repo with missing object' '
	git init missing &&
	(
		cd missing &&
		test_commit content &&
		rm -f "$(obj_to_file HEAD:content.t)"
	)
'

test_expect_success 'setup repo with misnamed object' '
	git init misnamed &&
	(
		cd misnamed &&
		test_commit content &&
		good=$(obj_to_file HEAD:content.t) &&
		blob=$(echo corrupt | git hash-object -w --stdin) &&
		bad=$(obj_to_file $blob) &&
		rm -f "$good" &&
		mv "$bad" "$good"
	)
'

test_expect_success 'streaming a corrupt blob fails' '
	(
		cd bit-error &&
		test_must_fail git cat-file blob HEAD:content.t
	)
'

test_expect_success 'getting type of a corrupt blob fails' '
	(
		cd bit-error &&
		test_must_fail git cat-file -s HEAD:content.t
	)
'

test_expect_success 'read-tree -u detects bit-errors in blobs' '
	(
		cd bit-error &&
		rm -f content.t &&
		test_must_fail git read-tree --reset -u HEAD
	)
'

test_expect_success 'read-tree -u detects missing objects' '
	(
		cd missing &&
		rm -f content.t &&
		test_must_fail git read-tree --reset -u HEAD
	)
'

# We use --bare to make sure that the transport detects it, not the checkout
# phase.
test_expect_success 'clone --no-local --bare detects corruption' '
	test_must_fail git clone --no-local --bare bit-error corrupt-transport
'

test_expect_success 'clone --no-local --bare detects missing object' '
	test_must_fail git clone --no-local --bare missing missing-transport
'

test_expect_success 'clone --no-local --bare detects misnamed object' '
	test_must_fail git clone --no-local --bare misnamed misnamed-transport
'

# We do not expect --local to detect corruption at the transport layer,
# so we are really checking the checkout() code path.
test_expect_success 'clone --local detects corruption' '
	test_must_fail git clone --local bit-error corrupt-checkout
'

test_expect_success 'error detected during checkout leaves repo intact' '
	test_path_is_dir corrupt-checkout/.git
'

test_expect_success 'clone --local detects missing objects' '
	test_must_fail git clone --local missing missing-checkout
'

test_expect_failure 'clone --local detects misnamed objects' '
	test_must_fail git clone --local misnamed misnamed-checkout
'

test_expect_success 'fetch into corrupted repo with index-pack' '
	cp -R bit-error bit-error-cp &&
	test_when_finished "rm -rf bit-error-cp" &&
	(
		cd bit-error-cp &&
		test_must_fail git -c transfer.unpackLimit=1 \
			fetch ../no-bit-error 2>stderr &&
		test_i18ngrep ! -i collision stderr
	)
'

test_expect_success 'internal tree objects are not "missing"' '
	git init missing-empty &&
	(
		cd missing-empty &&
		empty_tree=$(git hash-object -t tree /dev/null) &&
		commit=$(echo foo | git commit-tree $empty_tree) &&
		git rev-list --objects $commit
	)
'

test_done