blob: ea197f524747bbf01588a82e1172c436da572690 [file] [log] [blame]
// 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());
}