xref: /aosp_15_r20/external/jazzer-api/docs/junit-integration.md (revision 33edd6723662ea34453766bfdca85dbfdd5342b8)
1# JUnit Integration Implementation
2
3Jazzer's JUnit integration starts from
4the [`FuzzTest`](../src/main/java/com/code_intelligence/jazzer/junit/FuzzTest.java) annotation. As mentioned in the
5annotation's javadoc, our integration runs in one of two modes: fuzzing and regression. Fuzzing mode will generate new
6inputs to feed into the tests to find new issues and regression mode will run the tests against previous findings, no
7fuzzing is done. The main entrypoints for the actual integration code are found in two of the annotations
8on `FuzzTest`: `@ArgumentsSource(FuzzTestArgumentsProvider.class)` and `@ExtendsWith(FuzzTestExtensions.class)`.
9
10Because these same files and functions are involved in two mostly separate sets of functionality, this will look at the
11flow of the different methods involved in integrating with JUnit in fuzzing mode (when `JAZZER_FUZZ` is set to any
12non-empty value) and in regression mode (when `JAZZER_FUZZ` is not set) separately.
13
14# Fuzzing Flow
15
16JUnit will call the following methods for each test marked with `FuzzTest`.
17
18## `evaluateExecutionCondition`
19
20The first call to this test will determine if the test should be run at all. In fuzzing mode, we only allow one test to
21be run due to global state in libfuzzer that would mean multiple tests would interfere with each other. Jazzer will
22accept the first fuzz test that is checked as the test to be run. It will cache which test it has seen first and
23return that test as enabled.
24
25If this returns that a test is disabled, JUnit will not run the rest of these methods for this test and instead skip
26to the next one.
27
28## `provideArguments`
29
30This will configure the fuzzing agent to set up code instrumentation, instantiate a `FuzzTestExecutor` and put it into
31JUnit's `extensionContext`, then create a stream of a single empty argument set. As the comment mentions, this is so
32that JUnit will actually execute the test but the argument will not be used.
33
34## `evaluateExecutionCondition`
35
36This will be called for each argument set for the current test. In fuzzing mode, there will only be the single
37empty argument set which will be enabled.
38
39## `interceptTestTemplateMethod`
40
41This will call `invocation.skip()` which prevents invoking the test function with the default set of
42arguments `provideArguments` created. It will instead extract the `FuzzTestExecutor` instance from
43the `extensionContext` and then calls `FuzzTestExecutor#execute` which creates a `FuzzTargetRunner` to run the actual
44fuzzing.
45
46Crashes are saved in `resources/<package>/<test file name>Inputs/<test method name>` and results that are interesting to
47libfuzzer are saved in `.cifuzz-corpus`.
48
49# Regression Flow
50
51Similar to fuzzing mode, JUnit will call these methods for each test marked with `FuzzTest`.
52
53## `evaluateExecutionCondition`
54
55This checks if the given test should be run at all. In regression mode, all tests are run so this will always return
56enabled.
57
58## `provideArguments`
59
60This will configure the fuzzing agent as in fuzzing mode, then gather test cases to run from the following sources:
61
621. A default argument set of just an empty input
632. A set of arguments from the associated resources directory
643. If a `.cifuzz-corpus` directory exists, relevant entries from that are added as well
65
66Prior to returning, the stream of test cases is put through `adaptInputsForFuzzTest` to turn the raw bytes from the
67files into the actual types to be given to the tested function.
68
69### Resources Tests
70
71The tests from the resources directory are gathered by `walkInputs`. This will look for inputs in two places:
72- `resources/<package>/<test class name>Inputs` - files found directly within this directory will be used as inputs for
73  any tests within this class. This allows for easy sharing of corpus entries. Jazzer does not automatically put entries
74  here, instead a human will need to decide a finding should be shared and manually move it.
75- `resources/<package>/<test class name>Inputs/<test method name>` - files found in this directory and any directory
76  under it are used as inputs for only the test of the same name.
77
78JUnit will use the file's name as the name of the test case for its reporting. It also accepts .jar files where it will
79search with the given directory in the jar.
80
81### CIFuzz Corpus
82
83The corpus kept in `.cifuzz-corpus/<test class name>/<test method name>` holds any inputs that libfuzzer found worth
84saving and not necessarily just inputs that caused a crash. Jazzer is able to set the directory but the contents of
85these directories are managed entirely by libfuzzer. Unlike with the resources test inputs above, this will not look
86in `.cifuzz-corpus/<test class name>` for shared test cases. This is a limitation of libfuzzer.
87
88## `evaluateExecutionCondition`
89
90This will run once per argument set returned by `provideArguments` for this test. All argument sets will return as
91enabled.
92
93## `interceptTestTemplateMethod`
94
95This will run for each individual test case for each fuzz test and will mostly just allow the test function to proceed
96with the provided arguments. Prior to the call to the test, it will enable the agent's hooks and then disable them
97afterward. It will also check for and report any findings from Jazzer to JUnit.
98
99# Diagrams
100
101Below are two sequence diagrams for how JUnit calls `evaluateExecutionConditions` and `provideArguments` in fuzzing and
102regression mode. These diagrams ignore `interceptTestTemplateMethod` for brevity as its behavior and place in the
103sequence is more clear.
104
105## Fuzzing
106
107![created on sequencediagram.org, load the svg in the editor to edit](./images/fuzzing-flow.svg)
108
109## Regression
110
111![created on sequencediagram.org, load the svg in the editor to edit](./images/regression-flow.svg)
112