trace2: t/helper/test-trace2, t0210.sh, t0211.sh, t0212.sh
Create unit tests for Trace2. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									b3a5d5a80c
								
							
						
					
					
						commit
						a15860dca3
					
				
							
								
								
									
										1
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										1
									
								
								Makefile
								
								
								
								
							|  | @ -773,6 +773,7 @@ TEST_BUILTINS_OBJS += test-string-list.o | ||||||
| TEST_BUILTINS_OBJS += test-submodule-config.o | TEST_BUILTINS_OBJS += test-submodule-config.o | ||||||
| TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o | TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o | ||||||
| TEST_BUILTINS_OBJS += test-subprocess.o | TEST_BUILTINS_OBJS += test-subprocess.o | ||||||
|  | TEST_BUILTINS_OBJS += test-trace2.o | ||||||
| TEST_BUILTINS_OBJS += test-urlmatch-normalization.o | TEST_BUILTINS_OBJS += test-urlmatch-normalization.o | ||||||
| TEST_BUILTINS_OBJS += test-xml-encode.o | TEST_BUILTINS_OBJS += test-xml-encode.o | ||||||
| TEST_BUILTINS_OBJS += test-wildmatch.o | TEST_BUILTINS_OBJS += test-wildmatch.o | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ static struct test_cmd cmds[] = { | ||||||
| 	{ "submodule-config", cmd__submodule_config }, | 	{ "submodule-config", cmd__submodule_config }, | ||||||
| 	{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config }, | 	{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config }, | ||||||
| 	{ "subprocess", cmd__subprocess }, | 	{ "subprocess", cmd__subprocess }, | ||||||
|  | 	{ "trace2", cmd__trace2 }, | ||||||
| 	{ "urlmatch-normalization", cmd__urlmatch_normalization }, | 	{ "urlmatch-normalization", cmd__urlmatch_normalization }, | ||||||
| 	{ "xml-encode", cmd__xml_encode }, | 	{ "xml-encode", cmd__xml_encode }, | ||||||
| 	{ "wildmatch", cmd__wildmatch }, | 	{ "wildmatch", cmd__wildmatch }, | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ int cmd__string_list(int argc, const char **argv); | ||||||
| int cmd__submodule_config(int argc, const char **argv); | int cmd__submodule_config(int argc, const char **argv); | ||||||
| int cmd__submodule_nested_repo_config(int argc, const char **argv); | int cmd__submodule_nested_repo_config(int argc, const char **argv); | ||||||
| int cmd__subprocess(int argc, const char **argv); | int cmd__subprocess(int argc, const char **argv); | ||||||
|  | int cmd__trace2(int argc, const char **argv); | ||||||
| int cmd__urlmatch_normalization(int argc, const char **argv); | int cmd__urlmatch_normalization(int argc, const char **argv); | ||||||
| int cmd__xml_encode(int argc, const char **argv); | int cmd__xml_encode(int argc, const char **argv); | ||||||
| int cmd__wildmatch(int argc, const char **argv); | int cmd__wildmatch(int argc, const char **argv); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,273 @@ | ||||||
|  | #include "test-tool.h" | ||||||
|  | #include "cache.h" | ||||||
|  | #include "argv-array.h" | ||||||
|  | #include "run-command.h" | ||||||
|  | #include "exec-cmd.h" | ||||||
|  | #include "config.h" | ||||||
|  |  | ||||||
|  | typedef int(fn_unit_test)(int argc, const char **argv); | ||||||
|  |  | ||||||
|  | struct unit_test { | ||||||
|  | 	fn_unit_test *ut_fn; | ||||||
|  | 	const char *ut_name; | ||||||
|  | 	const char *ut_usage; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define MyOk 0 | ||||||
|  | #define MyError 1 | ||||||
|  |  | ||||||
|  | static int get_i(int *p_value, const char *data) | ||||||
|  | { | ||||||
|  | 	char *endptr; | ||||||
|  |  | ||||||
|  | 	if (!data || !*data) | ||||||
|  | 		return MyError; | ||||||
|  |  | ||||||
|  | 	*p_value = strtol(data, &endptr, 10); | ||||||
|  | 	if (*endptr || errno == ERANGE) | ||||||
|  | 		return MyError; | ||||||
|  |  | ||||||
|  | 	return MyOk; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cause process to exit with the requested value via "return". | ||||||
|  |  * | ||||||
|  |  * Rely on test-tool.c:cmd_main() to call trace2_cmd_exit() | ||||||
|  |  * with our result. | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm: | ||||||
|  |  * [] the process-exit value. | ||||||
|  |  * [] the "code" field in the "exit" trace2 event. | ||||||
|  |  * [] the "code" field in the "atexit" trace2 event. | ||||||
|  |  * [] the "name" field in the "cmd_name" trace2 event. | ||||||
|  |  * [] "def_param" events for all of the "interesting" pre-defined | ||||||
|  |  * config settings. | ||||||
|  |  */ | ||||||
|  | static int ut_001return(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  |  | ||||||
|  | 	if (get_i(&rc, argv[0])) | ||||||
|  | 		die("expect <exit_code>"); | ||||||
|  |  | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cause the process to exit with the requested value via "exit()". | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm: | ||||||
|  |  * [] the "code" field in the "exit" trace2 event. | ||||||
|  |  * [] the "code" field in the "atexit" trace2 event. | ||||||
|  |  * [] the "name" field in the "cmd_name" trace2 event. | ||||||
|  |  * [] "def_param" events for all of the "interesting" pre-defined | ||||||
|  |  * config settings. | ||||||
|  |  */ | ||||||
|  | static int ut_002exit(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  |  | ||||||
|  | 	if (get_i(&rc, argv[0])) | ||||||
|  | 		die("expect <exit_code>"); | ||||||
|  |  | ||||||
|  | 	exit(rc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Send an "error" event with each value in argv.  Normally, git only issues | ||||||
|  |  * a single "error" event immediately before issuing an "exit" event (such | ||||||
|  |  * as in die() or BUG()), but multiple "error" events are allowed. | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm: | ||||||
|  |  * [] a trace2 "error" event for each value in argv. | ||||||
|  |  * [] the "name" field in the "cmd_name" trace2 event. | ||||||
|  |  * [] (optional) the file:line in the "exit" event refers to this function. | ||||||
|  |  */ | ||||||
|  | static int ut_003error(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int k; | ||||||
|  |  | ||||||
|  | 	if (!argv[0] || !*argv[0]) | ||||||
|  | 		die("expect <error_message>"); | ||||||
|  |  | ||||||
|  | 	for (k = 0; k < argc; k++) | ||||||
|  | 		error("%s", argv[k]); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Run a child process and wait for it to finish and exit with its return code. | ||||||
|  |  * test-tool trace2 004child [<child-command-line>] | ||||||
|  |  * | ||||||
|  |  * For example: | ||||||
|  |  * test-tool trace2 004child git version | ||||||
|  |  * test-tool trace2 004child test-tool trace2 001return 0 | ||||||
|  |  * test-tool trace2 004child test-tool trace2 004child test-tool trace2 004child | ||||||
|  |  * test-tool trace2 004child git -c alias.xyz=version xyz | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm: | ||||||
|  |  * [] the "name" field in the "cmd_name" trace2 event. | ||||||
|  |  * [] that the outer process has a single component SID (or depth "d0" in | ||||||
|  |  *    the PERF stream). | ||||||
|  |  * [] that "child_start" and "child_exit" events are generated for the child. | ||||||
|  |  * [] if the child process is an instrumented executable: | ||||||
|  |  *    [] that "version", "start", ..., "exit", and "atexit" events are | ||||||
|  |  *       generated by the child process. | ||||||
|  |  *    [] that the child process events have a multiple component SID (or | ||||||
|  |  *       depth "dN+1" in the PERF stream). | ||||||
|  |  * [] that the child exit code is propagated to the parent process "exit" | ||||||
|  |  *    and "atexit" events.. | ||||||
|  |  * [] (optional) that the "t_abs" field in the child process "atexit" event | ||||||
|  |  *    is less than the "t_rel" field in the "child_exit" event of the parent | ||||||
|  |  *    process. | ||||||
|  |  * [] if the child process is like the alias example above, | ||||||
|  |  *    [] (optional) the child process attempts to run "git-xyx" as a dashed | ||||||
|  |  *       command. | ||||||
|  |  *    [] the child process emits an "alias" event with "xyz" => "version" | ||||||
|  |  *    [] the child process runs "git version" as a child process. | ||||||
|  |  *    [] the child process has a 3 component SID (or depth "d2" in the PERF | ||||||
|  |  *       stream). | ||||||
|  |  */ | ||||||
|  | static int ut_004child(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int result; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * Allow empty <child_command_line> so we can do arbitrarily deep | ||||||
|  | 	 * command nesting and let the last one be null. | ||||||
|  | 	 */ | ||||||
|  | 	if (!argc) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	result = run_command_v_opt(argv, 0); | ||||||
|  | 	exit(result); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Exec a git command.  This may either create a child process (Windows) | ||||||
|  |  * or replace the existing process. | ||||||
|  |  * test-tool trace2 005exec <git_command_args> | ||||||
|  |  * | ||||||
|  |  * For example: | ||||||
|  |  * test-tool trace2 005exec version | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm (on Windows): | ||||||
|  |  * [] the "name" field in the "cmd_name" trace2 event. | ||||||
|  |  * [] that the outer process has a single component SID (or depth "d0" in | ||||||
|  |  *    the PERF stream). | ||||||
|  |  * [] that "exec" and "exec_result" events are generated for the child | ||||||
|  |  *    process (since the Windows compatibility layer fakes an exec() with | ||||||
|  |  *    a CreateProcess(), WaitForSingleObject(), and exit()). | ||||||
|  |  * [] that the child process has multiple component SID (or depth "dN+1" | ||||||
|  |  *    in the PERF stream). | ||||||
|  |  * | ||||||
|  |  * Test harness can confirm (on platforms with a real exec() function): | ||||||
|  |  * [] TODO talk about process replacement and how it affects SID. | ||||||
|  |  */ | ||||||
|  | static int ut_005exec(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int result; | ||||||
|  |  | ||||||
|  | 	if (!argc) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	result = execv_git_cmd(argv); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int ut_006data(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	const char *usage_error = | ||||||
|  | 		"expect <cat0> <k0> <v0> [<cat1> <k1> <v1> [...]]"; | ||||||
|  |  | ||||||
|  | 	if (argc % 3 != 0) | ||||||
|  | 		die("%s", usage_error); | ||||||
|  |  | ||||||
|  | 	while (argc) { | ||||||
|  | 		if (!argv[0] || !*argv[0] || !argv[1] || !*argv[1] || | ||||||
|  | 		    !argv[2] || !*argv[2]) | ||||||
|  | 			die("%s", usage_error); | ||||||
|  |  | ||||||
|  | 		trace2_data_string(argv[0], the_repository, argv[1], argv[2]); | ||||||
|  | 		argv += 3; | ||||||
|  | 		argc -= 3; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Usage: | ||||||
|  |  *     test-tool trace2 <ut_name_1> <ut_usage_1> | ||||||
|  |  *     test-tool trace2 <ut_name_2> <ut_usage_2> | ||||||
|  |  *     ... | ||||||
|  |  */ | ||||||
|  | #define USAGE_PREFIX "test-tool trace2" | ||||||
|  |  | ||||||
|  | /* clang-format off */ | ||||||
|  | static struct unit_test ut_table[] = { | ||||||
|  | 	{ ut_001return,   "001return", "<exit_code>" }, | ||||||
|  | 	{ ut_002exit,     "002exit",   "<exit_code>" }, | ||||||
|  | 	{ ut_003error,    "003error",  "<error_message>+" }, | ||||||
|  | 	{ ut_004child,    "004child",  "[<child_command_line>]" }, | ||||||
|  | 	{ ut_005exec,     "005exec",   "<git_command_args>" }, | ||||||
|  | 	{ ut_006data,     "006data",   "[<category> <key> <value>]+" }, | ||||||
|  | }; | ||||||
|  | /* clang-format on */ | ||||||
|  |  | ||||||
|  | /* clang-format off */ | ||||||
|  | #define for_each_ut(k, ut_k)			\ | ||||||
|  | 	for (k = 0, ut_k = &ut_table[k];	\ | ||||||
|  | 	     k < ARRAY_SIZE(ut_table);		\ | ||||||
|  | 	     k++, ut_k = &ut_table[k]) | ||||||
|  | /* clang-format on */ | ||||||
|  |  | ||||||
|  | static int print_usage(void) | ||||||
|  | { | ||||||
|  | 	int k; | ||||||
|  | 	struct unit_test *ut_k; | ||||||
|  |  | ||||||
|  | 	fprintf(stderr, "usage:\n"); | ||||||
|  | 	for_each_ut (k, ut_k) | ||||||
|  | 		fprintf(stderr, "\t%s %s %s\n", USAGE_PREFIX, ut_k->ut_name, | ||||||
|  | 			ut_k->ut_usage); | ||||||
|  |  | ||||||
|  | 	return 129; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Issue various trace2 events for testing. | ||||||
|  |  * | ||||||
|  |  * We assume that these trace2 routines has already been called: | ||||||
|  |  *    [] trace2_initialize()      [common-main.c:main()] | ||||||
|  |  *    [] trace2_cmd_start()       [common-main.c:main()] | ||||||
|  |  *    [] trace2_cmd_name()        [test-tool.c:cmd_main()] | ||||||
|  |  *    [] tracd2_cmd_list_config() [test-tool.c:cmd_main()] | ||||||
|  |  * So that: | ||||||
|  |  *    [] the various trace2 streams are open. | ||||||
|  |  *    [] the process SID has been created. | ||||||
|  |  *    [] the "version" event has been generated. | ||||||
|  |  *    [] the "start" event has been generated. | ||||||
|  |  *    [] the "cmd_name" event has been generated. | ||||||
|  |  *    [] this writes various "def_param" events for interesting config values. | ||||||
|  |  * | ||||||
|  |  * We further assume that if we return (rather than exit()), trace2_cmd_exit() | ||||||
|  |  * will be called by test-tool.c:cmd_main(). | ||||||
|  |  */ | ||||||
|  | int cmd__trace2(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	int k; | ||||||
|  | 	struct unit_test *ut_k; | ||||||
|  |  | ||||||
|  | 	argc--; /* skip over "trace2" arg */ | ||||||
|  | 	argv++; | ||||||
|  |  | ||||||
|  | 	if (argc) | ||||||
|  | 		for_each_ut (k, ut_k) | ||||||
|  | 			if (!strcmp(argv[0], ut_k->ut_name)) | ||||||
|  | 				return ut_k->ut_fn(argc - 1, argv + 1); | ||||||
|  |  | ||||||
|  | 	return print_usage(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,135 @@ | ||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | test_description='test trace2 facility (normal target)' | ||||||
|  | . ./test-lib.sh | ||||||
|  |  | ||||||
|  | # Add t/helper directory to PATH so that we can use a relative | ||||||
|  | # path to run nested instances of test-tool.exe (see 004child). | ||||||
|  | # This helps with HEREDOC comparisons later. | ||||||
|  | TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR | ||||||
|  | PATH="$TTDIR:$PATH" && export PATH | ||||||
|  |  | ||||||
|  | # Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe | ||||||
|  | # Warning: to do the actual diff/comparison, so the HEREDOCs here | ||||||
|  | # Warning: only cover our actual calls to test-tool and/or git. | ||||||
|  | # Warning: So you may see extra lines in artifact files when | ||||||
|  | # Warning: interactively debugging. | ||||||
|  |  | ||||||
|  | # Turn off any inherited trace2 settings for this test. | ||||||
|  | unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT | ||||||
|  | unset GIT_TR2_BRIEF | ||||||
|  | unset GIT_TR2_CONFIG_PARAMS | ||||||
|  |  | ||||||
|  | V=$(git version | sed -e 's/^git version //') && export V | ||||||
|  |  | ||||||
|  | # There are multiple trace2 targets: normal, perf, and event. | ||||||
|  | # Trace2 events will/can be written to each active target (subject | ||||||
|  | # to whatever filtering that target decides to do). | ||||||
|  | # This script tests the normal target in isolation. | ||||||
|  | # | ||||||
|  | # Defer setting GIT_TR2 until the actual command line we want to test | ||||||
|  | # because hidden git and test-tool commands run by the test harness | ||||||
|  | # can contaminate our output. | ||||||
|  |  | ||||||
|  | # Enable "brief" feature which turns off "<clock> <file>:<line> " prefix. | ||||||
|  | GIT_TR2_BRIEF=1 && export GIT_TR2_BRIEF | ||||||
|  |  | ||||||
|  | # Basic tests of the trace2 normal stream.  Since this stream is used | ||||||
|  | # primarily with printf-style debugging/tracing, we do limited testing | ||||||
|  | # here. | ||||||
|  | # | ||||||
|  | # We do confirm the following API features: | ||||||
|  | # [] the 'version <v>' event | ||||||
|  | # [] the 'start <argv>' event | ||||||
|  | # [] the 'cmd_name <name>' event | ||||||
|  | # [] the 'exit <time> code:<code>' event | ||||||
|  | # [] the 'atexit <time> code:<code>' event | ||||||
|  | # | ||||||
|  | # Fields of the form _FIELD_ are tokens that have been replaced (such | ||||||
|  | # as the elapsed time). | ||||||
|  |  | ||||||
|  | # Verb 001return | ||||||
|  | # | ||||||
|  | # Implicit return from cmd_<verb> function propagates <code>. | ||||||
|  |  | ||||||
|  | test_expect_success 'normal stream, return code 0' ' | ||||||
|  | 	test_when_finished "rm trace.normal actual expect" && | ||||||
|  | 	GIT_TR2="$(pwd)/trace.normal" test-tool trace2 001return 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		version $V | ||||||
|  | 		start _EXE_ trace2 001return 0 | ||||||
|  | 		cmd_name trace2 (trace2) | ||||||
|  | 		exit elapsed:_TIME_ code:0 | ||||||
|  | 		atexit elapsed:_TIME_ code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'normal stream, return code 1' ' | ||||||
|  | 	test_when_finished "rm trace.normal actual expect" && | ||||||
|  | 	test_must_fail env GIT_TR2="$(pwd)/trace.normal" test-tool trace2 001return 1 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		version $V | ||||||
|  | 		start _EXE_ trace2 001return 1 | ||||||
|  | 		cmd_name trace2 (trace2) | ||||||
|  | 		exit elapsed:_TIME_ code:1 | ||||||
|  | 		atexit elapsed:_TIME_ code:1 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Verb 002exit | ||||||
|  | # | ||||||
|  | # Explicit exit(code) from within cmd_<verb> propagates <code>. | ||||||
|  |  | ||||||
|  | test_expect_success 'normal stream, exit code 0' ' | ||||||
|  | 	test_when_finished "rm trace.normal actual expect" && | ||||||
|  | 	GIT_TR2="$(pwd)/trace.normal" test-tool trace2 002exit 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		version $V | ||||||
|  | 		start _EXE_ trace2 002exit 0 | ||||||
|  | 		cmd_name trace2 (trace2) | ||||||
|  | 		exit elapsed:_TIME_ code:0 | ||||||
|  | 		atexit elapsed:_TIME_ code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'normal stream, exit code 1' ' | ||||||
|  | 	test_when_finished "rm trace.normal actual expect" && | ||||||
|  | 	test_must_fail env GIT_TR2="$(pwd)/trace.normal" test-tool trace2 002exit 1 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		version $V | ||||||
|  | 		start _EXE_ trace2 002exit 1 | ||||||
|  | 		cmd_name trace2 (trace2) | ||||||
|  | 		exit elapsed:_TIME_ code:1 | ||||||
|  | 		atexit elapsed:_TIME_ code:1 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Verb 003error | ||||||
|  | # | ||||||
|  | # To the above, add multiple 'error <msg>' events | ||||||
|  |  | ||||||
|  | test_expect_success 'normal stream, error event' ' | ||||||
|  | 	test_when_finished "rm trace.normal actual expect" && | ||||||
|  | 	GIT_TR2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		version $V | ||||||
|  | 		start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' | ||||||
|  | 		cmd_name trace2 (trace2) | ||||||
|  | 		error hello world | ||||||
|  | 		error this is a test | ||||||
|  | 		exit elapsed:_TIME_ code:0 | ||||||
|  | 		atexit elapsed:_TIME_ code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_done | ||||||
|  | @ -0,0 +1,48 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | # | ||||||
|  | # Scrub the variable fields from the normal trace2 output to | ||||||
|  | # make testing easier. | ||||||
|  |  | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  |  | ||||||
|  | my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?'; | ||||||
|  |  | ||||||
|  | # This code assumes that the trace2 data was written with bare | ||||||
|  | # turned on (which omits the "<clock> <file>:<line>" prefix. | ||||||
|  |  | ||||||
|  | while (<>) { | ||||||
|  |     # Various messages include an elapsed time in the middle | ||||||
|  |     # of the message.  Replace the time with a placeholder to | ||||||
|  |     # simplify our HEREDOC in the test script. | ||||||
|  |     s/elapsed:$float/elapsed:_TIME_/g; | ||||||
|  |  | ||||||
|  |     my $line = $_; | ||||||
|  |  | ||||||
|  |     # we expect: | ||||||
|  |     #    start <argv0> [<argv1> [<argv2> [...]]] | ||||||
|  |     # | ||||||
|  |     # where argv0 might be a relative or absolute path, with | ||||||
|  |     # or without quotes, and platform dependent.  Replace argv0 | ||||||
|  |     # with a token for HEREDOC matching in the test script. | ||||||
|  |  | ||||||
|  |     if ($line =~ m/^start/) { | ||||||
|  | 	$line =~ /^start\s+(.*)/; | ||||||
|  | 	my $argv = $1; | ||||||
|  | 	$argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/; | ||||||
|  | 	my $argv_0 = $1; | ||||||
|  | 	my $argv_rest = $2; | ||||||
|  |  | ||||||
|  | 	print "start _EXE_ $argv_rest\n"; | ||||||
|  |     } | ||||||
|  |     elsif ($line =~ m/^cmd_path/) { | ||||||
|  | 	# Likewise, the 'cmd_path' message breaks out argv[0]. | ||||||
|  | 	# | ||||||
|  | 	# This line is only emitted when RUNTIME_PREFIX is defined, | ||||||
|  | 	# so just omit it for testing purposes. | ||||||
|  | 	# print "cmd_path _EXE_\n"; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  | 	print "$line"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,153 @@ | ||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | test_description='test trace2 facility (perf target)' | ||||||
|  | . ./test-lib.sh | ||||||
|  |  | ||||||
|  | # Add t/helper directory to PATH so that we can use a relative | ||||||
|  | # path to run nested instances of test-tool.exe (see 004child). | ||||||
|  | # This helps with HEREDOC comparisons later. | ||||||
|  | TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR | ||||||
|  | PATH="$TTDIR:$PATH" && export PATH | ||||||
|  |  | ||||||
|  | # Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe | ||||||
|  | # Warning: to do the actual diff/comparison, so the HEREDOCs here | ||||||
|  | # Warning: only cover our actual calls to test-tool and/or git. | ||||||
|  | # Warning: So you may see extra lines in artifact files when | ||||||
|  | # Warning: interactively debugging. | ||||||
|  |  | ||||||
|  | # Turn off any inherited trace2 settings for this test. | ||||||
|  | unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT | ||||||
|  | unset GIT_TR2_PERF_BRIEF | ||||||
|  | unset GIT_TR2_CONFIG_PARAMS | ||||||
|  |  | ||||||
|  | V=$(git version | sed -e 's/^git version //') && export V | ||||||
|  |  | ||||||
|  | # There are multiple trace2 targets: normal, perf, and event. | ||||||
|  | # Trace2 events will/can be written to each active target (subject | ||||||
|  | # to whatever filtering that target decides to do). | ||||||
|  | # Test each target independently. | ||||||
|  | # | ||||||
|  | # Defer setting GIT_TR2_PERF until the actual command we want to | ||||||
|  | # test because hidden git and test-tool commands in the test | ||||||
|  | # harness can contaminate our output. | ||||||
|  |  | ||||||
|  | # Enable "brief" feature which turns off the prefix: | ||||||
|  | #     "<clock> <file>:<line> | <nr_parents> | " | ||||||
|  | GIT_TR2_PERF_BRIEF=1 && export GIT_TR2_PERF_BRIEF | ||||||
|  |  | ||||||
|  | # Repeat some of the t0210 tests using the perf target stream instead of | ||||||
|  | # the normal stream. | ||||||
|  | # | ||||||
|  | # Tokens here of the form _FIELD_ have been replaced in the observed output. | ||||||
|  |  | ||||||
|  | # Verb 001return | ||||||
|  | # | ||||||
|  | # Implicit return from cmd_<verb> function propagates <code>. | ||||||
|  |  | ||||||
|  | test_expect_success 'perf stream, return code 0' ' | ||||||
|  | 	test_when_finished "rm trace.perf actual expect" && | ||||||
|  | 	GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 001return 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		d0|main|version|||||$V | ||||||
|  | 		d0|main|start|||||_EXE_ trace2 001return 0 | ||||||
|  | 		d0|main|cmd_name|||||trace2 (trace2) | ||||||
|  | 		d0|main|exit||_T_ABS_|||code:0 | ||||||
|  | 		d0|main|atexit||_T_ABS_|||code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'perf stream, return code 1' ' | ||||||
|  | 	test_when_finished "rm trace.perf actual expect" && | ||||||
|  | 	test_must_fail env GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 001return 1 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		d0|main|version|||||$V | ||||||
|  | 		d0|main|start|||||_EXE_ trace2 001return 1 | ||||||
|  | 		d0|main|cmd_name|||||trace2 (trace2) | ||||||
|  | 		d0|main|exit||_T_ABS_|||code:1 | ||||||
|  | 		d0|main|atexit||_T_ABS_|||code:1 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Verb 003error | ||||||
|  | # | ||||||
|  | # To the above, add multiple 'error <msg>' events | ||||||
|  |  | ||||||
|  | test_expect_success 'perf stream, error event' ' | ||||||
|  | 	test_when_finished "rm trace.perf actual expect" && | ||||||
|  | 	GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 003error "hello world" "this is a test" && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		d0|main|version|||||$V | ||||||
|  | 		d0|main|start|||||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' | ||||||
|  | 		d0|main|cmd_name|||||trace2 (trace2) | ||||||
|  | 		d0|main|error|||||hello world | ||||||
|  | 		d0|main|error|||||this is a test | ||||||
|  | 		d0|main|exit||_T_ABS_|||code:0 | ||||||
|  | 		d0|main|atexit||_T_ABS_|||code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Verb 004child | ||||||
|  | # | ||||||
|  | # Test nested spawning of child processes. | ||||||
|  | # | ||||||
|  | # Conceptually, this looks like: | ||||||
|  | #    P1: TT trace2 004child | ||||||
|  | #    P2: |--- TT trace2 004child | ||||||
|  | #    P3:      |--- TT trace2 001return 0 | ||||||
|  | # | ||||||
|  | # Which should generate events: | ||||||
|  | #    P1: version | ||||||
|  | #    P1: start | ||||||
|  | #    P1: cmd_name | ||||||
|  | #    P1: child_start | ||||||
|  | #        P2: version | ||||||
|  | #        P2: start | ||||||
|  | #        P2: cmd_name | ||||||
|  | #        P2: child_start | ||||||
|  | #            P3: version | ||||||
|  | #            P3: start | ||||||
|  | #            P3: cmd_name | ||||||
|  | #            P3: exit | ||||||
|  | #            P3: atexit | ||||||
|  | #        P2: child_exit | ||||||
|  | #        P2: exit | ||||||
|  | #        P2: atexit | ||||||
|  | #    P1: child_exit | ||||||
|  | #    P1: exit | ||||||
|  | #    P1: atexit | ||||||
|  |  | ||||||
|  | test_expect_success 'perf stream, child processes' ' | ||||||
|  | 	test_when_finished "rm trace.perf actual expect" && | ||||||
|  | 	GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 004child test-tool trace2 004child test-tool trace2 001return 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && | ||||||
|  | 	cat >expect <<-EOF && | ||||||
|  | 		d0|main|version|||||$V | ||||||
|  | 		d0|main|start|||||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 | ||||||
|  | 		d0|main|cmd_name|||||trace2 (trace2) | ||||||
|  | 		d0|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 004child test-tool trace2 001return 0 | ||||||
|  | 		d1|main|version|||||$V | ||||||
|  | 		d1|main|start|||||_EXE_ trace2 004child test-tool trace2 001return 0 | ||||||
|  | 		d1|main|cmd_name|||||trace2 (trace2/trace2) | ||||||
|  | 		d1|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 001return 0 | ||||||
|  | 		d2|main|version|||||$V | ||||||
|  | 		d2|main|start|||||_EXE_ trace2 001return 0 | ||||||
|  | 		d2|main|cmd_name|||||trace2 (trace2/trace2/trace2) | ||||||
|  | 		d2|main|exit||_T_ABS_|||code:0 | ||||||
|  | 		d2|main|atexit||_T_ABS_|||code:0 | ||||||
|  | 		d1|main|child_exit||_T_ABS_|_T_REL_||[ch0] pid:_PID_ code:0 | ||||||
|  | 		d1|main|exit||_T_ABS_|||code:0 | ||||||
|  | 		d1|main|atexit||_T_ABS_|||code:0 | ||||||
|  | 		d0|main|child_exit||_T_ABS_|_T_REL_||[ch0] pid:_PID_ code:0 | ||||||
|  | 		d0|main|exit||_T_ABS_|||code:0 | ||||||
|  | 		d0|main|atexit||_T_ABS_|||code:0 | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_done | ||||||
|  | @ -0,0 +1,76 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | # | ||||||
|  | # Scrub the variable fields from the perf trace2 output to | ||||||
|  | # make testing easier. | ||||||
|  |  | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  |  | ||||||
|  | my $qpath = '\'[^\']*\'|[^ ]*'; | ||||||
|  |  | ||||||
|  | my $col_depth=0; | ||||||
|  | my $col_thread=1; | ||||||
|  | my $col_event=2; | ||||||
|  | my $col_repo=3; | ||||||
|  | my $col_t_abs=4; | ||||||
|  | my $col_t_rel=5; | ||||||
|  | my $col_category=6; | ||||||
|  | my $col_rest=7; | ||||||
|  |  | ||||||
|  | # This code assumes that the trace2 data was written with bare | ||||||
|  | # turned on (which omits the "<clock> <file>:<line> | <parents>" | ||||||
|  | # prefix. | ||||||
|  |  | ||||||
|  | while (<>) { | ||||||
|  |     my @tokens = split /\|/; | ||||||
|  |  | ||||||
|  |     foreach my $col (@tokens) { $col =~ s/^\s+|\s+$//g; } | ||||||
|  |  | ||||||
|  |     if ($tokens[$col_event] =~ m/^start/) { | ||||||
|  | 	# The 'start' message lists the contents of argv in $col_rest. | ||||||
|  | 	# On some platforms (Windows), argv[0] is *sometimes* a canonical | ||||||
|  | 	# absolute path to the EXE rather than the value passed in the | ||||||
|  | 	# shell script.  Replace it with a placeholder to simplify our | ||||||
|  | 	# HEREDOC in the test script. | ||||||
|  | 	my $argv0; | ||||||
|  | 	my $argvRest; | ||||||
|  | 	$tokens[$col_rest] =~ s/^($qpath)\W*(.*)/_EXE_ $2/; | ||||||
|  |     } | ||||||
|  |     elsif ($tokens[$col_event] =~ m/cmd_path/) { | ||||||
|  | 	# Likewise, the 'cmd_path' message breaks out argv[0]. | ||||||
|  | 	# | ||||||
|  | 	# This line is only emitted when RUNTIME_PREFIX is defined, | ||||||
|  | 	# so just omit it for testing purposes. | ||||||
|  | 	# $tokens[$col_rest] = "_EXE_"; | ||||||
|  | 	goto SKIP_LINE; | ||||||
|  |     } | ||||||
|  |     elsif ($tokens[$col_event] =~ m/child_exit/) { | ||||||
|  | 	$tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /; | ||||||
|  |     } | ||||||
|  |     elsif ($tokens[$col_event] =~ m/data/) { | ||||||
|  | 	if ($tokens[$col_category] =~ m/process/) { | ||||||
|  | 	    # 'data' and 'data_json' events containing 'process' | ||||||
|  | 	    # category data are assumed to be platform-specific | ||||||
|  | 	    # and highly variable.  Just omit them. | ||||||
|  | 	    goto SKIP_LINE; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # t_abs and t_rel are either blank or a float.  Replace the float | ||||||
|  |     # with a constant for matching the HEREDOC in the test script. | ||||||
|  |     if ($tokens[$col_t_abs] =~ m/\d/) { | ||||||
|  | 	$tokens[$col_t_abs] = "_T_ABS_"; | ||||||
|  |     } | ||||||
|  |     if ($tokens[$col_t_rel] =~ m/\d/) { | ||||||
|  | 	$tokens[$col_t_rel] = "_T_REL_"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     my $out; | ||||||
|  |  | ||||||
|  |     $out = join('|', @tokens); | ||||||
|  |     print "$out\n"; | ||||||
|  |  | ||||||
|  |   SKIP_LINE: | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,236 @@ | ||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | test_description='test trace2 facility' | ||||||
|  | . ./test-lib.sh | ||||||
|  |  | ||||||
|  | perl -MJSON::PP -e 0 >/dev/null 2>&1 && test_set_prereq JSON_PP | ||||||
|  |  | ||||||
|  | # Add t/helper directory to PATH so that we can use a relative | ||||||
|  | # path to run nested instances of test-tool.exe (see 004child). | ||||||
|  | # This helps with HEREDOC comparisons later. | ||||||
|  | TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR | ||||||
|  | PATH="$TTDIR:$PATH" && export PATH | ||||||
|  |  | ||||||
|  | # Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe | ||||||
|  | # Warning: to do the actual diff/comparison, so the HEREDOCs here | ||||||
|  | # Warning: only cover our actual calls to test-tool and/or git. | ||||||
|  | # Warning: So you may see extra lines in artifact files when | ||||||
|  | # Warning: interactively debugging. | ||||||
|  |  | ||||||
|  | # Turn off any inherited trace2 settings for this test. | ||||||
|  | unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT | ||||||
|  | unset GIT_TR2_BARE | ||||||
|  | unset GIT_TR2_CONFIG_PARAMS | ||||||
|  |  | ||||||
|  | V=$(git version | sed -e 's/^git version //') && export V | ||||||
|  |  | ||||||
|  | # There are multiple trace2 targets: normal, perf, and event. | ||||||
|  | # Trace2 events will/can be written to each active target (subject | ||||||
|  | # to whatever filtering that target decides to do). | ||||||
|  | # Test each target independently. | ||||||
|  | # | ||||||
|  | # Defer setting GIT_TR2_PERF until the actual command we want to | ||||||
|  | # test because hidden git and test-tool commands in the test | ||||||
|  | # harness can contaminate our output. | ||||||
|  |  | ||||||
|  | # We don't bother repeating the 001return and 002exit tests, since they | ||||||
|  | # have coverage in the normal and perf targets. | ||||||
|  |  | ||||||
|  | # Verb 003error | ||||||
|  | # | ||||||
|  | # To the above, add multiple 'error <msg>' events | ||||||
|  |  | ||||||
|  | test_expect_success JSON_PP 'event stream, error event' ' | ||||||
|  | 	test_when_finished "rm trace.event actual expect" && | ||||||
|  | 	GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 003error "hello world" "this is a test" && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && | ||||||
|  | 	sed -e "s/^|//" >expect <<-EOF && | ||||||
|  | 	|VAR1 = { | ||||||
|  | 	|  "_SID0_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "003error", | ||||||
|  | 	|      "hello world", | ||||||
|  | 	|      "this is a test" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "errors":[ | ||||||
|  | 	|      "%s", | ||||||
|  | 	|      "%s" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  } | ||||||
|  | 	|}; | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Verb 004child | ||||||
|  | # | ||||||
|  | # Test nested spawning of child processes. | ||||||
|  | # | ||||||
|  | # Conceptually, this looks like: | ||||||
|  | #    P1: TT trace2 004child | ||||||
|  | #    P2: |--- TT trace2 004child | ||||||
|  | #    P3:      |--- TT trace2 001return 0 | ||||||
|  |  | ||||||
|  | test_expect_success JSON_PP 'event stream, return code 0' ' | ||||||
|  | 	test_when_finished "rm trace.event actual expect" && | ||||||
|  | 	GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 004child test-tool trace2 004child test-tool trace2 001return 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && | ||||||
|  | 	sed -e "s/^|//" >expect <<-EOF && | ||||||
|  | 	|VAR1 = { | ||||||
|  | 	|  "_SID0_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "004child", | ||||||
|  | 	|      "test-tool", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "004child", | ||||||
|  | 	|      "test-tool", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "001return", | ||||||
|  | 	|      "0" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "child":{ | ||||||
|  | 	|      "0":{ | ||||||
|  | 	|        "child_argv":[ | ||||||
|  | 	|          "_EXE_", | ||||||
|  | 	|          "trace2", | ||||||
|  | 	|          "004child", | ||||||
|  | 	|          "test-tool", | ||||||
|  | 	|          "trace2", | ||||||
|  | 	|          "001return", | ||||||
|  | 	|          "0" | ||||||
|  | 	|        ], | ||||||
|  | 	|        "child_class":"?", | ||||||
|  | 	|        "child_code":0, | ||||||
|  | 	|        "use_shell":0 | ||||||
|  | 	|      } | ||||||
|  | 	|    }, | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  }, | ||||||
|  | 	|  "_SID0_/_SID1_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "004child", | ||||||
|  | 	|      "test-tool", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "001return", | ||||||
|  | 	|      "0" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "child":{ | ||||||
|  | 	|      "0":{ | ||||||
|  | 	|        "child_argv":[ | ||||||
|  | 	|          "_EXE_", | ||||||
|  | 	|          "trace2", | ||||||
|  | 	|          "001return", | ||||||
|  | 	|          "0" | ||||||
|  | 	|        ], | ||||||
|  | 	|        "child_class":"?", | ||||||
|  | 	|        "child_code":0, | ||||||
|  | 	|        "use_shell":0 | ||||||
|  | 	|      } | ||||||
|  | 	|    }, | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2/trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  }, | ||||||
|  | 	|  "_SID0_/_SID1_/_SID2_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "001return", | ||||||
|  | 	|      "0" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2/trace2/trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  } | ||||||
|  | 	|}; | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | # Test listing of all "interesting" config settings. | ||||||
|  |  | ||||||
|  | test_expect_success JSON_PP 'event stream, list config' ' | ||||||
|  | 	test_when_finished "rm trace.event actual expect" && | ||||||
|  | 	git config --local t0212.abc 1 && | ||||||
|  | 	git config --local t0212.def "hello world" && | ||||||
|  | 	GIT_TR2_EVENT="$(pwd)/trace.event" GIT_TR2_CONFIG_PARAMS="t0212.*" test-tool trace2 001return 0 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && | ||||||
|  | 	sed -e "s/^|//" >expect <<-EOF && | ||||||
|  | 	|VAR1 = { | ||||||
|  | 	|  "_SID0_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "001return", | ||||||
|  | 	|      "0" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "params":[ | ||||||
|  | 	|      { | ||||||
|  | 	|        "param":"t0212.abc", | ||||||
|  | 	|        "value":"1" | ||||||
|  | 	|      }, | ||||||
|  | 	|      { | ||||||
|  | 	|        "param":"t0212.def", | ||||||
|  | 	|        "value":"hello world" | ||||||
|  | 	|      } | ||||||
|  | 	|    ], | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  } | ||||||
|  | 	|}; | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success JSON_PP 'basic trace2_data' ' | ||||||
|  | 	test_when_finished "rm trace.event actual expect" && | ||||||
|  | 	GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 006data test_category k1 v1 test_category k2 v2 && | ||||||
|  | 	perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && | ||||||
|  | 	sed -e "s/^|//" >expect <<-EOF && | ||||||
|  | 	|VAR1 = { | ||||||
|  | 	|  "_SID0_":{ | ||||||
|  | 	|    "argv":[ | ||||||
|  | 	|      "_EXE_", | ||||||
|  | 	|      "trace2", | ||||||
|  | 	|      "006data", | ||||||
|  | 	|      "test_category", | ||||||
|  | 	|      "k1", | ||||||
|  | 	|      "v1", | ||||||
|  | 	|      "test_category", | ||||||
|  | 	|      "k2", | ||||||
|  | 	|      "v2" | ||||||
|  | 	|    ], | ||||||
|  | 	|    "data":{ | ||||||
|  | 	|      "test_category":{ | ||||||
|  | 	|        "k1":"v1", | ||||||
|  | 	|        "k2":"v2" | ||||||
|  | 	|      } | ||||||
|  | 	|    }, | ||||||
|  | 	|    "exit_code":0, | ||||||
|  | 	|    "hierarchy":"trace2", | ||||||
|  | 	|    "name":"trace2", | ||||||
|  | 	|    "version":"$V" | ||||||
|  | 	|  } | ||||||
|  | 	|}; | ||||||
|  | 	EOF | ||||||
|  | 	test_cmp expect actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_done | ||||||
|  | @ -0,0 +1,251 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | # | ||||||
|  | # Parse event stream and convert individual events into a summary | ||||||
|  | # record for the process. | ||||||
|  | # | ||||||
|  | # Git.exe generates one or more "event" records for each API method, | ||||||
|  | # such as "start <argv>" and "exit <code>", during the life of the git | ||||||
|  | # process.  Additionally, the input may contain interleaved events | ||||||
|  | # from multiple concurrent git processes and/or multiple threads from | ||||||
|  | # within a git process. | ||||||
|  | # | ||||||
|  | # Accumulate events for each process (based on its unique SID) in a | ||||||
|  | # dictionary and emit process summary records. | ||||||
|  | # | ||||||
|  | # Convert some of the variable fields (such as elapsed time) into | ||||||
|  | # placeholders (or omit them) to make HEREDOC comparisons easier in | ||||||
|  | # the test scripts. | ||||||
|  | # | ||||||
|  | # We may also omit fields not (currently) useful for testing purposes. | ||||||
|  |  | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | use JSON::PP; | ||||||
|  | use Data::Dumper; | ||||||
|  | use Getopt::Long; | ||||||
|  |  | ||||||
|  | # The version of the trace2 event target format that we understand. | ||||||
|  | # This is reported in the 'version' event in the 'evt' field. | ||||||
|  | # It comes from the GIT_TR2_EVENT_VERSION macro in trace2/tr2_tgt_event.c | ||||||
|  | my $evt_version = '1'; | ||||||
|  |  | ||||||
|  | my $show_children = 1; | ||||||
|  | my $show_exec     = 1; | ||||||
|  | my $show_threads  = 1; | ||||||
|  |  | ||||||
|  | # A hack to generate test HEREDOC data for pasting into the test script. | ||||||
|  | # Usage: | ||||||
|  | #    cd "t/trash directory.t0212-trace2-event" | ||||||
|  | #    $TT trace ... >trace.event | ||||||
|  | #    VV=$(../../git.exe version | sed -e 's/^git version //') | ||||||
|  | #    perl ../t0212/parse_events.perl --HEREDOC --VERSION=$VV <trace.event >heredoc | ||||||
|  | # Then paste heredoc into your new test. | ||||||
|  |  | ||||||
|  | my $gen_heredoc = 0; | ||||||
|  | my $gen_version = ''; | ||||||
|  |  | ||||||
|  | GetOptions("children!" => \$show_children, | ||||||
|  | 	   "exec!"     => \$show_exec, | ||||||
|  | 	   "threads!"  => \$show_threads, | ||||||
|  | 	   "HEREDOC!"  => \$gen_heredoc, | ||||||
|  | 	   "VERSION=s" => \$gen_version    ) | ||||||
|  |     or die("Error in command line arguments\n"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # SIDs contains timestamps and PIDs of the process and its parents. | ||||||
|  | # This makes it difficult to match up in a HEREDOC in the test script. | ||||||
|  | # Build a map from actual SIDs to predictable constant values and yet | ||||||
|  | # keep the parent/child relationships.  For example: | ||||||
|  | # {..., "sid":"1539706952458276-8652", ...} | ||||||
|  | # {..., "sid":"1539706952458276-8652/1539706952649493-15452", ...} | ||||||
|  | # becomes: | ||||||
|  | # {..., "sid":"_SID1_", ...} | ||||||
|  | # {..., "sid":"_SID1_/_SID2_", ...} | ||||||
|  | my $sid_map; | ||||||
|  | my $sid_count = 0; | ||||||
|  |  | ||||||
|  | my $processes; | ||||||
|  |  | ||||||
|  | while (<>) { | ||||||
|  |     my $line = decode_json( $_ ); | ||||||
|  |  | ||||||
|  |     my $sid = ""; | ||||||
|  |     my $sid_sep = ""; | ||||||
|  |  | ||||||
|  |     my $raw_sid = $line->{'sid'}; | ||||||
|  |     my @raw_sid_parts = split /\//, $raw_sid; | ||||||
|  |     foreach my $raw_sid_k (@raw_sid_parts) { | ||||||
|  | 	if (!exists $sid_map->{$raw_sid_k}) { | ||||||
|  | 	    $sid_map->{$raw_sid_k} = '_SID' . $sid_count . '_'; | ||||||
|  | 	    $sid_count++; | ||||||
|  | 	} | ||||||
|  | 	$sid = $sid . $sid_sep . $sid_map->{$raw_sid_k}; | ||||||
|  | 	$sid_sep = '/'; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     my $event = $line->{'event'}; | ||||||
|  |  | ||||||
|  |     if ($event eq 'version') { | ||||||
|  | 	$processes->{$sid}->{'version'} = $line->{'exe'}; | ||||||
|  | 	if ($gen_heredoc == 1 && $gen_version eq $line->{'exe'}) { | ||||||
|  | 	    # If we are generating data FOR the test script, replace | ||||||
|  | 	    # the reported git.exe version with a reference to an | ||||||
|  | 	    # environment variable.  When our output is pasted into | ||||||
|  | 	    # the test script, it will then be expanded in future | ||||||
|  | 	    # test runs to the THEN current version of git.exe. | ||||||
|  | 	    # We assume that the test script uses env var $V. | ||||||
|  | 	    $processes->{$sid}->{'version'} = "\$V"; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'start') { | ||||||
|  | 	$processes->{$sid}->{'argv'} = $line->{'argv'}; | ||||||
|  | 	$processes->{$sid}->{'argv'}[0] = "_EXE_"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'exit') { | ||||||
|  | 	$processes->{$sid}->{'exit_code'} = $line->{'code'}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'atexit') { | ||||||
|  | 	$processes->{$sid}->{'exit_code'} = $line->{'code'}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'error') { | ||||||
|  | 	# For HEREDOC purposes, use the error message format string if | ||||||
|  | 	# available, rather than the formatted message (which probably | ||||||
|  | 	# has an absolute pathname). | ||||||
|  | 	if (exists $line->{'fmt'}) { | ||||||
|  | 	    push( @{$processes->{$sid}->{'errors'}}, $line->{'fmt'} ); | ||||||
|  | 	} | ||||||
|  | 	elsif (exists $line->{'msg'}) { | ||||||
|  | 	    push( @{$processes->{$sid}->{'errors'}}, $line->{'msg'} ); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'cmd_path') { | ||||||
|  | 	## $processes->{$sid}->{'path'} = $line->{'path'}; | ||||||
|  | 	# | ||||||
|  | 	# Like in the 'start' event, we need to replace the value of | ||||||
|  | 	# argv[0] with a token for HEREDOC purposes.  However, the | ||||||
|  | 	# event is only emitted when RUNTIME_PREFIX is defined, so | ||||||
|  | 	# just omit it for testing purposes. | ||||||
|  | 	# $processes->{$sid}->{'path'} = "_EXE_"; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     elsif ($event eq 'cmd_name') { | ||||||
|  | 	$processes->{$sid}->{'name'} = $line->{'name'}; | ||||||
|  | 	$processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'alias') { | ||||||
|  | 	$processes->{$sid}->{'alias'}->{'key'} = $line->{'alias'}; | ||||||
|  | 	$processes->{$sid}->{'alias'}->{'argv'} = $line->{'argv'}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'def_param') { | ||||||
|  | 	my $kv; | ||||||
|  | 	$kv->{'param'} = $line->{'param'}; | ||||||
|  | 	$kv->{'value'} = $line->{'value'}; | ||||||
|  | 	push( @{$processes->{$sid}->{'params'}}, $kv ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'child_start') { | ||||||
|  | 	if ($show_children == 1) { | ||||||
|  | 	    $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_class'} = $line->{'child_class'}; | ||||||
|  | 	    $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_argv'} = $line->{'argv'}; | ||||||
|  | 	    $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_argv'}[0] = "_EXE_"; | ||||||
|  | 	    $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'use_shell'} = $line->{'use_shell'} ? 1 : 0; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'child_exit') { | ||||||
|  | 	if ($show_children == 1) { | ||||||
|  | 	    $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_code'} = $line->{'code'}; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # TODO decide what information we want to test from thread events. | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'thread_start') { | ||||||
|  | 	if ($show_threads == 1) { | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'thread_exit') { | ||||||
|  | 	if ($show_threads == 1) { | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # TODO decide what information we want to test from exec events. | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'exec') { | ||||||
|  | 	if ($show_exec == 1) { | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'exec_result') { | ||||||
|  | 	if ($show_exec == 1) { | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'def_param') { | ||||||
|  | 	# Accumulate parameter key/value pairs by key rather than in an array | ||||||
|  | 	# so that we get overwrite (last one wins) effects. | ||||||
|  | 	$processes->{$sid}->{'params'}->{$line->{'param'}} = $line->{'value'}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'def_repo') { | ||||||
|  | 	# $processes->{$sid}->{'repos'}->{$line->{'repo'}} = $line->{'worktree'}; | ||||||
|  | 	$processes->{$sid}->{'repos'}->{$line->{'repo'}} = "_WORKTREE_"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # A series of potentially nested and threaded region and data events | ||||||
|  |     # is fundamentally incompatibile with the type of summary record we | ||||||
|  |     # are building in this script.  Since they are intended for | ||||||
|  |     # perf-trace-like analysis rather than a result summary, we ignore | ||||||
|  |     # most of them here. | ||||||
|  |  | ||||||
|  |     # elsif ($event eq 'region_enter') { | ||||||
|  |     # } | ||||||
|  |     # elsif ($event eq 'region_leave') { | ||||||
|  |     # } | ||||||
|  |  | ||||||
|  |     elsif ($event eq 'data') { | ||||||
|  | 	my $cat = $line->{'category'}; | ||||||
|  | 	if ($cat eq 'test_category') { | ||||||
|  | 	     | ||||||
|  | 	    my $key = $line->{'key'}; | ||||||
|  | 	    my $value = $line->{'value'}; | ||||||
|  | 	    $processes->{$sid}->{'data'}->{$cat}->{$key} = $value; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # This trace2 target does not emit 'printf' events. | ||||||
|  |     # | ||||||
|  |     # elsif ($event eq 'printf') { | ||||||
|  |     # } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # Dump the resulting hash into something that we can compare against | ||||||
|  | # in the test script.  These options make Dumper output look a little | ||||||
|  | # bit like JSON.  Also convert variable references of the form "$VAR*" | ||||||
|  | # so that the matching HEREDOC doesn't need to escape it. | ||||||
|  |  | ||||||
|  | $Data::Dumper::Sortkeys = 1; | ||||||
|  | $Data::Dumper::Indent = 1; | ||||||
|  | $Data::Dumper::Purity = 1; | ||||||
|  | $Data::Dumper::Pair = ':'; | ||||||
|  |  | ||||||
|  | my $out = Dumper($processes); | ||||||
|  | $out =~ s/'/"/g; | ||||||
|  | $out =~ s/\$VAR/VAR/g; | ||||||
|  |  | ||||||
|  | # Finally, if we're running this script to generate (manually confirmed) | ||||||
|  | # data to add to the test script, guard the indentation. | ||||||
|  |  | ||||||
|  | if ($gen_heredoc == 1) { | ||||||
|  |     $out =~ s/^/\t\|/gms; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | print $out; | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jeff Hostetler
						Jeff Hostetler