blob: 6f360fee03696fa3b6334641ea45a5bea132421d [file] [log] [blame]
// Copyright 2021 The Chromium 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 "content/services/auction_worklet/worklet_devtools_debug_test_util.h"
#include <string>
#include <utility>
#include <vector>
#include "base/json/json_reader.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/json.h"
#include "third_party/inspector_protocol/crdtp/span.h"
namespace auction_worklet {
namespace {
crdtp::span<uint8_t> ToSpan(const mojo_base::BigBuffer& buffer) {
return crdtp::span<uint8_t>(buffer.data(), buffer.size());
}
crdtp::span<uint8_t> ToSpan(const std::string& string) {
return crdtp::span<uint8_t>(reinterpret_cast<const uint8_t*>(string.data()),
string.size());
}
std::string ToString(const std::vector<uint8_t>& vector) {
return std::string(reinterpret_cast<const char*>(vector.data()),
vector.size());
}
std::string ToString(crdtp::span<uint8_t> span) {
return std::string(reinterpret_cast<const char*>(span.data()), span.size());
}
} // namespace
TestDevToolsAgentClient::TestDevToolsAgentClient(
mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent,
std::string session_id,
bool use_binary_protocol)
: session_id_(std::move(session_id)),
use_binary_protocol_(use_binary_protocol),
agent_(std::move(agent)),
receiver_(this) {
agent_->AttachDevToolsSession(receiver_.BindNewEndpointAndPassRemote(),
session_.BindNewEndpointAndPassReceiver(),
io_session_.BindNewPipeAndPassReceiver(),
nullptr, use_binary_protocol_, session_id_);
}
TestDevToolsAgentClient::~TestDevToolsAgentClient() = default;
void TestDevToolsAgentClient::RunCommand(Channel channel,
int call_id,
std::string method,
std::string payload) {
base::span<const uint8_t> message;
std::vector<uint8_t> cbor;
if (use_binary_protocol_) {
// JSON -> CBOR.
crdtp::Status status =
crdtp::json::ConvertJSONToCBOR(ToSpan(payload), &cbor);
CHECK(status.ok()) << status.Message();
message = base::span<const uint8_t>(cbor.data(), cbor.size());
} else {
// Keep it JSON.
message = base::span<const uint8_t>(
reinterpret_cast<const uint8_t*>(payload.data()), payload.size());
}
if (channel == Channel::kMain)
session_->DispatchProtocolCommand(call_id, method, message);
else
io_session_->DispatchProtocolCommand(call_id, method, message);
}
TestDevToolsAgentClient::Event
TestDevToolsAgentClient::RunCommandAndWaitForResult(Channel channel,
int call_id,
std::string method,
std::string payload) {
RunCommand(channel, call_id, std::move(method), std::move(payload));
return WaitForEvent(base::BindRepeating(
[](int call_id, const Event& event) {
return event.type == Event::Type::kResponse &&
event.call_id == call_id &&
event.value.FindIntKey("id").value_or(-call_id) == call_id;
},
call_id));
}
TestDevToolsAgentClient::Event TestDevToolsAgentClient::WaitForEvent(
const EventPredicate& predicate) {
while (true) {
while (!events_.empty()) {
Event event = std::move(*events_.begin());
events_.pop_front();
if (predicate.Run(event))
return event;
}
// Note that this can't be using TaskEnvironment::RunUntilIdle() since it
// can be used when the V8 thread may be sleeping inside
// DebugCommandQueue::PauseForDebuggerAndRunCommands().
base::RunLoop().RunUntilIdle();
}
}
TestDevToolsAgentClient::Event
TestDevToolsAgentClient::WaitForMethodNotification(std::string method) {
return WaitForEvent(base::BindRepeating(
[](std::string method, const Event& event) -> bool {
if (event.type != Event::Type::kNotification)
return false;
const std::string* candidate_method =
event.value.FindStringKey("method");
return (candidate_method && *candidate_method == method);
},
method));
}
void TestDevToolsAgentClient::DispatchProtocolResponse(
blink::mojom::DevToolsMessagePtr message,
int32_t call_id,
blink::mojom::DevToolsSessionStatePtr updates) {
LogEvent(Event::Type::kResponse, call_id, std::move(message));
}
void TestDevToolsAgentClient::DispatchProtocolNotification(
blink::mojom::DevToolsMessagePtr message,
blink::mojom::DevToolsSessionStatePtr updates) {
LogEvent(Event::Type::kNotification, -1, std::move(message));
}
void TestDevToolsAgentClient::LogEvent(
Event::Type type,
int call_id,
blink::mojom::DevToolsMessagePtr message) {
crdtp::span<uint8_t> payload = ToSpan(message->data);
EXPECT_EQ(use_binary_protocol_, crdtp::cbor::IsCBORMessage(payload));
std::string payload_json;
if (use_binary_protocol_) {
// CBOR -> JSON.
std::vector<uint8_t> json;
crdtp::Status status = crdtp::json::ConvertCBORToJSON(payload, &json);
CHECK(status.ok()) << status.Message();
payload_json = ToString(json);
} else {
payload_json = ToString(payload);
}
// Now make it into a base::Value, to make it easy to look stuff up in it,
// and queue it.
absl::optional<base::Value> val = base::JSONReader::Read(payload_json);
CHECK(val.has_value());
Event event;
event.type = type;
event.call_id = call_id;
event.value = std::move(val.value());
// Make sure it has proper session ID.
const std::string* session = event.value.FindStringPath("sessionId");
ASSERT_TRUE(session);
EXPECT_EQ(session_id_, *session);
events_.push_back(std::move(event));
}
std::string MakeInstrumentationBreakpointCommand(int seq_number,
const char* verb,
const char* event_name) {
const char kTemplate[] = R"({
"id":%d,
"method":"EventBreakpoints.%sInstrumentationBreakpoint",
"params": {
"eventName": "%s"
}})";
return base::StringPrintf(kTemplate, seq_number, verb, event_name);
}
} // namespace auction_worklet