| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "task_tree.h" |
| |
| #include <lib/zx/object.h> |
| #include <zircon/process.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include "info_resource.h" |
| |
| class TaskTreeForTesting : public ::harvester::TaskTree { |
| public: |
| std::map<zx_koid_t, zx_handle_t> KoidsToHandles() { |
| return koids_to_handles_; |
| } |
| |
| void ClearForTesting() { Clear(); } |
| }; |
| |
| class TaskTreeTest : public ::testing::Test { |
| public: |
| void SetUp() override {} |
| |
| TaskTreeForTesting& tree() { return task_tree_; } |
| |
| private: |
| TaskTreeForTesting task_tree_; |
| }; |
| |
| TEST_F(TaskTreeTest, Test) { |
| EXPECT_EQ(0U, tree().Jobs().size()); |
| EXPECT_EQ(0U, tree().Processes().size()); |
| EXPECT_EQ(0U, tree().Threads().size()); |
| |
| tree().Gather(); |
| EXPECT_NE(0U, tree().Jobs().size()); |
| EXPECT_NE(0U, tree().Processes().size()); |
| EXPECT_NE(0U, tree().Threads().size()); |
| |
| // The tree is walked from the root job. So as we iterate over the jobs, |
| // processes, and threads (in that order) well will have visited the parent |
| // of each object. Use this set to see that the parent exists. |
| std::set<zx_koid_t> koids; |
| bool found_root = false; |
| |
| for (const auto& entry : tree().Jobs()) { |
| EXPECT_NE(ZX_HANDLE_INVALID, entry.handle); |
| if (entry.koid == 0U) { |
| found_root = true; |
| } else { |
| // This job's parent should be in the set. |
| EXPECT_NE(koids.end(), koids.find(entry.parent_koid)); |
| EXPECT_NE(entry.koid, entry.parent_koid); |
| } |
| |
| EXPECT_EQ(koids.end(), koids.find(entry.koid)); |
| koids.emplace(entry.koid); |
| } |
| |
| EXPECT_TRUE(found_root); |
| |
| for (const auto& entry : tree().Processes()) { |
| EXPECT_NE(ZX_HANDLE_INVALID, entry.handle); |
| EXPECT_NE(0U, entry.koid); |
| EXPECT_NE(entry.koid, entry.parent_koid); |
| // This process's parent should be in the set. |
| EXPECT_NE(koids.end(), koids.find(entry.parent_koid)); |
| |
| EXPECT_EQ(koids.end(), koids.find(entry.koid)); |
| koids.emplace(entry.koid); |
| } |
| |
| for (const auto& entry : tree().Threads()) { |
| EXPECT_NE(ZX_HANDLE_INVALID, entry.handle); |
| EXPECT_NE(0U, entry.koid); |
| EXPECT_NE(0U, entry.parent_koid); |
| EXPECT_NE(entry.koid, entry.parent_koid); |
| // This thread's parent should be in the set. |
| EXPECT_NE(koids.end(), koids.find(entry.parent_koid)); |
| |
| EXPECT_EQ(koids.end(), koids.find(entry.koid)); |
| koids.emplace(entry.koid); |
| } |
| |
| size_t total_entries = tree().Jobs().size() + tree().Processes().size() + |
| tree().Threads().size(); |
| EXPECT_EQ(total_entries, koids.size()); |
| EXPECT_EQ(total_entries, tree().KoidsToHandles().size()); |
| |
| // Our koid should appear somewhere in the list. |
| zx_info_handle_basic_t info; |
| zx_status_t status = zx_object_get_info( |
| zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info), |
| /*actual=*/nullptr, /*avail=*/nullptr); |
| ASSERT_EQ(status, ZX_OK); |
| EXPECT_NE(koids.end(), koids.find(info.koid)); |
| |
| tree().ClearForTesting(); |
| EXPECT_EQ(0U, tree().Jobs().size()); |
| EXPECT_EQ(0U, tree().Processes().size()); |
| EXPECT_EQ(0U, tree().Threads().size()); |
| EXPECT_EQ(0U, tree().KoidsToHandles().size()); |
| } |