Skip to content

Commit ba1e59f

Browse files
committed
trace2: t/helper/test-trace2
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
1 parent 7336c10 commit ba1e59f

File tree

10 files changed

+1175
-0
lines changed

10 files changed

+1175
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,7 @@ TEST_BUILTINS_OBJS += test-string-list.o
756756
TEST_BUILTINS_OBJS += test-submodule-config.o
757757
TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
758758
TEST_BUILTINS_OBJS += test-subprocess.o
759+
TEST_BUILTINS_OBJS += test-trace2.o
759760
TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
760761
TEST_BUILTINS_OBJS += test-wildmatch.o
761762
TEST_BUILTINS_OBJS += test-windows-named-pipe.o

t/helper/test-tool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static struct test_cmd cmds[] = {
5151
{ "submodule-config", cmd__submodule_config },
5252
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
5353
{ "subprocess", cmd__subprocess },
54+
{ "trace2", cmd__trace2 },
5455
{ "urlmatch-normalization", cmd__urlmatch_normalization },
5556
{ "wildmatch", cmd__wildmatch },
5657
#ifdef GIT_WINDOWS_NATIVE

t/helper/test-tool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ int cmd__string_list(int argc, const char **argv);
4646
int cmd__submodule_config(int argc, const char **argv);
4747
int cmd__submodule_nested_repo_config(int argc, const char **argv);
4848
int cmd__subprocess(int argc, const char **argv);
49+
int cmd__trace2(int argc, const char **argv);
4950
int cmd__urlmatch_normalization(int argc, const char **argv);
5051
int cmd__wildmatch(int argc, const char **argv);
5152
#ifdef GIT_WINDOWS_NATIVE

t/helper/test-trace2.c

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
#include "test-tool.h"
2+
#include "cache.h"
3+
#include "argv-array.h"
4+
#include "run-command.h"
5+
#include "exec-cmd.h"
6+
#include "config.h"
7+
8+
typedef int (fn_unit_test)(int argc, const char **argv);
9+
10+
struct unit_test
11+
{
12+
fn_unit_test *ut_fn;
13+
const char *ut_name;
14+
const char *ut_usage;
15+
};
16+
17+
#define MyOk 0
18+
#define MyError 1
19+
20+
static int get_i(int *p_value, const char *data)
21+
{
22+
char *endptr;
23+
24+
if (!data || !*data)
25+
return MyError;
26+
27+
*p_value = strtol(data, &endptr, 10);
28+
if (*endptr || errno == ERANGE)
29+
return MyError;
30+
31+
return MyOk;
32+
}
33+
34+
/*
35+
* Cause process to exit with the requested value via "return".
36+
*
37+
* Rely on test-tool.c:cmd_main() to call trace2_cmd_exit()
38+
* with our result.
39+
*
40+
* Test harness can confirm:
41+
* [] the process-exit value.
42+
* [] the "code" field in the "exit" trace2 event.
43+
* [] the "code" field in the "atexit" trace2 event.
44+
* [] the "name" field in the "cmd_verb" trace2 event.
45+
* [] "def_param" events for all of the "interesting" pre-defined config settings.
46+
*/
47+
static int ut_001return(int argc, const char **argv)
48+
{
49+
int rc;
50+
51+
if (get_i(&rc, argv[0]))
52+
die("expect <exit_code>");
53+
54+
return rc;
55+
}
56+
57+
/*
58+
* Cause the process to exit with the requested value via "exit()".
59+
*
60+
* Test harness can confirm:
61+
* [] the "code" field in the "exit" trace2 event.
62+
* [] the "code" field in the "atexit" trace2 event.
63+
* [] the "name" field in the "cmd_verb" trace2 event.
64+
* [] "def_param" events for all of the "interesting" pre-defined config settings.
65+
*/
66+
static int ut_002exit(int argc, const char **argv)
67+
{
68+
int rc;
69+
70+
if (get_i(&rc, argv[0]))
71+
die("expect <exit_code>");
72+
73+
exit(rc);
74+
}
75+
76+
/*
77+
* Send an "error" event with each value in argv. Normally, git only issues
78+
* a single "error" event immediately before issuing an "exit" event (such
79+
* as in die() or BUG()), but multiple "error" events are allowed.
80+
*
81+
* Test harness can confirm:
82+
* [] a trace2 "error" event for each value in argv.
83+
* [] the "name" field in the "cmd_verb" trace2 event.
84+
* [] (optional) the file:line in the "exit" event refers to this function.
85+
*/
86+
static int ut_003error(int argc, const char **argv)
87+
{
88+
int k;
89+
90+
if (!argv[0] || !*argv[0])
91+
die("expect <error_message>");
92+
93+
for (k = 0; k < argc; k++)
94+
error("%s", argv[k]);
95+
96+
return 0;
97+
}
98+
99+
/*
100+
* Run a child process and wait for it to finish and exit with its return code.
101+
* test-tool trace2 004child [<child-command-line>]
102+
*
103+
* For example:
104+
* test-tool trace2 004child git version
105+
* test-tool trace2 004child test-tool trace2 001return 0
106+
* test-tool trace2 004child test-tool trace2 004child test-tool trace2 004child
107+
* test-tool trace2 004child git -c alias.xyz=version xyz
108+
*
109+
* Test harness can confirm:
110+
* [] the "name" field in the "cmd_verb" trace2 event.
111+
* [] that the outer process has a single component SID (or depth "d0" in
112+
* the PERF stream).
113+
* [] that "child_start" and "child_exit" events are generated for the child.
114+
* [] if the child process is an instrumented executable:
115+
* [] that "version", "start", ..., "exit", and "atexit" events are
116+
* generated by the child process.
117+
* [] that the child process events have a multiple component SID (or
118+
* depth "dN+1" in the PERF stream).
119+
* [] that the child exit code is propagated to the parent process "exit"
120+
* and "atexit" events..
121+
* [] (optional) that the "t_abs" field in the child process "atexit" event
122+
* is less than the "t_rel" field in the "child_exit" event of the parent
123+
* process.
124+
* [] if the child process is like the alias example above,
125+
* [] (optional) the child process attempts to run "git-xyx" as a dashed
126+
* command.
127+
* [] the child process emits an "alias" event with "xyz" => "version"
128+
* [] the child process runs "git version" as a child process.
129+
* [] the child process has a 3 component SID (or depth "d2" in the PERF
130+
* stream).
131+
*/
132+
static int ut_004child(int argc, const char **argv)
133+
{
134+
int result;
135+
136+
/*
137+
* Allow empty <child_command_line> so we can do arbitrarily deep
138+
* command nesting and let the last one be null.
139+
*/
140+
if (!argc)
141+
return 0;
142+
143+
result = run_command_v_opt(argv, 0);
144+
exit(result);
145+
}
146+
147+
/*
148+
* Exec a git command. This may either create a child process (Windows)
149+
* or replace the existing process.
150+
* test-tool trace2 005exec <git_command_args>
151+
*
152+
* For example:
153+
* test-tool trace2 005exec version
154+
*
155+
* Test harness can confirm (on Windows):
156+
* [] the "name" field in the "cmd_verb" trace2 event.
157+
* [] that the outer process has a single component SID (or depth "d0" in
158+
* the PERF stream).
159+
* [] that "exec" and "exec_result" events are generated for the child
160+
* process (since the Windows compatibility layer fakes an exec() with
161+
* a CreateProcess(), WaitForSingleObject(), and exit()).
162+
* [] that the child process has multiple component SID (or depth "dN+1"
163+
* in the PERF stream).
164+
*
165+
* Test harness can confirm (on platforms with a real exec() function):
166+
* [] TODO talk about process replacement and how it affects SID.
167+
*/
168+
static int ut_005exec(int argc, const char **argv)
169+
{
170+
int result;
171+
172+
if (!argc)
173+
return 0;
174+
175+
result = execv_git_cmd(argv);
176+
return result;
177+
}
178+
179+
static int ut_006data(int argc, const char **argv)
180+
{
181+
const char *usage_error =
182+
"expect <cat0> <k0> <v0> [<cat1> <k1> <v1> [...]]";
183+
184+
if (argc % 3 != 0)
185+
die("%s", usage_error);
186+
187+
while (argc) {
188+
if (!argv[0] || !*argv[0] ||
189+
!argv[1] || !*argv[1] ||
190+
!argv[2] || !*argv[2])
191+
die("%s", usage_error);
192+
193+
trace2_data_string(argv[0], the_repository, argv[1], argv[2]);
194+
argv += 3;
195+
argc -= 3;
196+
}
197+
198+
return 0;
199+
}
200+
201+
/*
202+
* Usage:
203+
* test-tool trace2 <ut_name_1> <ut_usage_1>
204+
* test-tool trace2 <ut_name_2> <ut_usage_2>
205+
* ...
206+
*/
207+
#define USAGE_PREFIX "test-tool trace2"
208+
209+
static struct unit_test ut_table[] = {
210+
{ ut_001return, "001return", "<exit_code>" },
211+
{ ut_002exit, "002exit", "<exit_code>" },
212+
{ ut_003error, "003error", "<error_message>+" },
213+
{ ut_004child, "004child", "[<child_command_line>]" },
214+
{ ut_005exec, "005exec", "<git_command_args>" },
215+
{ ut_006data, "006data", "[<category> <key> <value>]+" },
216+
};
217+
218+
#define for_each_ut(k, ut_k) \
219+
for (k = 0, ut_k = &ut_table[k]; \
220+
k < ARRAY_SIZE(ut_table); \
221+
k++, ut_k = &ut_table[k])
222+
223+
static int print_usage(void)
224+
{
225+
int k;
226+
struct unit_test *ut_k;
227+
228+
fprintf(stderr, "usage:\n");
229+
for_each_ut(k, ut_k) {
230+
fprintf(stderr, "\t%s %s %s\n",
231+
USAGE_PREFIX, ut_k->ut_name, ut_k->ut_usage);
232+
}
233+
234+
return 129;
235+
}
236+
237+
/*
238+
* Issue various trace2 events for testing.
239+
*
240+
* We assume that these trace2 routines has already been called:
241+
* [] trace2_initialize() [common-main.c:main()]
242+
* [] trace2_cmd_start() [common-main.c:main()]
243+
* [] trace2_cmd_verb() [test-tool.c:cmd_main()]
244+
* [] tracd2_cmd_list_config() [test-tool.c:cmd_main()]
245+
* So that:
246+
* [] the various trace2 streams are open.
247+
* [] the process SID has been created.
248+
* [] the "version" event has been generated.
249+
* [] the "start" event has been generated.
250+
* [] the "verb" event has been generated.
251+
* [] this writes various "def_param" events for interesting config values.
252+
*
253+
* We further assume that if we return (rather than exit()), trace2_cmd_exit()
254+
* will be called by test-tool.c:cmd_main().
255+
*/
256+
int cmd__trace2(int argc, const char **argv)
257+
{
258+
int k;
259+
struct unit_test *ut_k;
260+
261+
argc--; /* skip over "trace2" arg */
262+
argv++;
263+
264+
if (argc) {
265+
for_each_ut(k, ut_k) {
266+
if (!strcmp(argv[0], ut_k->ut_name))
267+
return ut_k->ut_fn(argc - 1, argv + 1);
268+
}
269+
}
270+
271+
return print_usage();
272+
}
273+

0 commit comments

Comments
 (0)