acst

Tracks changes and corruption in files using xattr-based checksums.
git clone https://noxz.tech/git/acst.git
acst

test
1#!/bin/sh
2
3set -eu
4
5PRG="acst"
6
7cleanup() {
8	_RES=$?
9	[ $_RES -ne 0 ] && echo "\033[5;31m*** FAILED WITH CODE $_RES ***\033[0m"
10
11	cd ..
12	rm -rf "$TMPFILE"
13}
14
15fattr() {
16	if [ "$1" = "set" ] && command -v getfattr > /dev/null 2>&1; then
17		setfattr -n "$2" -v "$3" "$4"
18	elif [ "$1" = "get" ] && command -v getfattr > /dev/null 2>&1; then
19		getfattr -n "$2" "$3" -e hex
20	else
21		exit 1
22	fi
23}
24
25get_cs() {
26	fattr "get" "user.acst.cs" "$1"
27}
28
29set_cs() {
30	fattr "set" "user.acst.cs" "0x$1" "$2"
31}
32
33set_ts() {
34	fattr "set" "user.acst.ts" "$1" "$2"
35}
36
37TESTCNT=0
38header() {
39	printf 'test %02d: %s\n' "$((TESTCNT+=1))" "$1"
40}
41
42cd "$(dirname "$0")"
43TMPFILE="$(mktemp -d XXXXXXXXXX)" && {
44	cd "$TMPFILE"
45	trap cleanup EXIT
46
47	#########################################################################
48	header 'new empty file'
49	cat > expected <<- EOF
50	<new> object
51	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
52	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1592776800.000000000
53	EOF
54	TZ=CET touch -t 202006220000 object
55	../"${PRG}" object > output
56	diff -u expected output
57
58	echo "<ok> object" > expected
59	../"${PRG}" object > output
60	diff -u expected output
61
62	#########################################################################
63	header 'outdated file'
64	cat > expected <<- EOF
65	<outdated> object
66	 stored: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1592776800.000000000
67	 actual: 7f8b1dfc466b6249f06cbe55c9174df2578e7754da793fded244ef5cba2a38f1 1655848800.000000000
68	EOF
69	echo changed > object
70	TZ=CET touch -t 202206220000 object
71	../"${PRG}" object > output
72	diff -u expected output
73
74	#########################################################################
75	header 'touched file'
76	cat > expected <<- EOF
77	<hash ok> object
78	 stored: 7c34ee8c3de68a60833ad48675da46483dc2c7b1cb42333fd6a528a93a39f652 1592776800.000000000
79	 actual: 7c34ee8c3de68a60833ad48675da46483dc2c7b1cb42333fd6a528a93a39f652 1655848800.000000000
80	EOF
81	rm -f object
82	echo touched > object
83	TZ=CET touch -t 202006220000 object
84	../"${PRG}" object > /dev/null
85	TZ=CET touch -t 202206220000 object
86	../"${PRG}" object > output
87	diff -u expected output
88
89	#########################################################################
90	header 'modified empty file'
91	echo > object
92	../"${PRG}" object > /dev/null
93	../"${PRG}" object > /dev/null
94
95	#########################################################################
96	header 'new 100 zero file'
97	cat > expected <<- EOF
98	<new> object
99	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
100	 actual: 134e6543ddc35b40abb4f2f8aaaa2d0513a27e267beaf9081e29d84eba94017d 1655848800.000000000
101	EOF
102	rm -f object
103	printf '%0.s0' $(seq 1 100) > object
104	TZ=CET touch -t 202206220000 object
105	../"${PRG}" object > output
106	diff -u expected output
107
108	echo "<ok> object" > expected
109	../"${PRG}" object > output
110	diff -u expected output
111
112	#########################################################################
113	header 'attribute with appended NULL byte'
114	rm -f object
115	TZ=CET touch -t 202206220000 object
116	set_ts "1655848800.000000000" "object"
117	set_cs "6533623063343432393866633163313439616662663463383939366662393234323761653431653436343962393334636134393539393162373835326238353500" "object"
118	echo "<ok> object" > expected
119	../"${PRG}" object > output
120	diff -u expected output
121
122	#########################################################################
123	header 'attribute without appended NULL byte'
124	rm -f object
125	TZ=CET touch -t 202206220000 object
126	set_ts "1655848800.000000000" "object"
127	set_cs "65336230633434323938666331633134396166626634633839393666623932343237616534316534363439623933346361343935393931623738353262383535" "object"
128	echo "<ok> object" > expected
129	../"${PRG}" object > output
130	diff -u expected output
131
132	#########################################################################
133	header 'backdated file should persistently be flagged'
134	cat > expected <<- EOF
135	<backdated> object
136	 stored: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848800.000000000
137	 actual: d201858e7b45213e25f68d54255aa9337e77ab082fe023af25d49d4199db004f 1561154400.000000000
138	EOF
139	echo "backdated" > object
140	TZ=CET touch -t 201906220000 object
141	for i in $(seq 2); do
142		set +e
143		../"${PRG}" object 2>/dev/null > output
144		if [ $? -eq 0 ]; then
145			echo "should have returned an error code, but returned 0"
146			exit 1
147		fi
148		set -e
149		diff -u expected output
150	done
151
152	#########################################################################
153	header 'corrupt file should persistently be flagged'
154	cat > expected <<- EOF
155	<corrupt> object
156	 stored: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848800.000000000
157	 actual: 06d0083ba740ff26c91cb17f10d15d398eea1affd3112599b429f30452b59db4 1655848800.000000000
158	EOF
159	echo "corrupt" > object
160	TZ=CET touch -t 202206220000 object
161	for i in $(seq 2); do
162		set +e
163		../"${PRG}" object 2>/dev/null > output
164		if [ $? -eq 0 ]; then
165			echo "should have returned an error code, but returned 0"
166			exit 1
167		fi
168		set -e
169		diff -u expected output
170	done
171
172	#########################################################################
173	header 'file with malformed attributes should persistently be flagged'
174	echo "<malformed> object" > expected
175	echo "malformed" > object
176	set_cs "37323331375834333239653339623737323834366566373335386565666565386438353639626161383962316630366461363632373638336536323136353364" object
177	for i in $(seq 2); do
178		set +e
179		../"${PRG}" object 2>/dev/null > output
180		if [ $? -eq 0 ]; then
181			echo "should have returned an error code, but returned 0"
182			exit 1
183		fi
184		set -e
185		diff -u expected output
186	done
187
188	#########################################################################
189	header 'uppercase checksum should be changed to lowercase'
190	cat > expected <<- EOF
191	<outdated> object
192	 stored: 72317e4329e39b772846ef7358eefee8d8569baa89b1f06da6627683e621653d 1624320000.000000000
193	 actual: a6657f91652abf6d193fc9944c3e999d9aebfe5b33ebf3f733be673576f7af03 1655848800.000000000
194	EOF
195	echo "uppercase" > object
196	TZ=CET touch -t 202206220000 object
197	set_ts "1624320000.000000000" "object"
198	set_cs "37323331374534333239453339423737323834364546373335384545464545384438353639424141383942314630364441363632373638334536323136353344" object
199	../"${PRG}" object > output
200	diff -u expected output
201
202	#########################################################################
203	header 'removal of extended attributes'
204	cat > expected <<- EOF
205	<new> object
206	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
207	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848800.000000000
208	EOF
209	rm -f object
210	TZ=CET touch -t 202206220000 object
211	../"${PRG}" object > output
212	diff -u expected output
213	echo "<xattr removed> object" > expected
214	../"${PRG}" -x object > output
215	diff -u expected output
216	echo "Error: could not remove extended attributes from file \"object\": No data available" > expected
217	set +e
218	../"${PRG}" -x object > output 2>&1
219	if [ $? -eq 0 ]; then
220		echo "should have returned an error code, but returned 0"
221		exit 1
222	fi
223	set -e
224	diff -u expected output
225
226	#########################################################################
227	header 'nonexisting file'
228	set +e
229	echo "Error: could not open file \"nonexisting\"" > expected
230	../"${PRG}" nonexisting > output 2>&1
231	if [ $? -ne 2 ]; then
232		echo "should have returned an error code 2, but returned 0"
233		exit 1
234	fi
235	set -e
236	diff -u expected output
237
238	#########################################################################
239	header 'symlink'
240	ln -s object symlink
241	set +e
242	echo "Error: not a regular file \"symlink\"" > expected
243	../"${PRG}" symlink > output 2>&1
244	if [ $? -ne 3 ]; then
245		echo "should have returned an error code 3, but returned 0"
246		exit 1
247	fi
248	set -e
249	diff -u expected output
250	rm -f symlink
251
252	#########################################################################
253	header 'multiple files, using command line'
254	sort > expected <<- EOF
255	<new> object/level-1/file-1
256	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
257	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848860.000000000
258	<new> object/level-1/level-2/file-2
259	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
260	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848920.000000000
261	<new> object/level-1/level-2/level-3/file-3
262	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
263	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848980.000000000
264	EOF
265	rm -f object
266	mkdir -p object/level-1/level-2/level-3
267	TZ=CET touch -t 202206220001 object/level-1/file-1
268	TZ=CET touch -t 202206220002 object/level-1/level-2/file-2
269	TZ=CET touch -t 202206220003 object/level-1/level-2/level-3/file-3
270	find object -xdev -type f -print0 | xargs -r0 ../"${PRG}" | sort > output
271	diff -u expected output
272	rm -rf object
273
274	#########################################################################
275	header 'multiple files, using STDIN'
276	sort > expected <<- EOF
277	<new> object/level-1/file-1
278	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
279	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848860.000000000
280	<new> object/level-1/level-2/file-2
281	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
282	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848920.000000000
283	<new> object/level-1/level-2/level-3/file-3
284	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
285	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848980.000000000
286	EOF
287	rm -f object
288	mkdir -p object/level-1/level-2/level-3
289	TZ=CET touch -t 202206220001 object/level-1/file-1
290	TZ=CET touch -t 202206220002 object/level-1/level-2/file-2
291	TZ=CET touch -t 202206220003 object/level-1/level-2/level-3/file-3
292	find object -xdev -type f | ../"${PRG}" - | sort > output
293	diff -u expected output
294	rm -rf object
295
296	#########################################################################
297	header 'handle (-) as a file, when argument parsing is interrupted'
298	set +e
299	echo "Error: could not open file \"-\"" > expected
300	../"${PRG}" -- - > output 2>&1
301	if [ $? -ne 2 ]; then
302		echo "should have returned an error code 2, but returned 0"
303		exit 1
304	fi
305	set -e
306	diff -u expected output
307
308	#########################################################################
309	header 'dry run'
310	cat > expected <<- EOF
311	<new> object
312	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
313	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848800.000000000
314	EOF
315	TZ=CET touch -t 202206220000 object
316	../"${PRG}" -n object > output
317	diff -u expected output
318	../"${PRG}" object > output
319	diff -u expected output
320
321	#########################################################################
322	header 'dry run removal'
323	echo "<xattr removed> object" > expected
324	../"${PRG}" -xn object > output
325	diff -u expected output
326	../"${PRG}" -x object > output
327	diff -u expected output
328
329	#########################################################################
330	header 'recursive duplicate check'
331	sort > expected <<- EOF
332	Found 3 files with duplicates.
333	<dup> 1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2
334	 object/level-1/level-2/level-3/file-3
335	 object/level-1/level-2/file-3
336	 object/level-1/file-3
337	<dup> 4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865
338	 object/level-1/level-2/file-1
339	 object/level-1/file-1
340	<dup> 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3
341	 object/level-1/level-2/file-2
342	 object/level-1/file-2
343	EOF
344	rm -f object
345	mkdir -p object/level-1/level-2/level-3
346	echo "1" | tee object/level-1/file-1 > object/level-1/level-2/file-1
347	echo "2" | tee object/level-1/file-2 > object/level-1/level-2/file-2
348	echo "3" | tee object/level-1/file-3 object/level-1/level-2/file-3 >\
349	           object/level-1/level-2/level-3/file-3
350	echo "4" > object/level-1/file-4
351	find object -xdev -type f | ../"${PRG}" - > /dev/null 2>&1
352	find object -xdev -type f | ../"${PRG}" -d - 2>&1 | sort > output
353	diff -u expected output
354
355	#########################################################################
356	echo "\033[5;32m*** ALL TESTS WERE PASSED SUCCESSFULLY ***\033[0m"
357}