Skip to content

Commit a15860d

Browse files
jeffhostetlergitster
authored andcommitted
trace2: t/helper/test-trace2, t0210.sh, t0211.sh, t0212.sh
Create unit tests for Trace2. Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b3a5d5a commit a15860d

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
@@ -773,6 +773,7 @@ TEST_BUILTINS_OBJS += test-string-list.o
773773
TEST_BUILTINS_OBJS += test-submodule-config.o
774774
TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
775775
TEST_BUILTINS_OBJS += test-subprocess.o
776+
TEST_BUILTINS_OBJS += test-trace2.o
776777
TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
777778
TEST_BUILTINS_OBJS += test-xml-encode.o
778779
TEST_BUILTINS_OBJS += test-wildmatch.o

t/helper/test-tool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static struct test_cmd cmds[] = {
5252
{ "submodule-config", cmd__submodule_config },
5353
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
5454
{ "subprocess", cmd__subprocess },
55+
{ "trace2", cmd__trace2 },
5556
{ "urlmatch-normalization", cmd__urlmatch_normalization },
5657
{ "xml-encode", cmd__xml_encode },
5758
{ "wildmatch", cmd__wildmatch },

t/helper/test-tool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ int cmd__string_list(int argc, const char **argv);
4848
int cmd__submodule_config(int argc, const char **argv);
4949
int cmd__submodule_nested_repo_config(int argc, const char **argv);
5050
int cmd__subprocess(int argc, const char **argv);
51+
int cmd__trace2(int argc, const char **argv);
5152
int cmd__urlmatch_normalization(int argc, const char **argv);
5253
int cmd__xml_encode(int argc, const char **argv);
5354
int cmd__wildmatch(int argc, const char **argv);

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

0 commit comments

Comments
 (0)