xref: /freebsd/contrib/netbsd-tests/lib/libc/db/t_db.sh (revision 4e9c68081e1e4eaad6d3782f3c542b778e426d0c)
1# $NetBSD: t_db.sh,v 1.7 2016/09/24 20:12:33 christos Exp $
2#
3# Copyright (c) 2008 The NetBSD Foundation, Inc.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27
28prog_db()
29{
30	echo $(atf_get_srcdir)/h_db
31}
32
33prog_lfsr()
34{
35	echo $(atf_get_srcdir)/h_lfsr
36}
37
38dict()
39{
40	if [ -f /usr/share/dict/words ]; then
41		echo /usr/share/dict/words
42	elif [ -f /usr/dict/words ]; then
43		echo /usr/dict/words
44	else
45		atf_fail "no dictionary found"
46	fi
47}
48
49# Begin FreeBSD
50dict()
51{
52	echo /usr/share/dict/words
53}
54# End FreeBSD
55
56SEVEN_SEVEN="abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg"
57
58atf_test_case small_btree
59small_btree_head()
60{
61	atf_set "descr" \
62		"Checks btree database using small keys and small data" \
63		"pairs: takes the first hundred entries in the dictionary," \
64		"and makes them be key/data pairs."
65	# Begin FreeBSD
66	atf_set "require.files" /usr/share/dict/words
67	# End FreeBSD
68}
69small_btree_body()
70{
71	TMPDIR="$(pwd)/db_dir"; export TMPDIR
72	mkdir ${TMPDIR}
73
74	sed 200q $(dict) >exp
75
76	for i in `sed 200q $(dict)`; do
77		echo p
78		echo k$i
79		echo d$i
80		echo g
81		echo k$i
82	done >in
83
84	atf_check -o file:exp "$(prog_db)" btree in
85}
86
87atf_test_case small_hash
88small_hash_head()
89{
90	atf_set "descr" \
91		"Checks hash database using small keys and small data" \
92		"pairs: takes the first hundred entries in the dictionary," \
93		"and makes them be key/data pairs."
94	# Begin FreeBSD
95	atf_set "require.files" /usr/share/dict/words
96	# End FreeBSD
97}
98small_hash_body()
99{
100	TMPDIR="$(pwd)/db_dir"; export TMPDIR
101	mkdir ${TMPDIR}
102
103	sed 200q $(dict) >exp
104
105	for i in `sed 200q $(dict)`; do
106		echo p
107		echo k$i
108		echo d$i
109		echo g
110		echo k$i
111	done >in
112
113	atf_check -o file:exp "$(prog_db)" hash in
114}
115
116atf_test_case small_recno
117small_recno_head()
118{
119	atf_set "descr" \
120		"Checks recno database using small keys and small data" \
121		"pairs: takes the first hundred entries in the dictionary," \
122		"and makes them be key/data pairs."
123	# Begin FreeBSD
124	atf_set "require.files" /usr/share/dict/words
125	# End FreeBSD
126}
127small_recno_body()
128{
129	TMPDIR="$(pwd)/db_dir"; export TMPDIR
130	mkdir ${TMPDIR}
131
132	sed 200q $(dict) >exp
133
134	sed 200q $(dict) |
135	awk '{
136		++i;
137		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
138	}' >in
139
140	atf_check -o file:exp "$(prog_db)" recno in
141}
142
143atf_test_case medium_btree
144medium_btree_head()
145{
146	atf_set "descr" \
147		"Checks btree database using small keys and medium" \
148		"data pairs: takes the first 200 entries in the" \
149		"dictionary, and gives them each a medium size data entry."
150	# Begin FreeBSD
151	atf_set "require.files" /usr/share/dict/words
152	# End FreeBSD
153}
154medium_btree_body()
155{
156	TMPDIR="$(pwd)/db_dir"; export TMPDIR
157	mkdir ${TMPDIR}
158
159	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
160	echo $mdata |
161	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
162
163	for i in $(sed 200q $(dict)); do
164		echo p
165		echo k$i
166		echo d$mdata
167		echo g
168		echo k$i
169	done >in
170
171	atf_check -o file:exp "$(prog_db)" btree in
172}
173
174atf_test_case medium_hash
175medium_hash_head()
176{
177	atf_set "descr" \
178		"Checks hash database using small keys and medium" \
179		"data pairs: takes the first 200 entries in the" \
180		"dictionary, and gives them each a medium size data entry."
181	# Begin FreeBSD
182	atf_set "require.files" /usr/share/dict/words
183	# End FreeBSD
184}
185medium_hash_body()
186{
187	TMPDIR="$(pwd)/db_dir"; export TMPDIR
188	mkdir ${TMPDIR}
189
190	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
191	echo $mdata |
192	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
193
194	for i in $(sed 200q $(dict)); do
195		echo p
196		echo k$i
197		echo d$mdata
198		echo g
199		echo k$i
200	done >in
201
202	atf_check -o file:exp "$(prog_db)" hash in
203}
204
205atf_test_case medium_recno
206medium_recno_head()
207{
208	atf_set "descr" \
209		"Checks recno database using small keys and medium" \
210		"data pairs: takes the first 200 entries in the" \
211		"dictionary, and gives them each a medium size data entry."
212}
213medium_recno_body()
214{
215	TMPDIR="$(pwd)/db_dir"; export TMPDIR
216	mkdir ${TMPDIR}
217
218	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
219	echo $mdata |
220	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
221
222	echo $mdata |
223	awk '{  for (i = 1; i < 201; ++i)
224		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
225	}' >in
226
227	atf_check -o file:exp "$(prog_db)" recno in
228}
229
230atf_test_case big_btree
231big_btree_head()
232{
233	atf_set "descr" \
234		"Checks btree database using small keys and big data" \
235		"pairs: inserts the programs in /bin with their paths" \
236		"as their keys."
237}
238big_btree_body()
239{
240	TMPDIR="$(pwd)/db_dir"; export TMPDIR
241	mkdir ${TMPDIR}
242
243	(find /bin -type f -print | xargs cat) >exp
244
245	for psize in 512 16384 65536; do
246		echo "checking page size: $psize"
247
248		for i in `find /bin -type f -print`; do
249			echo p
250			echo k$i
251			echo D$i
252			echo g
253			echo k$i
254		done >in
255
256		atf_check "$(prog_db)" -o out btree in
257		cmp -s exp out || atf_fail "test failed for page size: $psize"
258	done
259}
260
261atf_test_case big_hash
262big_hash_head()
263{
264	atf_set "descr" \
265		"Checks hash database using small keys and big data" \
266		"pairs: inserts the programs in /bin with their paths" \
267		"as their keys."
268}
269big_hash_body()
270{
271	TMPDIR="$(pwd)/db_dir"; export TMPDIR
272	mkdir ${TMPDIR}
273
274	(find /bin -type f -print | xargs cat) >exp
275
276	for i in `find /bin -type f -print`; do
277		echo p
278		echo k$i
279		echo D$i
280		echo g
281		echo k$i
282	done >in
283
284	atf_check "$(prog_db)" -o out hash in
285	cmp -s exp out || atf_fail "test failed"
286}
287
288atf_test_case big_recno
289big_recno_head()
290{
291	atf_set "descr" \
292		"Checks recno database using small keys and big data" \
293		"pairs: inserts the programs in /bin with their paths" \
294		"as their keys."
295}
296big_recno_body()
297{
298	TMPDIR="$(pwd)/db_dir"; export TMPDIR
299	mkdir ${TMPDIR}
300
301	(find /bin -type f -print | xargs cat) >exp
302
303	find /bin -type f -print |
304	awk '{
305		++i;
306		printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
307	}' >in
308
309	for psize in 512 16384 65536; do
310		echo "checking page size: $psize"
311
312		atf_check "$(prog_db)" -o out recno in
313		cmp -s exp out || atf_fail "test failed for page size: $psize"
314	done
315}
316
317atf_test_case random_recno
318random_recno_head()
319{
320	atf_set "descr" "Checks recno database using random entries"
321}
322random_recno_body()
323{
324	TMPDIR="$(pwd)/db_dir"; export TMPDIR
325	mkdir ${TMPDIR}
326
327	echo $SEVEN_SEVEN |
328	awk '{
329		for (i = 37; i <= 37 + 88 * 17; i += 17) {
330			if (i % 41)
331				s = substr($0, 1, i % 41);
332			else
333				s = substr($0, 1);
334			printf("input key %d: %s\n", i, s);
335		}
336		for (i = 1; i <= 15; ++i) {
337			if (i % 41)
338				s = substr($0, 1, i % 41);
339			else
340				s = substr($0, 1);
341			printf("input key %d: %s\n", i, s);
342		}
343		for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
344			if (i % 41)
345				s = substr($0, 1, i % 41);
346			else
347				s = substr($0, 1);
348			printf("input key %d: %s\n", i, s);
349		}
350		exit
351	}' >exp
352
353	cat exp |
354	awk 'BEGIN {
355			i = 37;
356			incr = 17;
357		}
358		{
359			printf("p\nk%d\nd%s\n", i, $0);
360			if (i == 19234 + 61 * 27)
361				exit;
362			if (i == 37 + 88 * 17) {
363				i = 1;
364				incr = 1;
365			} else if (i == 15) {
366				i = 19234;
367				incr = 27;
368			} else
369				i += incr;
370		}
371		END {
372			for (i = 37; i <= 37 + 88 * 17; i += 17)
373				printf("g\nk%d\n", i);
374			for (i = 1; i <= 15; ++i)
375				printf("g\nk%d\n", i);
376			for (i = 19234; i <= 19234 + 61 * 27; i += 27)
377				printf("g\nk%d\n", i);
378		}' >in
379
380	atf_check -o file:exp "$(prog_db)" recno in
381}
382
383atf_test_case reverse_recno
384reverse_recno_head()
385{
386	atf_set "descr" "Checks recno database using reverse order entries"
387}
388reverse_recno_body()
389{
390	TMPDIR="$(pwd)/db_dir"; export TMPDIR
391	mkdir ${TMPDIR}
392
393	echo $SEVEN_SEVEN |
394	awk ' {
395		for (i = 1500; i; --i) {
396			if (i % 34)
397				s = substr($0, 1, i % 34);
398			else
399				s = substr($0, 1);
400			printf("input key %d: %s\n", i, s);
401		}
402		exit;
403	}' >exp
404
405	cat exp |
406	awk 'BEGIN {
407			i = 1500;
408		}
409		{
410			printf("p\nk%d\nd%s\n", i, $0);
411			--i;
412		}
413		END {
414			for (i = 1500; i; --i)
415				printf("g\nk%d\n", i);
416		}' >in
417
418	atf_check -o file:exp "$(prog_db)" recno in
419}
420
421atf_test_case alternate_recno
422alternate_recno_head()
423{
424	atf_set "descr" "Checks recno database using alternating order entries"
425}
426alternate_recno_body()
427{
428	TMPDIR="$(pwd)/db_dir"; export TMPDIR
429	mkdir ${TMPDIR}
430
431	echo $SEVEN_SEVEN |
432	awk ' {
433		for (i = 1; i < 1200; i += 2) {
434			if (i % 34)
435				s = substr($0, 1, i % 34);
436			else
437				s = substr($0, 1);
438			printf("input key %d: %s\n", i, s);
439		}
440		for (i = 2; i < 1200; i += 2) {
441			if (i % 34)
442				s = substr($0, 1, i % 34);
443			else
444				s = substr($0, 1);
445			printf("input key %d: %s\n", i, s);
446		}
447		exit;
448	}' >exp
449
450	cat exp |
451	awk 'BEGIN {
452			i = 1;
453			even = 0;
454		}
455		{
456			printf("p\nk%d\nd%s\n", i, $0);
457			i += 2;
458			if (i >= 1200) {
459				if (even == 1)
460					exit;
461				even = 1;
462				i = 2;
463			}
464		}
465		END {
466			for (i = 1; i < 1200; ++i)
467				printf("g\nk%d\n", i);
468		}' >in
469
470	atf_check "$(prog_db)" -o out recno in
471
472	sort -o exp exp
473	sort -o out out
474
475	cmp -s exp out || atf_fail "test failed"
476}
477
478h_delete()
479{
480	TMPDIR="$(pwd)/db_dir"; export TMPDIR
481	mkdir ${TMPDIR}
482
483	type=$1
484
485	echo $SEVEN_SEVEN |
486	awk '{
487		for (i = 1; i <= 120; ++i)
488			printf("%05d: input key %d: %s\n", i, i, $0);
489	}' >exp
490
491	cat exp |
492	awk '{
493		printf("p\nk%d\nd%s\n", ++i, $0);
494	}
495	END {
496		printf("fR_NEXT\n");
497		for (i = 1; i <= 120; ++i)
498			printf("s\n");
499		printf("fR_CURSOR\ns\nkXX\n");
500		printf("r\n");
501		printf("fR_NEXT\ns\n");
502		printf("fR_CURSOR\ns\nk1\n");
503		printf("r\n");
504		printf("fR_FIRST\ns\n");
505	}' >in
506
507	# For btree, the records are ordered by the string representation
508	# of the key value.  So sort the expected output file accordingly,
509	# and set the seek_last key to the last expected key value.
510
511	if [ "$type" = "btree" ] ; then
512		sed -e 's/kXX/k99/' < in > tmp
513		mv tmp in
514		sort -d -k4 < exp > tmp
515		mv tmp exp
516		echo $SEVEN_SEVEN |
517		awk '{
518			printf("%05d: input key %d: %s\n", 99, 99, $0);
519			printf("seq failed, no such key\n");
520			printf("%05d: input key %d: %s\n", 1, 1, $0);
521			printf("%05d: input key %d: %s\n", 10, 10, $0);
522			exit;
523		}' >> exp
524	else
525	# For recno, records are ordered by numerical key value.  No sort
526	# is needed, but still need to set proper seek_last key value.
527		sed -e 's/kXX/k120/' < in > tmp
528		mv tmp in
529		echo $SEVEN_SEVEN |
530		awk '{
531			printf("%05d: input key %d: %s\n", 120, 120, $0);
532			printf("seq failed, no such key\n");
533			printf("%05d: input key %d: %s\n", 1, 1, $0);
534			printf("%05d: input key %d: %s\n", 2, 2, $0);
535			exit;
536		}' >> exp
537	fi
538
539	atf_check "$(prog_db)" -o out $type in
540	atf_check -o file:exp cat out
541}
542
543atf_test_case delete_btree
544delete_btree_head()
545{
546	atf_set "descr" "Checks removing records in btree database"
547}
548delete_btree_body()
549{
550	h_delete btree
551}
552
553atf_test_case delete_recno
554delete_recno_head()
555{
556	atf_set "descr" "Checks removing records in recno database"
557}
558delete_recno_body()
559{
560	h_delete recno
561}
562
563h_repeated()
564{
565	local type="$1"
566	TMPDIR="$(pwd)/db_dir"; export TMPDIR
567	mkdir ${TMPDIR}
568
569	echo "" |
570	awk 'BEGIN {
571		for (i = 1; i <= 10; ++i) {
572			printf("p\nkkey1\nD/bin/sh\n");
573			printf("p\nkkey2\nD/bin/csh\n");
574			if (i % 8 == 0) {
575				printf("c\nkkey2\nD/bin/csh\n");
576				printf("c\nkkey1\nD/bin/sh\n");
577				printf("e\t%d of 10 (comparison)\n", i);
578			} else
579				printf("e\t%d of 10             \n", i);
580			printf("r\nkkey1\nr\nkkey2\n");
581		}
582	}' >in
583
584	$(prog_db) $type in
585}
586
587atf_test_case repeated_btree
588repeated_btree_head()
589{
590	atf_set "descr" \
591		"Checks btree database with repeated small keys and" \
592		"big data pairs. Makes sure that overflow pages are reused"
593}
594repeated_btree_body()
595{
596	h_repeated btree
597}
598
599atf_test_case repeated_hash
600repeated_hash_head()
601{
602	atf_set "descr" \
603		"Checks hash database with repeated small keys and" \
604		"big data pairs. Makes sure that overflow pages are reused"
605}
606repeated_hash_body()
607{
608	h_repeated hash
609}
610
611atf_test_case duplicate_btree
612duplicate_btree_head()
613{
614	atf_set "descr" "Checks btree database with duplicate keys"
615}
616duplicate_btree_body()
617{
618	TMPDIR="$(pwd)/db_dir"; export TMPDIR
619	mkdir ${TMPDIR}
620
621	echo $SEVEN_SEVEN |
622	awk '{
623		for (i = 1; i <= 543; ++i)
624			printf("%05d: input key %d: %s\n", i, i, $0);
625		exit;
626	}' >exp
627
628	cat exp |
629	awk '{
630		if (i++ % 2)
631			printf("p\nkduplicatekey\nd%s\n", $0);
632		else
633			printf("p\nkunique%dkey\nd%s\n", i, $0);
634	}
635	END {
636			printf("o\n");
637	}' >in
638
639	atf_check -o file:exp -x "$(prog_db) -iflags=1 btree in | sort"
640}
641
642h_cursor_flags()
643{
644	local type=$1
645	TMPDIR="$(pwd)/db_dir"; export TMPDIR
646	mkdir ${TMPDIR}
647
648	echo $SEVEN_SEVEN |
649	awk '{
650		for (i = 1; i <= 20; ++i)
651			printf("%05d: input key %d: %s\n", i, i, $0);
652		exit;
653	}' >exp
654
655	# Test that R_CURSOR doesn't succeed before cursor initialized
656	cat exp |
657	awk '{
658		if (i == 10)
659			exit;
660		printf("p\nk%d\nd%s\n", ++i, $0);
661	}
662	END {
663		printf("fR_CURSOR\nr\n");
664		printf("eR_CURSOR SHOULD HAVE FAILED\n");
665	}' >in
666
667	atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in
668	atf_check -s ne:0 test -s out
669
670	cat exp |
671	awk '{
672		if (i == 10)
673			exit;
674		printf("p\nk%d\nd%s\n", ++i, $0);
675	}
676	END {
677		printf("fR_CURSOR\np\nk1\ndsome data\n");
678		printf("eR_CURSOR SHOULD HAVE FAILED\n");
679	}' >in
680
681	atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in
682	atf_check -s ne:0 test -s out
683}
684
685atf_test_case cursor_flags_btree
686cursor_flags_btree_head()
687{
688	atf_set "descr" \
689		"Checks use of cursor flags without initialization in btree database"
690}
691cursor_flags_btree_body()
692{
693	h_cursor_flags btree
694}
695
696atf_test_case cursor_flags_recno
697cursor_flags_recno_head()
698{
699	atf_set "descr" \
700		"Checks use of cursor flags without initialization in recno database"
701}
702cursor_flags_recno_body()
703{
704	h_cursor_flags recno
705}
706
707atf_test_case reverse_order_recno
708reverse_order_recno_head()
709{
710	atf_set "descr" "Checks reverse order inserts in recno database"
711}
712reverse_order_recno_body()
713{
714	TMPDIR="$(pwd)/db_dir"; export TMPDIR
715	mkdir ${TMPDIR}
716
717	echo $SEVEN_SEVEN |
718	awk '{
719		for (i = 1; i <= 779; ++i)
720			printf("%05d: input key %d: %s\n", i, i, $0);
721		exit;
722	}' >exp
723
724	cat exp |
725	awk '{
726		if (i == 0) {
727			i = 1;
728			printf("p\nk1\nd%s\n", $0);
729			printf("%s\n", "fR_IBEFORE");
730		} else
731			printf("p\nk1\nd%s\n", $0);
732	}
733	END {
734			printf("or\n");
735	}' >in
736
737	atf_check -o file:exp "$(prog_db)" recno in
738}
739
740atf_test_case small_page_btree
741small_page_btree_head()
742{
743	atf_set "descr" \
744		"Checks btree database with lots of keys and small page" \
745		"size: takes the first 20000 entries in the dictionary," \
746		"reverses them, and gives them each a small size data" \
747		"entry. Uses a small page size to make sure the btree" \
748		"split code gets hammered."
749	# Begin FreeBSD
750	atf_set "require.files" /usr/share/dict/words
751	# End FreeBSD
752}
753small_page_btree_body()
754{
755	TMPDIR="$(pwd)/db_dir"; export TMPDIR
756	mkdir ${TMPDIR}
757
758	mdata=abcdefghijklmnopqrstuvwxy
759	echo $mdata |
760	awk '{ for (i = 1; i < 20001; ++i) print $0 }' >exp
761
762	for i in `sed 20000q $(dict) | rev`; do
763		echo p
764		echo k$i
765		echo d$mdata
766		echo g
767		echo k$i
768	done >in
769
770	atf_check -o file:exp "$(prog_db)" -i psize=512 btree in
771}
772
773h_byte_orders()
774{
775	TMPDIR="$(pwd)/db_dir"; export TMPDIR
776	mkdir ${TMPDIR}
777
778	type=$1
779
780	sed 50q $(dict) >exp
781	for order in 1234 4321; do
782		for i in `sed 50q $(dict)`; do
783			echo p
784			echo k$i
785			echo d$i
786			echo S
787			echo g
788			echo k$i
789		done >in
790
791		atf_check -o file:exp "$(prog_db)" -ilorder=$order -f byte.file $type in
792
793		for i in `sed 50q $(dict)`; do
794			echo g
795			echo k$i
796		done >in
797
798		atf_check -o file:exp "$(prog_db)" -s -ilorder=$order -f byte.file $type in
799	done
800}
801
802atf_test_case byte_orders_btree
803byte_orders_btree_head()
804{
805	atf_set "descr" "Checks btree database using differing byte orders"
806	# Begin FreeBSD
807	atf_set "require.files" /usr/share/dict/words
808	# End FreeBSD
809}
810byte_orders_btree_body()
811{
812	h_byte_orders btree
813}
814
815atf_test_case byte_orders_hash
816byte_orders_hash_head()
817{
818	atf_set "descr" "Checks hash database using differing byte orders"
819}
820byte_orders_hash_body()
821{
822	h_byte_orders hash
823}
824
825h_bsize_ffactor()
826{
827	bsize=$1
828	ffactor=$2
829
830	echo "bucketsize $bsize, fill factor $ffactor"
831	atf_check -o file:exp "$(prog_db)" "-ibsize=$bsize,\
832ffactor=$ffactor,nelem=25000,cachesize=65536" hash in
833}
834
835atf_test_case bsize_ffactor
836bsize_ffactor_head()
837{
838	atf_set "timeout" "1800"
839	atf_set "descr" "Checks hash database with various" \
840					"bucketsizes and fill factors"
841	# Begin FreeBSD
842	atf_set "require.files" /usr/share/dict/words
843	# End FreeBSD
844}
845bsize_ffactor_body()
846{
847	TMPDIR="$(pwd)/db_dir"; export TMPDIR
848	mkdir ${TMPDIR}
849
850	echo $SEVEN_SEVEN |
851	awk '{
852		for (i = 1; i <= 10000; ++i) {
853			if (i % 34)
854				s = substr($0, 1, i % 34);
855			else
856				s = substr($0, 1);
857			printf("%s\n", s);
858		}
859		exit;
860
861	}' >exp
862
863	sed 10000q $(dict) |
864	awk 'BEGIN {
865		ds="'$SEVEN_SEVEN'"
866	}
867	{
868		if (++i % 34)
869			s = substr(ds, 1, i % 34);
870		else
871			s = substr(ds, 1);
872		printf("p\nk%s\nd%s\n", $0, s);
873	}' >in
874
875	sed 10000q $(dict) |
876	awk '{
877		++i;
878		printf("g\nk%s\n", $0);
879	}' >>in
880
881	h_bsize_ffactor 256 11
882	h_bsize_ffactor 256 14
883	h_bsize_ffactor 256 21
884
885	h_bsize_ffactor 512 21
886	h_bsize_ffactor 512 28
887	h_bsize_ffactor 512 43
888
889	h_bsize_ffactor 1024 43
890	h_bsize_ffactor 1024 57
891	h_bsize_ffactor 1024 85
892
893	h_bsize_ffactor 2048 85
894	h_bsize_ffactor 2048 114
895	h_bsize_ffactor 2048 171
896
897	h_bsize_ffactor 4096 171
898	h_bsize_ffactor 4096 228
899	h_bsize_ffactor 4096 341
900
901	h_bsize_ffactor 8192 341
902	h_bsize_ffactor 8192 455
903	h_bsize_ffactor 8192 683
904
905	h_bsize_ffactor 16384 341
906	h_bsize_ffactor 16384 455
907	h_bsize_ffactor 16384 683
908
909	h_bsize_ffactor 32768 341
910	h_bsize_ffactor 32768 455
911	h_bsize_ffactor 32768 683
912
913	# Begin FreeBSD
914	if false; then
915	# End FreeBSD
916	h_bsize_ffactor 65536 341
917	h_bsize_ffactor 65536 455
918	h_bsize_ffactor 65536 683
919	# Begin FreeBSD
920	fi
921	# End FreeBSD
922}
923
924# This tests 64K block size addition/removal
925atf_test_case four_char_hash
926four_char_hash_head()
927{
928	atf_set "descr" \
929		"Checks hash database with 4 char key and" \
930		"value insert on a 65536 bucket size"
931}
932four_char_hash_body()
933{
934	TMPDIR="$(pwd)/db_dir"; export TMPDIR
935	mkdir ${TMPDIR}
936
937	cat >in <<EOF
938p
939k1234
940d1234
941r
942k1234
943EOF
944
945	# Begin FreeBSD
946	if true; then
947		atf_check "$(prog_db)" -i bsize=32768 hash in
948	else
949	# End FreeBSD
950	atf_check "$(prog_db)" -i bsize=65536 hash in
951	# Begin FreeBSD
952	fi
953	# End FreeBSD
954}
955
956
957atf_test_case bsize_torture
958bsize_torture_head()
959{
960	atf_set "timeout" "36000"
961	atf_set "descr" "Checks hash database with various bucket sizes"
962}
963bsize_torture_body()
964{
965	TMPDIR="$(pwd)/db_dir"; export TMPDIR
966	mkdir ${TMPDIR}
967	# Begin FreeBSD
968	#
969	# db(3) doesn't support 64kB bucket sizes
970	for i in 2048 4096 8192 16384 32768 # 65536
971	# End FreeBSD
972	do
973		atf_check "$(prog_lfsr)" $i
974	done
975}
976
977atf_test_case btree_weird_page_split
978btree_weird_page_split_head()
979{
980	atf_set "descr"  \
981	    "Test for a weird page split condition where an insertion " \
982	    "into index 0 of a page that would cause the new item to " \
983	    "be the only item on the left page results in index 0 of " \
984	    "the right page being erroneously skipped; this only " \
985	    "happens with one particular key+data length for each page size."
986}
987btree_weird_page_split_body()
988{
989	for psize in 512 1024 2048 4096 8192; do
990		echo "    page size $psize"
991		kdsizes=`awk 'BEGIN {
992			psize = '$psize'; hsize = int(psize/2);
993			for (kdsize = hsize-40; kdsize <= hsize; kdsize++) {
994				print kdsize;
995			}
996		}' /dev/null`
997
998		# Use a series of keylen+datalen values in the right
999		# neighborhood to find the one that triggers the bug.
1000		# We could compute the exact size that triggers the
1001		# bug but this additional fuzz may be useful.
1002
1003		# Insert keys in reverse order to maximize the chances
1004		# for a split on index 0.
1005
1006		for kdsize in $kdsizes; do
1007			awk 'BEGIN {
1008				kdsize = '$kdsize';
1009				for (i = 8; i-- > 0; ) {
1010					s = sprintf("a%03d:%09d", i, kdsize);
1011					for (j = 0; j < kdsize-20; j++) {
1012						s = s "x";
1013					}
1014					printf("p\nka%03d\nd%s\n", i, s);
1015				}
1016				print "o";
1017			}' /dev/null > in
1018			sed -n 's/^d//p' in | sort > exp
1019			atf_check -o file:exp \
1020			    "$(prog_db)" -i psize=$psize btree in
1021		done
1022	done
1023}
1024
1025# Extremely tricky test attempting to replicate some unusual database
1026# corruption seen in the field: pieces of the database becoming
1027# inaccessible to random access, sequential access, or both.  The
1028# hypothesis is that at least some of these are triggered by the bug
1029# in page splits on index 0 with a particular exact keylen+datalen.
1030# (See Test 40.)  For psize=4096, this size is exactly 2024.
1031
1032# The order of operations here relies on very specific knowledge of
1033# the internals of the btree access method in order to place records
1034# at specific offsets in a page and to create certain keys on internal
1035# pages.  The to-be-split page immediately prior to the bug-triggering
1036# split has the following properties:
1037#
1038# * is not the leftmost leaf page
1039# * key on the parent page is compares less than the key of the item
1040#   on index 0
1041# * triggering record's key also compares greater than the key on the
1042#   parent page
1043
1044# Additionally, we prime the mpool LRU chain so that the head page on
1045# the chain has the following properties:
1046#
1047# * record at index 0 is located where it will not get overwritten by
1048#   items written to the right-hand page during the split
1049# * key of the record at index 0 compares less than the key of the
1050#   bug-triggering record
1051
1052# If the page-split bug exists, this test appears to create a database
1053# where some records are inaccessible to a search, but still remain in
1054# the file and are accessible by sequential traversal.  At least one
1055# record gets duplicated out of sequence.
1056
1057atf_test_case btree_tricky_page_split
1058btree_tricky_page_split_head()
1059{
1060	atf_set "descr"  \
1061	    "btree: no unsearchables due to page split on index 0"
1062}
1063btree_tricky_page_split_body()
1064{
1065	list=`(for i in a b c d; do
1066			for j in 990 998 999; do
1067				echo g ${i}${j} 1024
1068			done
1069		done;
1070		echo g y997 2014
1071		for i in y z; do
1072			for j in 998 999; do
1073				echo g ${i}${j} 1024
1074			done
1075		done)`
1076	# Exact number for trigger condition accounts for newlines
1077	# retained by dbtest with -ofile but not without; we use
1078	# -ofile, so count newlines.  keylen=5,datalen=5+2014 for
1079	# psize=4096 here.
1080	(cat - <<EOF
1081p z999 1024
1082p z998 1024
1083p y999 1024
1084p y990 1024
1085p d999 1024
1086p d990 1024
1087p c999 1024
1088p c990 1024
1089p b999 1024
1090p b990 1024
1091p a999 1024
1092p a990 1024
1093p y998 1024
1094r y990
1095p d998 1024
1096p d990 1024
1097p c998 1024
1098p c990 1024
1099p b998 1024
1100p b990 1024
1101p a998 1024
1102p a990 1024
1103p y997 2014
1104S
1105o
1106EOF
1107	echo "$list") |
1108	# awk script input:
1109	# {p|g|r} key [datasize]
1110	awk '/^[pgr]/{
1111		printf("%s\nk%s\n", $1, $2);
1112	}
1113	/^p/{
1114		s = $2;
1115		for (i = 0; i < $3; i++) {
1116			s = s "x";
1117		}
1118		printf("d%s\n", s);
1119	}
1120	!/^[pgr]/{
1121		print $0;
1122	}' > in
1123	(echo "$list"; echo "$list") | awk '{
1124		s = $2;
1125		for (i = 0; i < $3; i++) {
1126			s = s "x";
1127		}
1128		print s;
1129	}' > exp
1130	atf_check -o file:exp \
1131	    "$(prog_db)" -i psize=4096 btree in
1132}
1133
1134# Begin FreeBSD
1135if false; then
1136# End FreeBSD
1137atf_test_case btree_recursive_traversal
1138btree_recursive_traversal_head()
1139{
1140	atf_set "descr"  \
1141	    "btree: Test for recursive traversal successfully " \
1142	    "retrieving records that are inaccessible to normal " \
1143	    "sequential 'sibling-link' traversal. This works by " \
1144	    "unlinking a few leaf pages but leaving their parent " \
1145	    "links intact. To verify that the unlink actually makes " \
1146	    "records inaccessible, the test first uses 'o' to do a " \
1147	    "normal sequential traversal, followed by 'O' to do a " \
1148	    "recursive traversal."
1149}
1150btree_recursive_traversal_body()
1151{
1152	fill="abcdefghijklmnopqrstuvwxyzy"
1153	script='{
1154		for (i = 0; i < 20000; i++) {
1155			printf("p\nkAA%05d\nd%05d%s\n", i, i, $0);
1156		}
1157		print "u";
1158		print "u";
1159		print "u";
1160		print "u";
1161	}'
1162	(echo $fill | awk "$script"; echo o) > in1
1163	echo $fill |
1164	awk '{
1165		for (i = 0; i < 20000; i++) {
1166			if (i >= 5 && i <= 40)
1167				continue;
1168			printf("%05d%s\n", i, $0);
1169		}
1170	}' > exp1
1171	atf_check -o file:exp1 \
1172	    "$(prog_db)" -i psize=512 btree in1
1173	echo $fill |
1174	awk '{
1175		for (i = 0; i < 20000; i++) {
1176			printf("%05d%s\n", i, $0);
1177		}
1178	}' > exp2
1179	(echo $fill | awk "$script"; echo O) > in2
1180	atf_check -o file:exp2 \
1181	    "$(prog_db)" -i psize=512 btree in2
1182}
1183# Begin FreeBSD
1184fi
1185# End FreeBSD
1186
1187atf_test_case btree_byteswap_unaligned_access_bksd
1188btree_byteswap_unaligned_access_bksd_head()
1189{
1190	atf_set "descr"  \
1191	    "btree: big key, small data, byteswap unaligned access"
1192}
1193btree_byteswap_unaligned_access_bksd_body()
1194{
1195	(echo foo; echo bar) |
1196	awk '{
1197		s = $0
1198		for (i = 0; i < 488; i++) {
1199			s = s "x";
1200		}
1201		printf("p\nk%s\ndx\n", s);
1202	}' > in
1203	for order in 1234 4321; do
1204		atf_check \
1205		    "$(prog_db)" -o out -i psize=512,lorder=$order btree in
1206	done
1207}
1208
1209atf_test_case btree_byteswap_unaligned_access_skbd
1210btree_byteswap_unaligned_access_skbd_head()
1211{
1212	atf_set "descr"  \
1213	    "btree: small key, big data, byteswap unaligned access"
1214}
1215btree_byteswap_unaligned_access_skbd_body()
1216{
1217	# 484 = 512 - 20 (header) - 7 ("foo1234") - 1 (newline)
1218	(echo foo1234; echo bar1234) |
1219	awk '{
1220		s = $0
1221		for (i = 0; i < 484; i++) {
1222			s = s "x";
1223		}
1224		printf("p\nk%s\nd%s\n", $0, s);
1225	}' > in
1226	for order in 1234 4321; do
1227		atf_check \
1228		    "$(prog_db)" -o out -i psize=512,lorder=$order btree in
1229	done
1230}
1231
1232atf_test_case btree_known_byte_order
1233btree_known_byte_order_head()
1234{
1235	atf_set "descr"  \
1236	    "btree: small key, big data, known byte order"
1237}
1238btree_known_byte_order_body()
1239{
1240	local a="-i psize=512,lorder="
1241
1242	(echo foo1234; echo bar1234) |
1243	awk '{
1244		s = $0
1245		for (i = 0; i < 484; i++) {
1246			s = s "x";
1247		}
1248		printf("%s\n", s);
1249	}' > exp
1250	(echo foo1234; echo bar1234) |
1251	awk '{
1252		s = $0
1253		for (i = 0; i < 484; i++) {
1254			s = s "x";
1255		}
1256		printf("p\nk%s\nd%s\n", $0, s);
1257	}' > in1
1258	for order in 1234 4321; do
1259		atf_check \
1260		    "$(prog_db)" -f out.$order $a$order btree in1
1261	done
1262	(echo g; echo kfoo1234; echo g; echo kbar1234) > in2
1263	for order in 1234 4321; do
1264		atf_check -o file:exp \
1265		    "$(prog_db)" -s -f out.$order $a$order btree in2
1266	done
1267}
1268
1269atf_init_test_cases()
1270{
1271	atf_add_test_case small_btree
1272	atf_add_test_case small_hash
1273	atf_add_test_case small_recno
1274	atf_add_test_case medium_btree
1275	atf_add_test_case medium_hash
1276	atf_add_test_case medium_recno
1277	atf_add_test_case big_btree
1278	atf_add_test_case big_hash
1279	atf_add_test_case big_recno
1280	atf_add_test_case random_recno
1281	atf_add_test_case reverse_recno
1282	atf_add_test_case alternate_recno
1283	atf_add_test_case delete_btree
1284	atf_add_test_case delete_recno
1285	atf_add_test_case repeated_btree
1286	atf_add_test_case repeated_hash
1287	atf_add_test_case duplicate_btree
1288	atf_add_test_case cursor_flags_btree
1289	atf_add_test_case cursor_flags_recno
1290	atf_add_test_case reverse_order_recno
1291	atf_add_test_case small_page_btree
1292	atf_add_test_case byte_orders_btree
1293	atf_add_test_case byte_orders_hash
1294	atf_add_test_case bsize_ffactor
1295	atf_add_test_case four_char_hash
1296	atf_add_test_case bsize_torture
1297	atf_add_test_case btree_weird_page_split
1298	atf_add_test_case btree_tricky_page_split
1299	# Begin FreeBSD
1300	if false; then
1301	# End FreeBSD
1302	atf_add_test_case btree_recursive_traversal
1303	# Begin FreeBSD
1304	fi
1305	# End FreeBSD
1306	atf_add_test_case btree_byteswap_unaligned_access_bksd
1307	atf_add_test_case btree_byteswap_unaligned_access_skbd
1308	atf_add_test_case btree_known_byte_order
1309}
1310