| [#](#) Tutorial: Debug tests using zxdb |
| |
| This tutorial walks through a debugging workflow using the `fx test` command |
| and the Fuchsia debugger (`zxdb`). |
| |
| For additional info on debugging tests using zxdb, see |
| [Debug tests using zxdb][zxdb-test-doc] |
| |
| ## Understanding test cases {:#understand-test-cases .numbered} |
| |
| Note: In most test cases, no additional setup is necessary in the code to run |
| the `fx test` command with `zxdb`. |
| |
| * {Rust} |
| |
| Rust tests are executed by the [Rust test runner][rust-test-runner]. Unlike |
| gTest or gUnit runners for C++ tests, the Rust test runner defaults to running |
| test cases in parallel. This creates a different experience while using the |
| `--break-on-failure` feature. For more information on expectations while |
| debugging parallel test processes, see |
| [Executing test cases in parallel][zxdb-parallel-tests]. Parallel test |
| processes are supported. |
| |
| Here is an example based on some sample |
| [rust test code][rust-calculator-test-example]: |
| |
| Note: This code is a modified version of the original code and is abbreviated |
| for brevity. |
| |
| ```rust |
| #[fuchsia::test] |
| async fn add_test() { |
| let (proxy, stream) = create_proxy_and_stream::<CalculatorMarker>(); |
| |
| // Run two tasks: The calculator_fake & the calculator_line method we're interested |
| // in testing. |
| let fake_task = calculator_fake(stream).fuse(); |
| let calculator_line_task = calculator_line("1 + 2", &proxy).fuse(); |
| futures::pin_mut!(fake_task, calculator_line_task); |
| futures::select! { |
| actual = calculator_line_task => { |
| let actual = actual.expect("Calculator didn't return value"); |
| assert_eq!(actual, 5.0); |
| }, |
| _ = fake_task => { |
| panic!("Fake should never complete.") |
| } |
| }; |
| } |
| ``` |
| |
| You can add this test target to your build graph with `fx set`: |
| |
| ```posix-terminal |
| fx set workbench_eng.x64 --with-test //examples/fidl/calculator/rust/client:hermetic_tests |
| ``` |
| |
| * {C++} |
| |
| By default, the gTest test runner executes test cases serially, so only one |
| test failure is debugged at a time. You can execute test cases in parallel |
| by adding the `--parallel-cases` flag to the `fx test` command. |
| |
| Here is an example based on some sample |
| [C++ test code][debug-agent-test-example]: |
| |
| Note: This code is abbreviated for brevity. |
| |
| ```cpp |
| // Inject 1 process. |
| auto process1 = std::make_unique<MockProcess>(nullptr, kProcessKoid1, kProcessName1); |
| process1->AddThread(kProcess1ThreadKoid1); |
| harness.debug_agent()->InjectProcessForTest(std::move(process1)); |
| |
| // And another, with 2 threads. |
| auto process2 = std::make_unique<MockProcess>(nullptr, kProcessKoid2, kProcessName2); |
| process2->AddThread(kProcess2ThreadKoid1); |
| process2->AddThread(kProcess2ThreadKoid2); |
| harness.debug_agent()->InjectProcessForTest(std::move(process2)); |
| |
| reply = {}; |
| remote_api->OnStatus(request, &reply); |
| |
| ASSERT_EQ(reply.processes.size(), 3u); // <-- This will fail, since reply.processes.size() == 2 |
| EXPECT_EQ(reply.processes[0].process_koid, kProcessKoid1); |
| EXPECT_EQ(reply.processes[0].process_name, kProcessName1); |
| ... |
| ``` |
| |
| You can add this test target to your build graph with `fx set`: |
| |
| ```posix-terminal |
| fx set workbench_eng.x64 --with-test //src/developer/debug:tests |
| ``` |
| |
| ## Executing tests {:#execute-tests .numbered} |
| |
| * {Rust} |
| |
| Execute the tests with the `fx test --break-on-failure` command, for example: |
| |
| ```posix-terminal |
| fx test -o --break-on-failure calculator-client-rust-unittests |
| ``` |
| |
| The output looks like: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| <...fx test startup...> |
| |
| ... |
| [RUNNING] tests::add_test |
| [RUNNING] tests::divide_test |
| [RUNNING] tests::multiply_test |
| [PASSED] parse::tests::parse_expression |
| [RUNNING] tests::pow_test |
| [PASSED] parse::tests::parse_expression_with_negative_numbers |
| [RUNNING] tests::subtract_test |
| [PASSED] parse::tests::parse_expression_with_multiplication |
| [PASSED] parse::tests::parse_expression_with_subtraction |
| [PASSED] parse::tests::parse_expression_with_pow |
| [PASSED] parse::tests::parse_operators |
| [01234.052188][218417][218422][<root>][add_test] ERROR: [examples/fidl/calculator/rust/client/src/main.rs(110)] PANIC info=panicked at ../../examples/fidl/calculato |
| r/rust/client/src/main.rs:110:17: |
| assertion `left == right` failed |
| left: 3.0 |
| right: 5.0 |
| [PASSED] parse::tests::parse_expression_with_division |
| [PASSED] tests::multiply_test |
| [PASSED] tests::divide_test |
| ... |
| đź‘‹ zxdb is loading symbols to debug test failure in calculator-client-rust-unittest, please wait. |
| âš test failure in calculator-client-rust-unittest, type `frame` or `help` to get started. |
| 108 actual = calculator_line_task => { |
| 109 let actual = actual.expect("Calculator didn't return value"); |
| â–¶ 110 assert_eq!(actual, 5.0); |
| 111 }, |
| 112 _ = fake_task => { |
| 🛑 process 8 calculator_client_bin_test::tests::add_test::test_entry_point::λ(core::task::wake::Context*) • main.rs:110 |
| [zxdb] |
| ``` |
| |
| Notice that the output from the test is mixed up, this is because |
| the rust test runner runs test cases in |
| [parallel by default][rust-test-runner-parallel-default]. You can avoid |
| this by using the `--parallel-cases` option with `fx test`, for example: |
| `fx test --parallel-cases 1 --break-on-failure |
| calculator-client-rust-unittests`. This flag is not required for the tools to |
| function, but it can be helpful for debugging as it prevents the output of |
| multiple tests from being interleaved, making it easier to read. |
| |
| With that option, the output looks like this: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| fx test --parallel-cases 1 -o --break-on-failure calculator-client-rust-unittests |
| |
| ... |
| [RUNNING] parse::tests::parse_operators |
| [PASSED] parse::tests::parse_operators |
| [RUNNING] tests::add_test |
| [01391.909144][249125][249127][<root>][add_test] ERROR: [examples/fidl/calculator/rust/client/src/main.rs(110)] PANIC info=panicked at ../../examples/fidl/calculato |
| r/rust/client/src/main.rs:110:17: |
| assertion `left == right` failed |
| left: 3.0 |
| right: 5.0 |
| |
| Status: [duration: 5.0s] |
| Running 1 tests [ ] 0.0% |
| fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests#meta/calculator-client-rust-unittests.cm [0.5s] |
| đź‘‹ zxdb is loading symbols to debug test failure in calculator-client-rust-unittest, please wait. |
| âš test failure in calculator-client-rust-unittest, type `frame` or `help` to get started. |
| 108 actual = calculator_line_task => { |
| 109 let actual = actual.expect("Calculator didn't return value"); |
| â–¶ 110 assert_eq!(actual, 5.0); |
| 111 }, |
| 112 _ = fake_task => { |
| 🛑 process 2 calculator_client_bin_test::tests::add_test::test_entry_point::λ(core::task::wake::Context*) • main.rs:110 |
| [zxdb] |
| ``` |
| |
| * {C++} |
| |
| Execute the tests with the `fx test --break-on-failure` command, for example: |
| |
| ```posix-terminal |
| fx test -o --break-on-failure debug_agent_unit_tests |
| ``` |
| |
| The output looks like: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| <...fx test startup...> |
| |
| Starting: fuchsia-pkg://fuchsia.com/debug_agent_unit_tests#meta/debug_agent_unit_tests.cm (NOT HERMETIC) |
| Command: fx ffx test run --realm /core/testing/system-tests --max-severity-logs WARN --break-on-failure fuchsia-pkg://fuchsia.com/debug_agent_unit_tests?hash=3f6d97801bb147034a344e3fe1bb69291a7b690b9d3d075246ddcba59397ac12#meta/debug_agent_unit_tests.cm |
| |
| Status: [duration: 30.9s] [tasks: 3 running, 15/19 complete] |
| Running 2 tests [ ] 0.0% |
| đź‘‹ zxdb is loading symbols to debug test failure in debug_agent_unit_tests.cm, please wait. |
| ⚠️ test failure in debug_agent_unit_tests.cm, type `frame` or `help` to get started. |
| 103 remote_api->OnStatus(request, &reply); |
| 104 |
| â–¶ 105 ASSERT_EQ(reply.processes.size(), 3u); |
| 106 EXPECT_EQ(reply.processes[0].process_koid, kProcessKoid1); |
| 107 EXPECT_EQ(reply.processes[0].process_name, kProcessName1); |
| 🛑 thread 1 debug_agent::DebugAgentTests_OnGlobalStatus_Test::TestBody(debug_agent::DebugAgentTests_OnGlobalStatus_Test*) • debug_agent_unittest.cc:105 |
| [zxdb] |
| ``` |
| |
| ## Examining failures {:#examine-failures .numbered} |
| |
| * {Rust} |
| |
| The example contains a test failure, so Rust tests issue an `abort` on |
| failure, which `zxdb` notices and reports. `zxdb` also analyzes the call |
| stack from the abort and conveniently drop us straight into the source code |
| that failed. You can view additional lines of the code from the current frame |
| with `list`, for example: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| list |
| 105 let calculator_line_task = calculator_line("1 + 2", &proxy).fuse(); |
| 106 futures::pin_mut!(fake_task, calculator_line_task); |
| 107 futures::select! { |
| 108 actual = calculator_line_task => { |
| 109 let actual = actual.expect("Calculator didn't return value"); |
| â–¶ 110 assert_eq!(actual, 5.0); |
| 111 }, |
| 112 _ = fake_task => { |
| 113 panic!("Fake should never complete.") |
| 114 } |
| 115 }; |
| 116 } |
| 117 |
| 118 #[fuchsia::test] |
| 119 async fn subtract_test() { |
| 120 let (proxy, stream) = create_proxy_and_stream::<CalculatorMarker>() |
| ``` |
| |
| You can also examine the entire call stack with `frame`, for example: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| frame |
| 0…12 «Rust library» (-r expands) |
| 13 std::panicking::begin_panic_handler(…) • library/std/src/panicking.rs:697 |
| 14 core::panicking::panic_fmt(…) • library/core/src/panicking.rs:75 |
| 15 core::panicking::assert_failed_inner(…) • library/core/src/panicking.rs:448 |
| 16 core::panicking::assert_failed<…>(…) • fuchsia-third_party-rust/library/core/src/panicking.rs:403 |
| ▶ 17 calculator_client_bin_test::tests::add_test::test_entry_point::λ(…) • main.rs:110 |
| 18 core::future::future::«impl»::poll<…>(…) • future/future.rs:133 |
| 19…44 «Polled event in fuchsia::test_singlethreaded» (-r expands) |
| 45 calculator_client_bin_test::tests::add_test() • main.rs:98 |
| 46 calculator_client_bin_test::tests::add_test::λ(…) • main.rs:99 |
| 47 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:253 |
| 48 core::ops::function::FnOnce::call_once<…>(…) • library/core/src/ops/function.rs:253 (inline) |
| 49…70 «Rust test startup» (-r expands) |
| ``` |
| |
| Or, when in an asynchronous context, you can use `async-backtrace`, for example: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| async-backtrace |
| Task(id = 0) |
| └─ calculator_client_bin_test::tests::divide_test::test_entry_point • select_mod.rs:321 |
| └─ select! |
| └─ (terminated) |
| └─ calculator_client_bin_test::tests::calculator_fake • main.rs:93 |
| └─ futures_util::stream::try_stream::try_for_each::TryForEach |
| Task(id = 1) |
| └─ diagnostics_log::fuchsia::filter::«impl»::listen_to_interest_changes • fuchsia/filter.rs:63 |
| └─ fidl::client::QueryResponseFut |
| ``` |
| |
| All commands that you run are in the context of frame #17, as indicated by `â–¶`. |
| You can list the source code again with a little bit of additional context: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| list -c 10 |
| 100 let (proxy, stream) = create_proxy_and_stream::<CalculatorMarker>(); |
| 101 |
| 102 // Run two tasks: The calculator_fake & the calculator_line method we're interested |
| 103 // in testing. |
| 104 let fake_task = calculator_fake(stream).fuse(); |
| 105 let calculator_line_task = calculator_line("1 + 2", &proxy).fuse(); |
| 106 futures::pin_mut!(fake_task, calculator_line_task); |
| 107 futures::select! { |
| 108 actual = calculator_line_task => { |
| 109 let actual = actual.expect("Calculator didn't return value"); |
| â–¶ 110 assert_eq!(actual, 5.0); |
| 111 }, |
| 112 _ = fake_task => { |
| 113 panic!("Fake should never complete.") |
| 114 } |
| 115 }; |
| 116 } |
| 117 |
| 118 #[fuchsia::test] |
| 119 async fn subtract_test() { |
| 120 let (proxy, stream) = create_proxy_and_stream::<CalculatorMarker>(); |
| ``` |
| |
| To find out why the test failed, print out some variables to see what is |
| happening. The `actual` frame contains a local variable, which |
| should have some strings that were added by calling `write_log` on the |
| `log_helper` and `log_helper2` instances and by receiving them with the |
| mpsc channel `recv_logs`: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| print actual |
| 3 |
| ``` |
| |
| It seems that the test's expectations are slightly incorrect. It was expected |
| that the calculator would return "1 + 2" would be equal to 3, but the test |
| expected it to be 5! The calculator returned the right answer but the test |
| expectation is incorrect. You can now detach from the failed test case and fix |
| the test expectation. |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| detach |
| |
| <...fx test output continues...> |
| |
| Failed tests: tests::add_test |
| 11 out of 12 tests passed... |
| |
| Test fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests?hash=b105775fa7c39eb67195a09d63be6c4314eeef8e93eb542616c0b5dbda73b8e2#meta/calculator-client-rust-unittests.cm produced unex |
| pected high-severity logs: |
| ----------------xxxxx---------------- |
| [09353.731026][1225676][1225678][<root>][add_test] ERROR: [examples/fidl/calculator/rust/client/src/main.rs(110)] PANIC info=panicked at ../../examples/fidl/calculator/rust/client/src/main |
| .rs:110:17: |
| assertion `left == right` failed |
| left: 3.0 |
| right: 5.0 |
| |
| ----------------xxxxx---------------- |
| Failing this test. See: https://fuchsia.dev/fuchsia-src/development/diagnostics/test_and_logs#restricting_log_severity |
| |
| fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests?hash=b105775fa7c39eb67195a09d63be6c4314eeef8e93eb542616c0b5dbda73b8e2#meta/calculator-client-rust-unittests.cm completed with res |
| ult: FAILED |
| The test was executed in the hermetic realm. If your test depends on system capabilities, pass in correct realm. See https://fuchsia.dev/go/components/non-hermetic-tests |
| Tests failed. |
| ``` |
| |
| Now you can fix the test by making the following change to the code: |
| |
| Note: `-` indicates a removal of a line and `+` indicates an added line. |
| |
| ```diff |
| - assert_eq!(actual, 5.0); |
| + assert_eq!(actual, 3.0); |
| ``` |
| |
| You can now run the tests again: |
| |
| ```posix-terminal |
| fx test --break-on-failure calculator-client-rust-unittests |
| ``` |
| |
| The output should look like: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| <...fx test startup...> |
| |
| Running 1 tests |
| |
| Status: [duration: 13.5s] |
| Running 1 tests |
| |
| Starting: fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests#meta/calculator-client-rust-unittests.cm |
| Command: fx --dir /usr/local/google/home/jruthe/upstream/fuchsia/out/default ffx test run --max-severity-logs WARN --parallel 1 --no-exception-channel --break-on-failure fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests?hash=abc77325b830d25e47d1de85b764f2b7a0d8975269dfc654f3a7f9a6859b851a#meta/calculator-client-rust-unittests.cm |
| |
| Running test 'fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests?hash=abc77325b830d25e47d1de85b764f2b7a0d8975269dfc654f3a7f9a6859b851a#meta/calculator-client-rust-unittests.cm' |
| [RUNNING] parse::tests::parse_expression |
| [PASSED] parse::tests::parse_expression |
| [RUNNING] parse::tests::parse_expression_with_division |
| [PASSED] parse::tests::parse_expression_with_division |
| [RUNNING] parse::tests::parse_expression_with_multiplication |
| [PASSED] parse::tests::parse_expression_with_multiplication |
| [RUNNING] parse::tests::parse_expression_with_negative_numbers |
| [PASSED] parse::tests::parse_expression_with_negative_numbers |
| [RUNNING] parse::tests::parse_expression_with_pow |
| [PASSED] parse::tests::parse_expression_with_pow |
| [RUNNING] parse::tests::parse_expression_with_subtraction |
| [PASSED] parse::tests::parse_expression_with_subtraction |
| [RUNNING] parse::tests::parse_operators |
| [PASSED] parse::tests::parse_operators |
| [RUNNING] tests::add_test |
| [PASSED] tests::add_test |
| [RUNNING] tests::divide_test |
| [PASSED] tests::divide_test |
| [RUNNING] tests::multiply_test |
| [PASSED] tests::multiply_test |
| [RUNNING] tests::pow_test |
| [PASSED] tests::pow_test |
| [RUNNING] tests::subtract_test |
| [PASSED] tests::subtract_test |
| |
| 12 out of 12 tests passed... |
| fuchsia-pkg://fuchsia.com/calculator-client-rust-unittests?hash=abc77325b830d25e47d1de85b764f2b7a0d8975269dfc654f3a7f9a6859b851a#meta/calculator-client-rust-unittests.cm completed with res |
| ult: PASSED |
| Deleting 1 files at /tmp/tmprwdcy73n: ffx_logs/ffx.log |
| To keep these files, set --ffx-output-directory. |
| |
| Status: [duration: 14.8s] [tests: PASSED: 1 FAILED: 0 SKIPPED: 0] |
| ``` |
| |
| * {C++} |
| |
| The example contains a test failure, gTest has an option to insert a software |
| breakpoint in the path of a test failure, which `zxdb` picked up. `zxdb` has |
| also determined the location of your test code based on this, and jumps |
| straight to the frame from your test. You can view additional lines of code of |
| the current frame with `list`, for example: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| list |
| 100 harness.debug_agent()->InjectProcessForTest(std::move(process2)); |
| 101 |
| 102 reply = {}; |
| 103 remote_api->OnStatus(request, &reply); |
| 104 |
| â–¶ 105 ASSERT_EQ(reply.processes.size(), 3u); |
| 106 EXPECT_EQ(reply.processes[0].process_koid, kProcessKoid1); |
| 107 EXPECT_EQ(reply.processes[0].process_name, kProcessName1); |
| 108 ASSERT_EQ(reply.processes[0].threads.size(), 1u); |
| ``` |
| |
| You can see more lines of source code by using `list`'s `-c` flag: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| list -c 10 |
| 95 constexpr uint64_t kProcess2ThreadKoid2 = 0x2; |
| 96 |
| 97 auto process2 = std::make_unique<MockProcess>(nullptr, kProcessKoid2, kProcessName2); |
| 98 process2->AddThread(kProcess2ThreadKoid1); |
| 99 process2->AddThread(kProcess2ThreadKoid2); |
| 100 harness.debug_agent()->InjectProcessForTest(std::move(process2)); |
| 101 |
| 102 reply = {}; |
| 103 remote_api->OnStatus(request, &reply); |
| 104 |
| â–¶ 105 ASSERT_EQ(reply.processes.size(), 3u); |
| 106 EXPECT_EQ(reply.processes[0].process_koid, kProcessKoid1); |
| 107 EXPECT_EQ(reply.processes[0].process_name, kProcessName1); |
| 108 ASSERT_EQ(reply.processes[0].threads.size(), 1u); |
| 109 EXPECT_EQ(reply.processes[0].threads[0].id.process, kProcessKoid1); |
| 110 EXPECT_EQ(reply.processes[0].threads[0].id.thread, kProcess1ThreadKoid1); |
| 111 |
| 112 EXPECT_EQ(reply.processes[1].process_koid, kProcessKoid2); |
| 113 EXPECT_EQ(reply.processes[1].process_name, kProcessName2); |
| 114 ASSERT_EQ(reply.processes[1].threads.size(), 2u); |
| 115 EXPECT_EQ(reply.processes[1].threads[0].id.process, kProcessKoid2); |
| [zxdb] |
| ``` |
| |
| You can also examine the full stack trace with the `frame` command: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| frame |
| 0 testing::UnitTest::AddTestPartResult(…) • gtest.cc:5383 |
| 1 testing::internal::AssertHelper::operator=(…) • gtest.cc:476 |
| ▶ 2 debug_agent::DebugAgentTests_OnGlobalStatus_Test::TestBody(…) • debug_agent_unittest.cc:105 |
| 3 testing::internal::HandleSehExceptionsInMethodIfSupported<…>(…) • gtest.cc:2635 |
| 4 testing::internal::HandleExceptionsInMethodIfSupported<…>(…) • gtest.cc:2690 |
| 5 testing::Test::Run(…) • gtest.cc:2710 |
| 6 testing::TestInfo::Run(…) • gtest.cc:2859 |
| 7 testing::TestSuite::Run(…) • gtest.cc:3038 |
| 8 testing::internal::UnitTestImpl::RunAllTests(…) • gtest.cc:5942 |
| 9 testing::internal::HandleSehExceptionsInMethodIfSupported<…>(…) • gtest.cc:2635 |
| 10 testing::internal::HandleExceptionsInMethodIfSupported<…>(…) • gtest.cc:2690 |
| 11 testing::UnitTest::Run(…) • gtest.cc:5506 |
| 12 RUN_ALL_TESTS() • gtest.h:2318 |
| 13 main(…) • run_all_unittests.cc:20 |
| 14…17 «libc startup» (-r expands) |
| [zxdb] |
| ``` |
| |
| Notice that the `â–¶` points to your test's source code frame, indicating that |
| all commands are executed within this context. You can select other frames |
| by using the `frame` command with the associated number from the stack trace. |
| |
| To find out why the test failed, print out some variables to see what is |
| happening. The `reply` frame contains a local variable, which should have been |
| populated by the function call to `remote_api->OnStatus`: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| print reply |
| { |
| processes = { |
| [0] = { |
| process_koid = 4660 |
| process_name = "process-1" |
| components = {} |
| threads = { |
| [0] = { |
| id = {process = 4660, thread = 1} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| } |
| } |
| [1] = { |
| process_koid = 22136 |
| process_name = "process-2" |
| components = {} |
| threads = { |
| [0] = { |
| id = {process = 22136, thread = 1} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| [1] = { |
| id = {process = 22136, thread = 2} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| } |
| } |
| } |
| limbo = {} |
| breakpoints = {} |
| filters = {} |
| } |
| ``` |
| |
| From the output, you can see the `reply` variable has been filled in with some |
| information, the expectation is that the size of the `processes` vector should |
| be equal to 3. Print the member variable of `reply` to see more information. |
| You can also print the size method of that vector (general function calling |
| support is not implemented yet): |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| print reply.processes |
| { |
| [0] = { |
| process_koid = 4660 |
| process_name = "process-1" |
| components = {} |
| threads = { |
| [0] = { |
| id = {process = 4660, thread = 1} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| } |
| } |
| [1] = { |
| process_koid = 22136 |
| process_name = "process-2" |
| components = {} |
| threads = { |
| [0] = { |
| id = {process = 22136, thread = 1} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| [1] = { |
| id = {process = 22136, thread = 2} |
| name = "test thread" |
| state = kRunning |
| blocked_reason = kNotBlocked |
| stack_amount = kNone |
| frames = {} |
| } |
| } |
| } |
| } |
| [zxdb] print reply.processes.size() |
| 2 |
| ``` |
| |
| It seems that the test's expectations are slightly incorrect. You only |
| injected 2 mock processes, but the test was expecting 3. You can simply |
| update the test to expect the size of the `reply.processes` vector to be be |
| 2 instead of 3. You can now close zxdb with `quit` to then update and fix the |
| tests: |
| |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } |
| quit |
| |
| <...fx test output continues...> |
| |
| Failed tests: DebugAgentTests.OnGlobalStatus <-- Failed test case that we debugged. |
| 175 out of 176 attempted tests passed, 2 tests skipped... |
| fuchsia-pkg://fuchsia.com/debug_agent_unit_tests?hash=3f6d97801bb147034a344e3fe1bb69291a7b690b9d3d075246ddcba59397ac12#meta/debug_agent_unit_tests.cm completed with result: FAILED |
| Tests failed. |
| |
| |
| FAILED: fuchsia-pkg://fuchsia.com/debug_agent_unit_tests#meta/debug_agent_unit_tests.cm |
| ``` |
| |
| Now that you have found the source of the test failure, you can fix the test: |
| |
| ```diff |
| -ASSERT_EQ(reply.processes.size(), 3u) |
| +ASSERT_EQ(reply.processes.size(), 2u) |
| ``` |
| |
| Then, run `fx test`: |
| |
| ```posix-terminal |
| fx test --break-on-failure debug_agent_unit_tests |
| ``` |
| |
| The output should look like: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| You are using the new fx test, which is currently ready for general use âś… |
| See details here: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/scripts/fxtest/rewrite |
| To go back to the old fx test, use `fx --enable=legacy_fxtest test`, and please file a bug under b/293917801. |
| |
| Default flags loaded from /usr/local/google/home/jruthe/.fxtestrc: |
| [] |
| |
| Logging all output to: /usr/local/google/home/jruthe/upstream/fuchsia/out/workbench_eng.x64/fxtest-2024-03-25T15:56:31.874893.log.json.gz |
| Use the `--logpath` argument to specify a log location or `--no-log` to disable |
| |
| To show all output, specify the `-o/--output` flag. |
| |
| Found 913 total tests in //out/workbench_eng.x64/tests.json |
| |
| Plan to run 1 test |
| |
| Refreshing 1 target |
| > fx build src/developer/debug/debug_agent:debug_agent_unit_tests host_x64/debug_agent_unit_tests |
| Use --no-build to skip building |
| |
| Executing build. Status output suspended. |
| ninja: Entering directory `/usr/local/google/home/jruthe/upstream/fuchsia/out/workbench_eng.x64' |
| [22/22](0) STAMP obj/src/developer/debug/debug_agent/debug_agent_unit_tests.stamp |
| |
| Running 1 test |
| |
| Starting: fuchsia-pkg://fuchsia.com/debug_agent_unit_tests#meta/debug_agent_unit_tests.cm (NOT HERMETIC) |
| Command: fx ffx test run --realm /core/testing/system-tests --max-severity-logs WARN --break-on-failure fuchsia-pkg://fuchsia.com/debug_agent_unit_tests?hash=399ff8d9871a6f0d53557c3d7c233cad645061016d44a7855dcea2c7b8af8101#meta/debug_agent_unit_tests.cm |
| Deleting 1 files at /tmp/tmp8m56ht95: ffx_logs/ffx.log |
| To keep these files, set --ffx-output-directory. |
| |
| PASSED: fuchsia-pkg://fuchsia.com/debug_agent_unit_tests#meta/debug_agent_unit_tests.cm |
| |
| Status: [duration: 16.9s] [tests: PASS: 1 FAIL: 0 SKIP: 0] |
| Running 1 tests [=====================================================================================================] 100.0% |
| ``` |
| |
| zxdb no longer appears, because you have successfully fixed all of the test |
| failures! |
| |
| [debug-agent-test-example]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/developer/debug/debug_agent/debug_agent_unittest.cc;l=64-148;drc=0ebebaff9f1f0f4b48325c9d63fddda924cd8da7 |
| [rust-calculator-test-example]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/fidl/calculator/rust/client/src/main.rs;l=99;drc=97a1774dd7457ffec1ffcebf81e35b7695a4cf54 |
| [rust-test-runner]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/sys/test_runners/rust/ |
| [rust-test-runner-parallel-default]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/sys/test_runners/rust/src/test_server.rs;l=48;drc=906023d3bdbf3d0aeb3b1080b2cdeb316112112f |
| [zxdb-test-doc]: /docs/development/debugger/tests.md |
| [zxdb-parallel-tests]: /docs/development/debugger/tests.md#executing-test-cases-in-parallel |