[GSOC 2014][PATCH 5/7] JSON: Add basic test support for JSON framework

Zhu YangMin zym0017d at gmail.com
Mon Jul 21 14:35:27 UTC 2014


We will do 3 compare to check the output:
1) Compare the Unmodified strace output to the Normal outputs;
2) Compare the JSON parsed results to the Normal outputs(ignore space);
3) Compare the JSON parsed results to the Unmodified strace outputs(ignore space);

The 1st comparison should be identical to make sure we didn't break
the output content of strace.
The 2nd,3rd comparison may be different which remind us our implementation
need to be checked to see why we got this different.

Note: All the comparison may be different in some cases that the traced
results are random depending the runtime. You'd better install wdiff and
colordiff to make the output looks better.

* test/json_parse.py(newfile): I use python to parse the JSON output of
strace, you can also see this file for an example for parsing the JSON output.

* test/json_test.sh(newfile): The test main control, just run this script
under test to start all the test.
---
 test/json_parse.py | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/json_test.sh  |  68 +++++++++++++++++++++++++
 2 files changed, 214 insertions(+)
 create mode 100755 test/json_parse.py
 create mode 100755 test/json_test.sh

diff --git a/test/json_parse.py b/test/json_parse.py
new file mode 100755
index 0000000..d75e254
--- /dev/null
+++ b/test/json_parse.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python
+import json
+from sys import argv
+from sys import stdout
+from sys import stderr
+
+
+def arg_printfd(fd):
+	if type(fd) == list:
+		# when -y option is enabled
+		stdout.write(fd[0] + "<" + fd[1] + ">")
+	else:
+		stdout.write(fd)
+
+def arg_iov(iovs):
+	stdout.write("[")
+	first = True
+	for i in iovs:
+		if not first:
+			stdout.write(", ")
+		stdout.write("{")
+		stdout.write(i[0] + ", " + i[1])
+		stdout.write("}")
+		first = False
+	stdout.write("]")
+
+def arg_iop(iop):
+	first = True
+	for i in iop:
+		if not first:
+			stdout.write(" or ")
+		first = False
+		stdout.write(i)
+
+def arg_simple(arg):
+	stdout.write(arg if arg is not None else "NULL")
+
+def arg_print_off_t(arg):
+	if not arg:
+		stdout.write("NULL")
+	elif arg.startswith("0x"):
+		stdout.write(arg)
+	else:
+		stdout.write("[" + arg + "]")
+
+def choose(*args):
+	first_type = args[0]
+	fun_list = args[1]
+	fun_def = args[2]
+
+	def real_fun(arg):
+		if type(arg) == first_type:
+			fun_list(arg)
+		else:
+			fun_def(arg)
+
+	return real_fun
+
+
+arg_fun_table = {
+	"read"			:	[arg_printfd, arg_simple, arg_simple],
+	"write"			:	[arg_printfd, arg_simple, arg_simple],
+	"readv"			:	[arg_printfd, choose(list, arg_iov, arg_simple), arg_simple],
+	"writev"		:	[arg_printfd, choose(list, arg_iov, arg_simple), arg_simple],
+	"pread"			:	[arg_printfd, arg_simple, arg_simple, arg_simple],
+	"pwrite"		:	[arg_printfd, arg_simple, arg_simple, arg_simple],
+	"preadv"		:	[arg_printfd, choose(list, arg_iov, arg_simple), arg_simple, arg_simple],
+	"pwritev"		:	[arg_printfd, choose(list, arg_iov, arg_simple), arg_simple, arg_simple],
+	"sendfile"		:	[arg_printfd, arg_printfd, arg_print_off_t, arg_simple],
+	"sendfile64"	:	[arg_printfd, arg_printfd, arg_print_off_t, arg_simple],
+	"tee"			:	[arg_printfd, arg_printfd, arg_simple, arg_simple],
+	"splice"		:	[arg_printfd, arg_simple, arg_printfd, arg_simple, arg_simple, arg_simple],
+	"vmsplice"		:	[arg_printfd, arg_iov, arg_simple, arg_simple],
+	"ioctl"			:	[arg_printfd, choose(list, arg_iop, arg_simple), arg_simple, arg_simple],
+}
+
+
+def arg_default(obj):
+	outstr = ", ".join(obj)
+	stdout.write(outstr)
+
+
+def syscall(entry):
+		stdout.write(entry["name"])
+		stdout.write("(")
+		if entry["name"] in arg_fun_table:
+			i = 0
+			for arg in entry["args"]:
+				if i > 0:
+					# special case for ioctl()
+					if i == 2 and entry["name"] == "ioctl":
+						# the 3rd argument of ioctl() itself contain a ', '
+						pass
+					else:
+						stdout.write(", ")
+				arg_fun_table[entry["name"]][i](arg)
+				i += 1
+		else:
+			arg_default(entry["args"])
+		stdout.write(")")
+
+		stdout.write(" = " + entry["ret"])
+		if ("desc" in entry):
+			stdout.write(" " + entry["desc"])
+		if ("desc_long" in entry):
+			stdout.write(" (" + entry["desc_long"] + ")")
+		if ("auxstr" in entry):
+			stdout.write(" (" + entry["auxstr"] + ")")
+		stdout.write("\n")
+
+
+# this is for the +++ signal, should rename..
+def plusplusplus(entry):
+	print "+++ " + entry["desc"] + " with " + entry["sigcode"] + " +++"
+
+
+def main(infile, options):
+	with open(infile) as f:
+		for i, line in enumerate(f):
+			try:
+				entry = json.loads(line)
+			except ValueError as e:
+				stderr.write("<Error> JSON format invalid!\n")
+				stderr.write("  File:" + infile + ", line:" + str(i+1) + "\n")
+				stderr.write("  " + line + "\n")
+				raise ValueError
+			try:
+				if (entry["type"] == "syscall"):
+					syscall(entry)
+				elif (entry["type"] == "+++"):
+					plusplusplus(entry)
+				else:
+					raise ValueError
+			except Exception:
+				stderr.write("<Error> Failed to parse output!\n")
+				stderr.write("  File:" + infile + ", line:" + str(i+1) + "\n")
+				stderr.write("  " + line + "\n")
+
+
+if __name__ == "__main__":
+	options = {}
+	for o in argv[1:-1]:
+		if o == "-y":
+			options["y"] = True
+	# in fact, the options here is not used explicitly
+	main(argv[-1], options)
diff --git a/test/json_test.sh b/test/json_test.sh
new file mode 100755
index 0000000..0738220
--- /dev/null
+++ b/test/json_test.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+set -u
+
+Unmodified_Strace="strace -y"
+Normal_Strace="../strace -y"
+JSON_Strace="../strace -j -y"
+
+TEMPDIR=${TEMPDIR:-"./temp_results"}
+SYSCALLS=${SYSCALLS:-""}
+FLAGS=${FLAGS:-""}
+TARGETS=${TARGETS:-""}
+
+JSON_PARSER="./json_parse.py"
+
+function simple_diff()
+{
+	diff $1 $2
+}
+function adv_diff()
+{
+	wdiff -3 $1 $2 | colordiff
+}
+
+DODIFF="simple_diff"
+if type colordiff &> /dev/null; then
+	if type wdiff &> /dev/null; then
+		DODIFF="adv_diff"
+	fi
+fi
+
+$DODIFF "lala"
+
+mkdir -p $TEMPDIR
+
+function start_test() {
+	for i in $TARGETS; do
+		echo "--- --- --- ---"
+		echo "generating trace results for $i"
+		$Unmodified_Strace -o "$TEMPDIR/$i-raw-unmodified" $SYSCALLS $FLAGS ./$i
+		$Normal_Strace -o "$TEMPDIR/$i-raw-normal" $SYSCALLS $FLAGS ./$i
+		$JSON_Strace -o "$TEMPDIR/$i-json-GSOC" $SYSCALLS $FLAGS ./$i
+		$JSON_PARSER "$TEMPDIR/$i-json-GSOC" > "$TEMPDIR/$i-raw-GSOC"
+
+		echo "> comparing $i-raw-unmodified $i-raw-normal results:"
+		$DODIFF "$TEMPDIR/$i-raw-unmodified" "$TEMPDIR/$i-raw-normal"
+
+		echo -e "\n> comparing $i-raw-unmodified $i-raw-GSOC results(ignore all white space):"
+		$DODIFF "$TEMPDIR/$i-raw-unmodified" "$TEMPDIR/$i-raw-GSOC"
+
+		echo -e "\n> comparing $i-raw-normal $i-raw-GSOC results(ignore all white space):"
+		$DODIFF "$TEMPDIR/$i-raw-normal" "$TEMPDIR/$i-raw-GSOC"
+		echo -e "--- --- --- ---\n"
+	done
+}
+
+# test for io-related syscall
+IO_SYSCALL="-e read,write,readv,writev,pread,pwrite,preadv,pwritev,sendfile,sendfile64,tee,splice,vmsplice,ioctl"
+SYSCALLS=$IO_SYSCALL
+TARGETS="json_io mtd ubi select"
+start_test
+
+# test for fork-related syscall
+FLAGS="-ff"
+TARGETS="vfork fork clone childthread threaded_execve"
+
+# test for other syscall
+FLAGS=""
+TARGETS="sig skodic clone leaderkill childthread sigkill_rain wait_must_be_interruptible sigreturn"
-- 
1.9.1





More information about the Strace-devel mailing list