blob: 7b018f72f9869661cef52f83e62293881a9177d2 [file]
// Copyright 2026 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 "src/developer/debug/zxdb/debug_adapter/handlers/request_terminate.h"
#include <gtest/gtest.h>
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/target_impl.h"
#include "src/developer/debug/zxdb/debug_adapter/context_test.h"
namespace zxdb {
namespace {
class RequestTerminateTest : public DebugAdapterContextTest {};
TEST_F(RequestTerminateTest, TerminateSpecificTargetByKoid) {
InitializeDebugging();
auto target_impls = session().system().GetTargetImpls();
ASSERT_EQ(1u, target_impls.size());
TargetImpl* target1 = target_impls[0];
target1->CreateProcess(Process::StartType::kLaunch, kProcessKoid, "process1", 0, {},
std::nullopt);
TargetImpl* target2 = session().system().CreateNewTargetImpl(nullptr);
target2->CreateProcess(Process::StartType::kAttach, kProcessKoid + 1, "process2", 0, {},
std::nullopt);
ASSERT_EQ(session().system().GetTargets().size(), 2u);
RunClient();
// Explicitly terminate target1 (kProcessKoid)
dap::ZxdbTerminateRequest request = {};
request.koid = kProcessKoid;
auto response = client().send(request);
context().OnStreamReadable();
loop().RunUntilNoTasks();
RunPendingClientCalls();
auto got = response.get();
EXPECT_FALSE(got.error);
// target1 should be killed/terminated
EXPECT_EQ(target1->GetState(), Target::State::kNone);
EXPECT_EQ(target1->GetProcess(), nullptr);
// target2 should be left completely untouched and running!
EXPECT_EQ(target2->GetState(), Target::State::kRunning);
EXPECT_NE(target2->GetProcess(), nullptr);
}
TEST_F(RequestTerminateTest, TerminateInvalidKoidValue) {
InitializeDebugging();
auto target_impls = session().system().GetTargetImpls();
ASSERT_EQ(1u, target_impls.size());
TargetImpl* target = target_impls[0];
target->CreateProcess(Process::StartType::kLaunch, kProcessKoid, "process1", 0, {}, std::nullopt);
RunClient();
// Terminate with unknown KOID
dap::ZxdbTerminateRequest request = {};
request.koid = kProcessKoid + 999;
auto response = client().send(request);
context().OnStreamReadable();
loop().RunUntilNoTasks();
RunPendingClientCalls();
auto got = response.get();
EXPECT_TRUE(got.error);
}
TEST_F(RequestTerminateTest, TerminateNonPositiveKoid) {
InitializeDebugging();
RunClient();
// Test KOID = 0
{
dap::ZxdbTerminateRequest request = {};
request.koid = 0;
auto response = client().send(request);
context().OnStreamReadable();
loop().RunUntilNoTasks();
RunPendingClientCalls();
auto got = response.get();
EXPECT_TRUE(got.error);
}
// Test KOID = -5 (negative values)
{
dap::ZxdbTerminateRequest request = {};
request.koid = -5;
auto response = client().send(request);
context().OnStreamReadable();
loop().RunUntilNoTasks();
RunPendingClientCalls();
auto got = response.get();
EXPECT_TRUE(got.error);
}
}
TEST_F(RequestTerminateTest, TerminateWithoutKoidFails) {
InitializeDebugging();
auto target_impls = session().system().GetTargetImpls();
ASSERT_EQ(1u, target_impls.size());
TargetImpl* target = target_impls[0];
target->CreateProcess(Process::StartType::kLaunch, kProcessKoid, "process1", 0, {}, std::nullopt);
RunClient();
dap::ZxdbTerminateRequest request = {};
auto response = client().send(request);
context().OnStreamReadable();
loop().RunUntilNoTasks();
RunPendingClientCalls();
auto got = response.get();
EXPECT_TRUE(got.error);
EXPECT_EQ(got.error.message, "zxdb does not support terminate without a process KOID.");
EXPECT_EQ(target->GetState(), Target::State::kRunning);
EXPECT_NE(target->GetProcess(), nullptr);
}
} // namespace
} // namespace zxdb