Subversion Repositories vgwhois

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
#!/bin/bash
2
 
3
#
4
#  generic Whois - Maintenance Framework: Testcases
5
#
6
#  (c) 2012-2015 Daniel Marschall, ViaThinkSoft [www.viathinksoft.de]
7
#
8
#  Distribution, usage etc. pp. regulated by the current version of GPL.
9
#
10
#
11
#  Version 2015-05-03
12
#
13
 
14
# TODO: use >&2
15
 
16
# TODO: anzeigen von wann der whois output ist... "last checked" -> "last activity" (da ein user-mode-batch-approval ja kein recheck beinhaltet)
17
 
18
DIR=$( dirname "$0" )
19
 
20
annotfile="$DIR/../../config/testcases.annot"
21
 
22
TESTCASE_CACHE_FILE="$DIR/../../.cache/testcases"
23
 
24
# ---
25
 
26
function resetconsole {
27
	# http://superuser.com/questions/122911/bash-reset-and-clear-commands
28
 
29
	# clear
30
 
31
	# clears the console screen, but not the scrollback buffer
32
	# this is actually the escape code to "reset" the terminal
33
	echo -en "\ec"
34
 
35
	# clears the scrollback buffer, but not the console screen
36
	# screen content remains, and cursor position remains at its last position
37
	echo -en "\e[3J"
38
}
39
 
40
function showPatternHighlighted {
41
	A=()
42
 
43
	patterns=$( "$DIR"/allpatterns )
44
	for p in ${patterns[@]}; do
45
		A+=("$p");
46
	done
47
 
48
	out=""
49
	while IFS= read data; do
50
		out="$out$data"$'\n'
51
	done
52
 
53
	# Attention: "less" or "nano" does not work with Unicode for Asian languages :-(
54
	# Maybe this helps? http://serverfault.com/questions/414760/how-to-make-the-less-command-handle-utf-8 .
55
	# But then it still can't handle colors...
56
	echo "$out" | "$DIR"/highlighter "${A[@]}"
57
}
58
 
59
function question {
60
	if [ -f "$annotfile" ]; then
61
		ANNOTS=$( cat "$annotfile" | grep -E "^$query:" )
62
		if [ "$ANNOTS" != "" ]; then
63
			echo ""
64
			echo "********************"
65
			echo "Notes in $annotfile :"
66
			OLDIFS="$IFS"
67
			IFS=$'\n'
68
			for p in ${ANNOTS[@]}; do
69
				pos="${#query}"
70
				(( pos += 2 ))
71
				echo "   ${p:$pos}";
72
			done
73
			IFS="$OLDIFS"
74
			echo "********************"
75
		fi
76
	fi
77
	echo ""
78
	echo "Keep in mind to only set this result as expected state, when:"
79
	echo "   (1) The output is well formatted OR when you add an entry to the ToDo"
80
	echo "       list when the output is 'OK, but not optimal'."
81
	echo "   (2) For web-requests you should also have a testcase which shows"
82
	echo "       non-existant domains"
83
	echo "   (3) All handles should have testcases too, or it should be noted that"
84
	echo "       specific handles cannot be queried by the NIC."
85
	echo "   (4) There should be no volative stuff like dates, serving whois server"
86
	echo "       names or your IP address in the output."
87
	echo "       Otherwise you should grep them away in $0 before you approve this testcase."
88
	echo "   (5) In notices, URLs/information must be correct"
89
	echo "   (6) Highlighting shall be working, otherwise the patterns or $DIR/highlighter needs to be changed"
90
	while true; do
91
		echo ""
92
		if [ -f "$E" ]; then
93
			echo "Do you want to override the expected result? ([y]es, [n]o, [s]kip, [r]etry, [a]dd note, reset[t], e[x]it)"
94
		else
95
			# TODO: braucht man hier reset?
96
			echo "Do you want to define this as the expected result? ([y]es, [n]o, [s]kip, [r]etry, [a]dd note, rese[t], e[x]it)"
97
		fi
98
		read yn
99
		case $yn in
100
			[Yy]* )
101
				cat "$T" > "$E"
102
				rm "$T"
103
				if [ -f "$Q" ] && [ "$Q" != "$T" ]; then
104
					rm "$Q"
105
				fi
106
				touch "$tsfile"
107
				return 0
108
				;;
109
			[Nn]* )
110
				rm "$T"
111
				return 1
112
				;;
113
			[Ss]* )
114
				return 1
115
				;;
116
			[Rr]* )
117
				bakmode="$mode"
118
				mode="i"
119
				bakforce="$force"
120
				force=1
121
				process "$query"
122
				RES=$?
123
				mode="$bakmode"
124
				force="$bakforce"
125
				return $RES
126
				;;
127
			[Aa]* )
128
				echo "Please enter a note you want to add or empty string if you want to cancel"
129
				read note
130
 
131
				if [ "$note" == "" ]; then
132
					echo "Cancelled"
133
				else
134
					echo "Note added to testcase of $query"
135
					echo "$query: $note" >> "$annotfile"
136
				fi
137
				;;
138
			[Xx]* )
139
				return 2
140
				;;
141
			[Tt]* )
142
				# Clears the expected state
143
				#rm $TESTCASE_CACHE_FILE/*/$query
144
				rm "$E"
145
				rm "$Q"
146
				rm "$tsfile"
147
				# Now retry
148
				# TODO: codeduplikat vermeiden?
149
				bakmode="$mode"
150
				mode="i"
151
				bakforce="$force"
152
				force=1
153
				process "$query"
154
				RES=$?
155
				mode="$bakmode"
156
				force="$bakforce"
157
				return $RES
158
				;;
159
			* )
160
				echo "Please answer with the letter written in square brackets."
161
				;;
162
		esac
163
	done
164
}
165
 
166
function question2 {
167
	while true; do
168
		echo ""
169
		echo "Gwhois might already have been fixed. Do you want to enforce a gwhois recheck now? ([y]es, [n]o, e[x]it)"
170
		read yn
171
		case $yn in
172
			[YyRr]* )
173
				if [ -f "$Q" ]; then
174
					rm "$Q"
175
				fi
176
				bakmode="$mode"
177
				mode="i"
178
				bakforce="$force"
179
				force=1
180
				process "$query"
181
				RES=$?
182
				mode="$bakmode"
183
				force="$bakforce"
184
				return $RES
185
				;;
186
			[NnSs]* )
187
				return 1
188
				;;
189
			[Xx]* )
190
				return 2
191
				;;
192
			* )
193
				echo "Please answer with the letter written in square brackets."
194
				;;
195
		esac
196
	done
197
}
198
 
199
function unquote {
200
	echo "$1" | sed "s/^'\(.*\)'$/\1/";
201
}
202
 
203
function process {
204
	if [ "$mode" != "b" ]; then
205
		# TODO: diese meldung soll nicht kommen, wenn einfach nur da steht "does not need a recheck" now...
206
		resetconsole
207
	fi
208
 
209
	query="$1"
210
	echo "Query: $query"
211
 
212
	E="$TESTCASE_CACHE_FILE/expected/$query"
213
	Q="$TESTCASE_CACHE_FILE/problems/$query"
214
	tsfile="$TESTCASE_CACHE_FILE/checktimestamps/$query"
215
 
216
	if [ "$mode" == "u" ]; then
217
		T="$Q"
218
		if [ ! -f "$T" ]; then
219
			echo "There is no action needed by the user"
220
			return 0
221
		fi
222
	else
223
		T=$( mktemp --suffix='.gwhoisTC' )
224
 
225
		# In interactive/background mode, we will always do a webrequest when there is no problem and no expectation file without respect of the last checktime, to avoid that the status monitor will show entries with "no expectation file" when the user pressed "no", and then he would have to wait 7 days until "batch u" works again.
226
		# TODO: how to do that in 1 line?
227
		CALL_GWI=0
228
		if [ $force -eq 1 ]; then
229
			CALL_GWI=1
230
		else
231
			test \( ! -f "$Q" \) -a \( ! -f "$E" \)
232
			if [ $? -eq 0 ]; then
233
				CALL_GWI=1
234
			elif [ ! -f "$tsfile" ] || [ $( stat --format=%Y "$tsfile" ) -le $(( $( date +%s ) - $recheck_time )) ]; then
235
				if [ -f "$Q" ] && [ $( stat --format=%Y "$Q" ) -gt $(( $( date +%s ) - $recheck_time )) ]; then
236
					CALL_GWI=0
237
				else
238
					CALL_GWI=1
239
				fi
240
			fi
241
		fi
242
		if [ $CALL_GWI -eq 1 ]; then
243
			echo "... calling gwhois ..."
244
			# We have to use loc_gwhois to allow $trytor to work correctly.
245
			# The torifiers "torify" and "usewithtor" always outputting bogus "libtorsocks" warning messages which would be saved in the output
246
			# "vtor" - if applied to this script - can only filter them from STDOUT and STDERR, but not intercept this "&>" pipe
247
			# So we have to use this loc_gwhois script, where we torify manually
248
			# Also, it is important that we do the warning message filtering in this step, because in the final output the lines will be colored/highlighted, and therefore "vtor" cannot grep them correctly anymore.
249
			# Note: regex only valid in the years 1000-1099, 1900-2099, 2900-2999
250
			# grep away volative stuff like server names or times
251
			(
252
				"$DIR"/loc_gwhois "$query" \
253
					| grep -v "This query was served by " \
254
					| grep -v "(c)[12][90][0-9]\{2\}" \
255
					| grep -v "[12][90][0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}" \
256
					| grep -v "\[[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\} REQUEST\]" \
257
					| grep -v "RL Net \[.*\] - RL IP \[.*\]" \
258
					| grep -v "% Query time:" \
259
					| grep -v "% request from" \
260
					| grep -v "% Last update of whois database:" \
261
					| grep -v "%AM TLD whois server #" \
262
					| grep -v "Last updated on " \
263
					| grep -v "This is the Ukrainian Whois query server #" \
264
					| grep -v "Last update of whois database" \
265
					| grep -v "Query time:" \
266
					| grep -v "nsstat:" \
267
					| grep -v "nslastaa:"
268
			) &> "$T"
269
			# auskommentiert wegen problem: wenn man einen recheck wegen perl errors macht und dann abbricht, ist dann der PROBLEM state gespeichert? nein, er wurde im i-mode gelöscht!
270
			# -> lösung ?rm "$Q" nur im erfolgsfall
271
			#			if [ -f "$Q" ]; then
272
			#				rm "$Q"
273
			#			fi
274
 
275
			# behoben? in mode=i and mode=u, should the output of a new gwhois request be saved into the problem file, if the user cancels? (to avoid a second web request?)
276
			#       also, when doing a recheck after a perl error, and then cancel, the problem-file will not be updated!
277
			# TODO: was ist besser?
278
			#if [ ! -f "$Q" ] && [ "$T" != "$Q" ]; then
279
			if [ "$T" != "$Q" ]; then
280
				cat "$T" > "$Q"
281
			fi
282
 
283
 
284
		else
285
			rm "$T"
286
			if [ "$mode" == "b" ]; then
287
				echo "The query does not need a recheck now. Use --force to enforce it."
288
#				if [ -f "$Q" ] && [ "$Q" != "$T" ]; then
289
#					rm "$Q"
290
#				fi
291
				return 0
292
			else
293
				T="$Q"
294
				if [ ! -f "$T" ]; then
295
					echo "There is no action needed by the user"
296
					return 0
297
				fi
298
			fi
299
		fi
300
	fi
301
 
302
	WARNINGS=()
303
	cat "$T" | grep -E "at /(bin|usr|etc|var)/\S+ line" > /dev/null
304
	if [ $? -eq 0 ]; then
305
		WARNINGS+=("Perl errors found in gwhois output!")
306
	fi
307
	cat "$T" | head -n 1 | grep -E "^("$'\xEF\xBB\xBF'"){0,1}Process query: '$query'" > /dev/null
308
	if [ $? -ne 0 ]; then
309
		WARNINGS+=("The gwhois output does not begin with 'Process query'!")
310
	fi
311
	cat "$T" | grep "gwhois remarks: If this is a valid domainname or handle, please file a bug report." > /dev/null
312
	if [ $? -eq 0 ]; then
313
		WARNINGS+=("No pattern match!")
314
	fi
315
	if [ ${#WARNINGS[@]} -gt 0 ]; then
316
		if [ "$T" != "$Q" ]; then
317
			cat "$T" > "$Q"
318
			rm "$T"
319
		fi
320
#		if [ "$mode" != "b" ]; then
321
#			resetconsole
322
#		fi
323
		OLDIFS="$IFS"
324
		IFS=$'\n'
325
		for p in ${WARNINGS[@]}; do
326
			echo "WARNING: $p"
327
		done
328
		IFS="$OLDIFS"
329
		if [ "$mode" == "b" ]; then
330
			echo "Saved for later analysis."
331
			# TODO: problem: this will prevent another background runner to check it again, but it will prevent the user-batch to investigate this, too?!!
332
#			touch "$tsfile"
333
			return 1
334
		else
335
			# Hinweis: niemals vor "question" oder "question2" ein ts aktualisieren. denn wenn man in question* einen recheck beantragt und dann abbricht, dann würde dieser aktualisierte ts bewirken, dass der testcase erst wieder in 7 tagen angezeigt wird
336
			echo ""
337
			cat "$Q" | showPatternHighlighted
338
			question2
339
			return $?
340
		fi
341
	fi
342
 
343
	if [ -f "$E" ]; then
344
		D=$( date -r "$E" )
345
		echo "Compare with results of $D"
346
		diff -U 0 "$E" "$T" | showPatternHighlighted
347
		if [ ${PIPESTATUS[0]} -eq 0 ]; then
348
			echo "OK! No differences found!"
349
			rm "$T"
350
			touch "$tsfile"
351
			if [ -f "$Q" ] && [ "$Q" != "$T" ]; then
352
				rm "$Q"
353
			fi
354
			return 0
355
		else
356
			echo "Problem! Differences found!"
357
 
358
			if [ "$mode" == "b" ]; then
359
				echo "Saved for later analysis."
360
				if [ "$T" != "$Q" ]; then
361
					cat "$T" > "$Q"
362
					rm "$T"
363
				fi
364
 
365
				# TODO: problem: this will prevent another background runner to check it again, but it will prevent the user-batch to investigate this, too?!!
366
#				touch "$tsfile"
367
				return 1
368
			else
369
				if [ "$T" != "$Q" ]; then
370
					rm "$T"
371
				fi
372
 
373
				question
374
				return $?
375
			fi
376
		fi
377
	else
378
		if [ "$mode" == "b" ]; then
379
			echo "This query has no expected state. Please define one."
380
			echo "Saved for later analysis."
381
			if [ "$T" != "$Q" ]; then
382
				cat "$T" > "$Q"
383
				rm "$T"
384
			fi
385
			# TODO: problem: this will prevent another background runner to check it again, but it will prevent the user-batch to investigate this, too?!!
386
#			touch "$tsfile"
387
			return 1
388
		else
389
#			resetconsole
390
			echo "This query has no expected state. Please define one."
391
			echo "This is the current output of gwhois:"
392
 
393
			echo ""
394
			cat "$T" | showPatternHighlighted
395
			echo ""
396
 
397
			if [ "$T" != "$Q" ]; then
398
				rm "$T"
399
			fi
400
 
401
			question
402
			return $?
403
		fi
404
	fi
405
}
406
 
407
function HumanReadableTime {
408
	local seconds=$1
409
	local days=$(($seconds/86400))
410
	seconds=$(($seconds-($days*86400) ))
411
	local hours=$(($seconds/3600))
412
	seconds=$((seconds-($hours*3600) ))
413
	local minutes=$(($seconds/60))
414
	seconds=$(( $seconds-($minutes*60) ))
415
 
416
	# echo -n "${days}D ${hours}H ${minutes}M ${seconds}S"
417
	if [ $days -gt 0 ]; then
418
		if [ $hours -gt 12 ]; then
419
			((days++));
420
		fi
421
		echo -n "${days} days"
422
	elif [ $hours -gt 0 ]; then
423
		if [ $minutes -gt 30 ]; then
424
			((hours++));
425
		fi
426
		echo -n "${hours} hours"
427
	elif [ $minutes -gt 0 ]; then
428
		if [ $seconds -gt 30 ]; then
429
			((minutes++));
430
		fi
431
		echo -n "${minutes} minutes"
432
	else
433
		echo -n "a few seconds"
434
	fi
435
}
436
 
437
function usage {
438
	. "$DIR/../../config/testcases.conf"
439
 
440
	hf_recheck_time=$( HumanReadableTime $recheck_time )
441
 
442
	echo "Syntax: $0 options query"
443
	echo "	-h|--help"
444
	echo "	-m|--mode mode"
445
	echo "		Default: $mode"
446
	echo "		Mode: i = interactive (download and then show results/ask the developer if the result is OK)"
447
	echo "		      b = background (download only and save the results for later query)"
448
	echo "		      u = user-dialog only (only ask the developer if there are questions, e.g. which were generated by mode b)."
449
	echo "	-r|--rechecktime seconds"
450
	echo "		Default: $recheck_time = approx. $hf_recheck_time)"
451
	echo "	-f|--force"
452
	echo "		Ignores --rechecktime and forces a new gwhois request"
453
	echo "		Default: $force"
454
}
455
 
456
# ---
457
 
458
if [ $# -eq 0 ]; then
459
	usage;
460
	exit;
461
fi
462
 
463
if [ ! -d "$TESTCASE_CACHE_FILE/checktimestamps" ]; then
464
	mkdir "$TESTCASE_CACHE_FILE/checktimestamps"
465
fi
466
 
467
if [ ! -d "$TESTCASE_CACHE_FILE/problems" ]; then
468
	mkdir "$TESTCASE_CACHE_FILE/problems"
469
fi
470
 
471
if [ ! -d "$TESTCASE_CACHE_FILE/expected" ]; then
472
	mkdir "$TESTCASE_CACHE_FILE/expected"
473
fi
474
 
475
# defaults
476
. "$DIR/../../config/testcases.conf"
477
 
478
PARAMS=( "$@" );
479
optarr=( $( getopt --name "$0" --options 'hfr:m:' --long 'help,force,rechecktime:,mode:' -- "${PARAMS[@]}" 2> /dev/null ) );
480
 
481
# Now process the arguments
482
i=0;
483
while true; do
484
	case "${optarr[$i]}" in
485
		-h|--help)
486
			usage;
487
			exit 0;
488
			;;
489
		-f|--force)
490
			force=1;
491
			((i++));
492
			;;
493
		-r|--rechecktime)
494
			recheck_time=$( unquote "${optarr[$((i+1))]}" );
495
			((i=i+2));
496
			;;
497
		-m|--mode)
498
			mode=$( unquote "${optarr[$((i+1))]}" );
499
 
500
			if [ "$mode" != "i" ] && [ "$mode" != "b" ] && [ "$mode" != "u" ]; then
501
				echo "Invalid mode '$mode'"
502
				usage
503
				exit 2
504
			fi
505
 
506
			((i=i+2));
507
			;;
508
		--)
509
			((i++));
510
			break;
511
			;;
512
		*)
513
			# Should never happen
514
			echo "$0: Internal error while command-line-processing! Please report this error as bug." >&2;
515
			exit 2;
516
			;;
517
	esac
518
done
519
 
520
RESTARGS=${optarr[@]:i}; # i..end
521
CMD="${optarr[i]}";
522
ARG="${optarr[@]:((i+1))}"; # (i+1)..end
523
 
524
 
525
EXITSTATUS=0
526
for X in ${RESTARGS[@]}
527
do
528
	X=$( unquote "$X" )
529
	process "$X"
530
	EC=$?
531
 
532
	if [ $EC -eq 2 ]; then
533
		# user pressed x for exit
534
		exit $EXITSTATUS;
535
	elif [ $EC -gt $EXITSTATUS ]; then
536
		# exitcode = max(exitcodes from processes)
537
		EXITSTATUS=$EC
538
	fi
539
 
540
done
541
 
542
exit $EXITSTATUS