blob: 7de33beae3bae556c4ef245d19bef31f7eb2ce58 [file] [log] [blame]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/devtools/devtools_http_service_handler.h"
#include "base/memory/ptr_util.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "chrome/browser/devtools/devtools_dispatch_http_request_params.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/test/base/testing_profile.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/url_loader_interceptor.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// This class uses the actual implementation of the CanMakeRequest
class TestServiceHandler : public DevToolsHttpServiceHandler {
public:
TestServiceHandler() = default;
~TestServiceHandler() override = default;
GURL BaseURL() const override { return GURL("http://localhost:8000"); }
signin::OAuthConsumerId OAuthConsumerId() const override {
return signin::OAuthConsumerId::kDevtoolsAida;
}
net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag()
const override {
return TRAFFIC_ANNOTATION_FOR_TESTS;
}
};
class DevToolsHttpServiceHandlerTest : public testing::Test {
protected:
void SetUp() override {
profile_ = IdentityTestEnvironmentProfileAdaptor::
CreateProfileForIdentityTestEnvironment();
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
mock_handler_ = base::WrapUnique(new TestServiceHandler());
params_.service = "unknownService";
params_.path = "/path";
params_.method = "GET";
interceptor_ = std::make_unique<content::URLLoaderInterceptor>(
base::BindRepeating(&DevToolsHttpServiceHandlerTest::InterceptRequest,
base::Unretained(this)));
}
void TearDown() override {
interceptor_.reset();
mock_handler_.reset();
identity_test_env_adaptor_.reset();
profile_.reset();
}
bool InterceptRequest(content::URLLoaderInterceptor::RequestParams* params) {
if (intercept_callback_) {
return intercept_callback_.Run(params);
}
return false;
}
DevToolsDispatchHttpRequestParams params_;
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
std::unique_ptr<TestServiceHandler> mock_handler_;
std::unique_ptr<content::URLLoaderInterceptor> interceptor_;
base::RepeatingCallback<bool(content::URLLoaderInterceptor::RequestParams*)>
intercept_callback_;
};
TEST_F(DevToolsHttpServiceHandlerTest, RequestWithNullProfileFails) {
base::test::TestFuture<std::unique_ptr<DevToolsHttpServiceHandler::Result>>
result_future;
mock_handler_->Request(nullptr, params_, std::nullopt,
result_future.GetCallback());
std::unique_ptr<DevToolsHttpServiceHandler::Result> result =
result_future.Take();
ASSERT_TRUE(result);
EXPECT_EQ(result->error,
DevToolsHttpServiceHandler::Result::Error::kValidationFailed);
}
TEST_F(DevToolsHttpServiceHandlerTest, RequestWithOTRProfileFails) {
base::test::TestFuture<std::unique_ptr<DevToolsHttpServiceHandler::Result>>
result_future;
auto* incognito_profile = profile_->GetPrimaryOTRProfile(true);
mock_handler_->Request(incognito_profile, params_, std::nullopt,
result_future.GetCallback());
std::unique_ptr<DevToolsHttpServiceHandler::Result> result =
result_future.Take();
ASSERT_TRUE(result);
EXPECT_EQ(result->error,
DevToolsHttpServiceHandler::Result::Error::kValidationFailed);
}
TEST_F(DevToolsHttpServiceHandlerTest, RequestStreamingSuccess) {
std::string received_data;
auto stream_writer = base::BindLambdaForTesting(
[&received_data](std::string_view chunk) { received_data += chunk; });
intercept_callback_ = base::BindLambdaForTesting(
[](content::URLLoaderInterceptor::RequestParams* params) {
content::URLLoaderInterceptor::WriteResponse(
"HTTP/1.1 200 OK\nContent-Type: text/plain\n\n", "Hello, world!",
params->client.get());
return true;
});
base::test::TestFuture<std::unique_ptr<DevToolsHttpServiceHandler::Result>>
result_future;
identity_test_env_adaptor_->identity_test_env()->MakePrimaryAccountAvailable(
"test@google.com", signin::ConsentLevel::kSignin);
mock_handler_->Request(profile_.get(), params_, std::move(stream_writer),
result_future.GetCallback());
identity_test_env_adaptor_->identity_test_env()
->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"test_token", base::Time::Max());
std::unique_ptr<DevToolsHttpServiceHandler::Result> result =
result_future.Take();
ASSERT_TRUE(result);
EXPECT_EQ(result->error, DevToolsHttpServiceHandler::Result::Error::kNone);
EXPECT_EQ(result->http_status, 200);
EXPECT_EQ(received_data, "Hello, world!");
EXPECT_TRUE(!result->response_body.has_value());
}
TEST_F(DevToolsHttpServiceHandlerTest, RequestStreamingNetworkError) {
auto stream_writer =
base::BindLambdaForTesting([](std::string_view chunk) {});
intercept_callback_ = base::BindLambdaForTesting(
[](content::URLLoaderInterceptor::RequestParams* params) {
params->client->OnComplete(
network::URLLoaderCompletionStatus(net::ERR_FAILED));
return true;
});
base::test::TestFuture<std::unique_ptr<DevToolsHttpServiceHandler::Result>>
result_future;
identity_test_env_adaptor_->identity_test_env()->MakePrimaryAccountAvailable(
"test@google.com", signin::ConsentLevel::kSignin);
mock_handler_->Request(profile_.get(), params_, std::move(stream_writer),
result_future.GetCallback());
identity_test_env_adaptor_->identity_test_env()
->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"test_token", base::Time::Max());
std::unique_ptr<DevToolsHttpServiceHandler::Result> result =
result_future.Take();
ASSERT_TRUE(result);
EXPECT_EQ(result->error,
DevToolsHttpServiceHandler::Result::Error::kNetworkError);
EXPECT_EQ(result->net_error, net::ERR_FAILED);
}
TEST_F(DevToolsHttpServiceHandlerTest, RequestStreamingHttpError) {
auto stream_writer =
base::BindLambdaForTesting([](std::string_view chunk) {});
intercept_callback_ = base::BindLambdaForTesting(
[](content::URLLoaderInterceptor::RequestParams* params) {
content::URLLoaderInterceptor::WriteResponse(
"HTTP/1.1 500 Internal Server Error\n\n", "Error",
params->client.get());
return true;
});
base::test::TestFuture<std::unique_ptr<DevToolsHttpServiceHandler::Result>>
result_future;
identity_test_env_adaptor_->identity_test_env()->MakePrimaryAccountAvailable(
"test@google.com", signin::ConsentLevel::kSignin);
mock_handler_->Request(profile_.get(), params_, std::move(stream_writer),
result_future.GetCallback());
identity_test_env_adaptor_->identity_test_env()
->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"test_token", base::Time::Max());
std::unique_ptr<DevToolsHttpServiceHandler::Result> result =
result_future.Take();
ASSERT_TRUE(result);
EXPECT_EQ(result->error,
DevToolsHttpServiceHandler::Result::Error::kHttpError);
EXPECT_EQ(result->http_status, 500);
}
} // namespace