1#!/bin/sh -
2#
3#	$OpenBSD: run.test,v 1.3 2001/01/29 02:05:41 niklas Exp $
4#	$NetBSD: run.test,v 1.8 1996/05/03 21:57:51 cgd Exp $
5#	@(#)run.test	8.10 (Berkeley) 7/26/94
6#
7
8# db regression tests
9main()
10{
11
12	PROG=./dbtest
13	TMP1=t1
14	TMP2=t2
15	TMP3=t3
16
17	if [ -f /usr/share/dict/words ]; then
18		DICT=/usr/share/dict/words
19	elif [ -f /usr/dict/words ]; then
20		DICT=/usr/dict/words
21	else
22		echo 'run.test: no dictionary'
23		exit 1
24	fi
25	
26	if [ $# -eq 0 ]; then
27		for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 20; do
28			test$t
29		done
30	else
31		while [ $# -gt 0 ]
32			do case "$1" in
33			test*)
34				$1;;
35			[0-9]*)
36				test$1;;
37			btree)
38				for t in 1 2 3 7 8 9 10 12 13; do
39					test$t
40				done;;
41			hash)
42				for t in 1 2 3 8 13 20; do
43					test$t
44				done;;
45			recno)
46				for t in 1 2 3 4 5 6 7 10 11; do
47					test$t
48				done;;
49			*)
50				echo "run.test: unknown test $1"
51				echo "usage: run.test test# | type"
52				exit 1
53			esac
54			shift
55		done
56	fi
57	rm -f $TMP1 $TMP2 $TMP3
58	exit 0
59}
60
61# Take the first hundred entries in the dictionary, and make them
62# be key/data pairs.
63test1()
64{
65	echo "Test 1: btree, hash: small key, small data pairs"
66	sed 200q $DICT > $TMP1
67	for type in btree hash; do
68		rm -f $TMP2 $TMP3
69		for i in `sed 200q $DICT`; do
70			echo p
71			echo k$i
72			echo d$i
73			echo g
74			echo k$i
75		done > $TMP2
76		$PROG -o $TMP3 $type $TMP2
77		if (cmp -s $TMP1 $TMP3) ; then :
78		else
79			echo "test1: type $type: failed"
80			exit 1
81		fi
82	done
83	echo "Test 1: recno: small key, small data pairs"
84	rm -f $TMP2 $TMP3
85	sed 200q $DICT |
86	awk '{ 
87		++i;
88		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
89	}' > $TMP2
90	$PROG -o $TMP3 recno $TMP2
91	if (cmp -s $TMP1 $TMP3) ; then :
92	else
93		echo "test1: type recno: failed"
94		exit 1
95	fi
96}
97
98# Take the first 200 entries in the dictionary, and give them
99# each a medium size data entry.
100test2()
101{
102	echo "Test 2: btree, hash: small key, medium data pairs"
103	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
104	echo $mdata |
105	awk '{ for (i = 1; i < 201; ++i) print $0 }' > $TMP1
106	for type in hash btree; do
107		rm -f $TMP2 $TMP3
108		for i in `sed 200q $DICT`; do
109			echo p
110			echo k$i
111			echo d$mdata
112			echo g
113			echo k$i
114		done > $TMP2
115		$PROG -o $TMP3 $type $TMP2
116		if (cmp -s $TMP1 $TMP3) ; then :
117		else
118			echo "test2: type $type: failed"
119			exit 1
120		fi
121	done
122	echo "Test 2: recno: small key, medium data pairs"
123	rm -f $TMP2 $TMP3
124	echo $mdata | 
125	awk '{  for (i = 1; i < 201; ++i)
126		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
127	}' > $TMP2
128	$PROG -o $TMP3 recno $TMP2
129	if (cmp -s $TMP1 $TMP3) ; then :
130	else
131		echo "test2: type recno: failed"
132		exit 1
133	fi
134}
135
136# Insert the programs in /bin with their paths as their keys.
137test3()
138{
139	echo "Test 3: hash: small key, big data pairs"
140	rm -f $TMP1
141	(find /bin -type f -print | xargs cat) > $TMP1
142	for type in hash; do
143		rm -f $TMP2 $TMP3
144		for i in `find /bin -type f -print`; do
145			echo p
146			echo k$i
147			echo D$i
148			echo g
149			echo k$i
150		done > $TMP2
151		$PROG -o $TMP3 $type $TMP2
152		if (cmp -s $TMP1 $TMP3) ; then :
153		else
154			echo "test3: $type: failed"
155			exit 1
156		fi
157	done
158	echo "Test 3: btree: small key, big data pairs"
159	for psize in 512 16384 65536; do
160		echo "    page size $psize"
161		for type in btree; do
162			rm -f $TMP2 $TMP3
163			for i in `find /bin -type f -print`; do
164				echo p
165				echo k$i
166				echo D$i
167				echo g
168				echo k$i
169			done > $TMP2
170			$PROG -i psize=$psize -o $TMP3 $type $TMP2
171			if (cmp -s $TMP1 $TMP3) ; then :
172			else
173				echo "test3: $type: page size $psize: failed"
174				exit 1
175			fi
176		done
177	done
178	echo "Test 3: recno: big data pairs"
179	rm -f $TMP2 $TMP3
180	find /bin -type f -print | 
181	awk '{
182		++i;
183		printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
184	}' > $TMP2
185	for psize in 512 16384 65536; do
186		echo "    page size $psize"
187		$PROG -i psize=$psize -o $TMP3 recno $TMP2
188		if (cmp -s $TMP1 $TMP3) ; then :
189		else
190			echo "test3: recno: page size $psize: failed"
191			exit 1
192		fi
193	done
194}
195
196# Do random recno entries.
197test4()
198{
199	echo "Test 4: recno: random entries"
200	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
201	awk '{
202		for (i = 37; i <= 37 + 88 * 17; i += 17) {
203			if (i % 41)
204				s = substr($0, 1, i % 41);
205			else
206				s = substr($0, 1);
207			printf("input key %d: %s\n", i, s);
208		}
209		for (i = 1; i <= 15; ++i) {
210			if (i % 41)
211				s = substr($0, 1, i % 41);
212			else
213				s = substr($0, 1);
214			printf("input key %d: %s\n", i, s);
215		}
216		for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
217			if (i % 41)
218				s = substr($0, 1, i % 41);
219			else
220				s = substr($0, 1);
221			printf("input key %d: %s\n", i, s);
222		}
223		exit
224	}' > $TMP1
225	rm -f $TMP2 $TMP3
226	cat $TMP1 |
227	awk 'BEGIN {
228			i = 37;
229			incr = 17;
230		}
231		{
232			printf("p\nk%d\nd%s\n", i, $0);
233			if (i == 19234 + 61 * 27)
234				exit;
235			if (i == 37 + 88 * 17) {
236				i = 1;
237				incr = 1;
238			} else if (i == 15) {
239				i = 19234;
240				incr = 27;
241			} else
242				i += incr;
243		}
244		END {
245			for (i = 37; i <= 37 + 88 * 17; i += 17)
246				printf("g\nk%d\n", i);
247			for (i = 1; i <= 15; ++i)
248				printf("g\nk%d\n", i);
249			for (i = 19234; i <= 19234 + 61 * 27; i += 27)
250				printf("g\nk%d\n", i);
251		}' > $TMP2
252	$PROG -o $TMP3 recno $TMP2
253	if (cmp -s $TMP1 $TMP3) ; then :
254	else
255		echo "test4: type recno: failed"
256		exit 1
257	fi
258}
259
260# Do reverse order recno entries.
261test5()
262{
263	echo "Test 5: recno: reverse order entries"
264	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
265	awk ' {
266		for (i = 1500; i; --i) {
267			if (i % 34)
268				s = substr($0, 1, i % 34);
269			else
270				s = substr($0, 1);
271			printf("input key %d: %s\n", i, s);
272		}
273		exit;
274	}' > $TMP1
275	rm -f $TMP2 $TMP3
276	cat $TMP1 |
277	awk 'BEGIN {
278			i = 1500;
279		}
280		{
281			printf("p\nk%d\nd%s\n", i, $0);
282			--i;
283		}
284		END {
285			for (i = 1500; i; --i) 
286				printf("g\nk%d\n", i);
287		}' > $TMP2
288	$PROG -o $TMP3 recno $TMP2
289	if (cmp -s $TMP1 $TMP3) ; then :
290	else
291		echo "test5: type recno: failed"
292		exit 1
293	fi
294}
295		
296# Do alternating order recno entries.
297test6()
298{
299	echo "Test 6: recno: alternating order entries"
300	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
301	awk ' {
302		for (i = 1; i < 1200; i += 2) {
303			if (i % 34)
304				s = substr($0, 1, i % 34);
305			else
306				s = substr($0, 1);
307			printf("input key %d: %s\n", i, s);
308		}
309		for (i = 2; i < 1200; i += 2) {
310			if (i % 34)
311				s = substr($0, 1, i % 34);
312			else
313				s = substr($0, 1);
314			printf("input key %d: %s\n", i, s);
315		}
316		exit;
317	}' > $TMP1
318	rm -f $TMP2 $TMP3
319	cat $TMP1 |
320	awk 'BEGIN {
321			i = 1;
322			even = 0;
323		}
324		{
325			printf("p\nk%d\nd%s\n", i, $0);
326			i += 2;
327			if (i >= 1200) {
328				if (even == 1)
329					exit;
330				even = 1;
331				i = 2;
332			}
333		}
334		END {
335			for (i = 1; i < 1200; ++i) 
336				printf("g\nk%d\n", i);
337		}' > $TMP2
338	$PROG -o $TMP3 recno $TMP2
339	sort -o $TMP1 $TMP1
340	sort -o $TMP3 $TMP3
341	if (cmp -s $TMP1 $TMP3) ; then :
342	else
343		echo "test6: type recno: failed"
344		exit 1
345	fi
346}
347
348# Delete cursor record
349test7()
350{
351	echo "Test 7: btree, recno: delete cursor record"
352	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
353	awk '{
354		for (i = 1; i <= 120; ++i)
355			printf("%05d: input key %d: %s\n", i, i, $0);
356		printf("%05d: input key %d: %s\n", 120, 120, $0);
357		printf("seq failed, no such key\n");
358		printf("%05d: input key %d: %s\n", 1, 1, $0);
359		printf("%05d: input key %d: %s\n", 2, 2, $0);
360		exit;
361	}' > $TMP1
362	rm -f $TMP2 $TMP3
363
364	for type in btree recno; do
365		cat $TMP1 |
366		awk '{
367			if (i == 120)
368				exit;
369			printf("p\nk%d\nd%s\n", ++i, $0);
370		}
371		END {
372			printf("fR_NEXT\n");
373			for (i = 1; i <= 120; ++i)
374				printf("s\n");
375			printf("fR_CURSOR\ns\nk120\n");
376			printf("r\n");
377			printf("fR_NEXT\ns\n");
378			printf("fR_CURSOR\ns\nk1\n");
379			printf("r\n");
380			printf("fR_FIRST\ns\n");
381		}' > $TMP2
382		$PROG -o $TMP3 recno $TMP2
383		if (cmp -s $TMP1 $TMP3) ; then :
384		else
385			echo "test7: type $type: failed"
386			exit 1
387		fi
388	done
389}
390
391# Make sure that overflow pages are reused.
392test8()
393{
394	echo "Test 8: btree, hash: repeated small key, big data pairs"
395	rm -f $TMP1
396	echo "" | 
397	awk 'BEGIN {
398		for (i = 1; i <= 10; ++i) {
399			printf("p\nkkey1\nD/bin/sh\n");
400			printf("p\nkkey2\nD/bin/csh\n");
401			if (i % 8 == 0) {
402				printf("c\nkkey2\nD/bin/csh\n");
403				printf("c\nkkey1\nD/bin/sh\n");
404				printf("e\t%d of 10 (comparison)\n", i);
405			} else
406				printf("e\t%d of 10             \n", i);
407			printf("r\nkkey1\nr\nkkey2\n");
408		}
409	}' > $TMP1
410	$PROG btree $TMP1
411#	$PROG hash $TMP1
412	# No explicit test for success.
413}
414
415# Test btree duplicate keys
416test9()
417{
418	echo "Test 9: btree: duplicate keys"
419	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
420	awk '{
421		for (i = 1; i <= 543; ++i)
422			printf("%05d: input key %d: %s\n", i, i, $0);
423		exit;
424	}' > $TMP1
425	rm -f $TMP2 $TMP3
426
427	for type in btree; do
428		cat $TMP1 | 
429		awk '{
430			if (i++ % 2)
431				printf("p\nkduplicatekey\nd%s\n", $0);
432			else
433				printf("p\nkunique%dkey\nd%s\n", i, $0);
434		}
435		END {
436				printf("o\n");
437		}' > $TMP2
438		$PROG -iflags=1 -o $TMP3 $type $TMP2
439		sort -o $TMP3 $TMP3
440		if (cmp -s $TMP1 $TMP3) ; then :
441		else
442			echo "test9: type $type: failed"
443			exit 1
444		fi
445	done
446}
447
448# Test use of cursor flags without initialization
449test10()
450{
451	echo "Test 10: btree, recno: test cursor flag use"
452	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
453	awk '{
454		for (i = 1; i <= 20; ++i)
455			printf("%05d: input key %d: %s\n", i, i, $0);
456		exit;
457	}' > $TMP1
458	rm -f $TMP2 $TMP3
459
460	# Test that R_CURSOR doesn't succeed before cursor initialized
461	for type in btree recno; do
462		cat $TMP1 |
463		awk '{
464			if (i == 10)
465				exit;
466			printf("p\nk%d\nd%s\n", ++i, $0);
467		}
468		END {
469			printf("fR_CURSOR\nr\n");
470			printf("eR_CURSOR SHOULD HAVE FAILED\n");
471		}' > $TMP2
472		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
473		if [ -s $TMP3 ] ; then
474			echo "Test 10: delete: R_CURSOR SHOULD HAVE FAILED"
475			exit 1
476		fi
477	done
478	for type in btree recno; do
479		cat $TMP1 |
480		awk '{
481			if (i == 10)
482				exit;
483			printf("p\nk%d\nd%s\n", ++i, $0);
484		}
485		END {
486			printf("fR_CURSOR\np\nk1\ndsome data\n");
487			printf("eR_CURSOR SHOULD HAVE FAILED\n");
488		}' > $TMP2
489		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
490		if [ -s $TMP3 ] ; then
491			echo "Test 10: put: R_CURSOR SHOULD HAVE FAILED"
492			exit 1
493		fi
494	done
495}
496
497# Test insert in reverse order.
498test11()
499{
500	echo "Test 11: recno: reverse order insert"
501	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
502	awk '{
503		for (i = 1; i <= 779; ++i)
504			printf("%05d: input key %d: %s\n", i, i, $0);
505		exit;
506	}' > $TMP1
507	rm -f $TMP2 $TMP3
508
509	for type in recno; do
510		cat $TMP1 |
511		awk '{
512			if (i == 0) {
513				i = 1;
514				printf("p\nk1\nd%s\n", $0);
515				printf("%s\n", "fR_IBEFORE");
516			} else
517				printf("p\nk1\nd%s\n", $0);
518		}
519		END {
520				printf("or\n");
521		}' > $TMP2
522		$PROG -o $TMP3 $type $TMP2
523		if (cmp -s $TMP1 $TMP3) ; then :
524		else
525			echo "test11: type $type: failed"
526			exit 1
527		fi
528	done
529}
530
531# Take the first 20000 entries in the dictionary, reverse them, and give
532# them each a small size data entry.  Use a small page size to make sure
533# the btree split code gets hammered.
534test12()
535{
536	echo "Test 12: btree: lots of keys, small page size"
537	mdata=abcdefghijklmnopqrstuvwxy
538	echo $mdata |
539	awk '{ for (i = 1; i < 20001; ++i) print $0 }' > $TMP1
540	for type in btree; do
541		rm -f $TMP2 $TMP3
542		for i in `sed 20000q $DICT | rev`; do
543			echo p
544			echo k$i
545			echo d$mdata
546			echo g
547			echo k$i
548		done > $TMP2
549		$PROG -i psize=512 -o $TMP3 $type $TMP2
550		if (cmp -s $TMP1 $TMP3) ; then :
551		else
552			echo "test12: type $type: failed"
553			exit 1
554		fi
555	done
556}
557
558# Test different byte orders.
559test13()
560{
561	echo "Test 13: btree, hash: differing byte orders"
562	sed 50q $DICT > $TMP1
563	for order in 1234 4321; do
564		for type in btree hash; do
565			rm -f byte.file $TMP2 $TMP3
566			for i in `sed 50q $DICT`; do
567				echo p
568				echo k$i
569				echo d$i
570				echo g
571				echo k$i
572			done > $TMP2
573			$PROG -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
574			if (cmp -s $TMP1 $TMP3) ; then :
575			else
576				echo "test13: $type/$order put failed"
577				exit 1
578			fi
579			for i in `sed 50q $DICT`; do
580				echo g
581				echo k$i
582			done > $TMP2
583			$PROG -s \
584			    -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
585			if (cmp -s $TMP1 $TMP3) ; then :
586			else
587				echo "test13: $type/$order get failed"
588				exit 1
589			fi
590		done
591	done
592	rm -f byte.file
593}
594
595# Try a variety of bucketsizes and fill factors for hashing
596test20()
597{
598	echo\
599    "Test 20: hash: bucketsize, fill factor; nelem 25000 cachesize 65536"
600	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
601	awk '{
602		for (i = 1; i <= 10000; ++i) {
603			if (i % 34)
604				s = substr($0, 1, i % 34);
605			else
606				s = substr($0, 1);
607			printf("%s\n", s);
608		}
609		exit;
610	}' > $TMP1
611	sed 10000q $DICT |
612	awk 'BEGIN {
613		ds="abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg"
614	}
615	{
616		if (++i % 34)
617			s = substr(ds, 1, i % 34);
618		else
619			s = substr(ds, 1);
620		printf("p\nk%s\nd%s\n", $0, s);
621	}' > $TMP2
622	sed 10000q $DICT |
623	awk '{
624		++i;
625		printf("g\nk%s\n", $0);
626	}' >> $TMP2
627	bsize=256
628	for ffactor in 11 14 21; do
629		echo "    bucketsize $bsize, fill factor $ffactor"
630		$PROG -o$TMP3 \
631		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
632		    hash $TMP2
633		if (cmp -s $TMP1 $TMP3) ; then :
634		else
635			echo "test20: type hash:\
636bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
637			exit 1
638		fi
639	done
640	bsize=512
641	for ffactor in 21 28 43; do
642		echo "    bucketsize $bsize, fill factor $ffactor"
643		$PROG -o$TMP3 \
644		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
645		    hash $TMP2
646		if (cmp -s $TMP1 $TMP3) ; then :
647		else
648			echo "test20: type hash:\
649bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
650			exit 1
651		fi
652	done
653	bsize=1024
654	for ffactor in 43 57 85; do
655		echo "    bucketsize $bsize, fill factor $ffactor"
656		$PROG -o$TMP3 \
657		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
658		    hash $TMP2
659		if (cmp -s $TMP1 $TMP3) ; then :
660		else
661			echo "test20: type hash:\
662bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
663			exit 1
664		fi
665	done
666	bsize=2048
667	for ffactor in 85 114 171; do
668		echo "    bucketsize $bsize, fill factor $ffactor"
669		$PROG -o$TMP3 \
670		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
671		    hash $TMP2
672		if (cmp -s $TMP1 $TMP3) ; then :
673		else
674			echo "test20: type hash:\
675bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
676			exit 1
677		fi
678	done
679	bsize=4096
680	for ffactor in 171 228 341; do
681		echo "    bucketsize $bsize, fill factor $ffactor"
682		$PROG -o$TMP3 \
683		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
684		    hash $TMP2
685		if (cmp -s $TMP1 $TMP3) ; then :
686		else
687			echo "test20: type hash:\
688bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
689			exit 1
690		fi
691	done
692	bsize=8192
693	for ffactor in 341 455 683; do
694		echo "    bucketsize $bsize, fill factor $ffactor"
695		$PROG -o$TMP3 \
696		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
697		    hash $TMP2
698		if (cmp -s $TMP1 $TMP3) ; then :
699		else
700			echo "test20: type hash:\
701bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
702			exit 1
703		fi
704	done
705}
706
707main $*
708