LibWebView+UI: Read and set echo server port in HttpEchoServerFixture

This commit adds a "echo_server_port" property to `WebContentOptions`.

Additionally, it makes `Application::web_content_options()` return a
mutable reference instead of a const reference so that we can set the
port value from the fixture.
This commit is contained in:
rmg-x 2024-12-02 19:33:26 -06:00 committed by Andrew Kaster
parent aa4dcca0b2
commit ece611718d
Notes: github-actions[bot] 2024-12-06 00:09:27 +00:00
5 changed files with 40 additions and 19 deletions

View file

@ -34,7 +34,7 @@ public:
static Application& the() { return *s_the; }
static ChromeOptions const& chrome_options() { return the().m_chrome_options; }
static WebContentOptions const& web_content_options() { return the().m_web_content_options; }
static WebContentOptions& web_content_options() { return the().m_web_content_options; }
static Requests::RequestClient& request_server_client() { return *the().m_request_server_client; }
static ImageDecoderClient::Client& image_decoder_client() { return *the().m_image_decoder_client; }

View file

@ -127,6 +127,7 @@ struct WebContentOptions {
ForceFontconfig force_fontconfig { ForceFontconfig::No };
EnableAutoplay enable_autoplay { EnableAutoplay::No };
CollectGarbageOnEveryAllocation collect_garbage_on_every_allocation { CollectGarbageOnEveryAllocation::No };
Optional<u16> echo_server_port {};
};
}

View file

@ -93,10 +93,11 @@ ErrorOr<void> Application::launch_test_fixtures()
// FIXME: Add option to only run specific fixtures from command line by name
// And an option to not run any fixtures at all
for (auto& fixture : Fixture::all()) {
if (auto result = fixture->setup(); result.is_error())
for (auto const& fixture : Fixture::all()) {
if (auto result = fixture->setup(web_content_options()); result.is_error())
return result;
}
return {};
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/ByteBuffer.h>
#include <AK/LexicalPath.h>
#include <LibCore/Process.h>
#include <LibCore/StandardPaths.h>
@ -19,7 +20,7 @@ Fixture::~Fixture() = default;
Optional<Fixture&> Fixture::lookup(StringView name)
{
for (auto& fixture : all()) {
for (auto const& fixture : all()) {
if (fixture->name() == name)
return *fixture;
}
@ -34,7 +35,7 @@ Vector<NonnullOwnPtr<Fixture>>& Fixture::all()
class HttpEchoServerFixture final : public Fixture {
public:
virtual ErrorOr<void> setup() override;
virtual ErrorOr<void> setup(WebView::WebContentOptions&) override;
virtual void teardown_impl() override;
virtual StringView name() const override { return "HttpEchoServer"sv; }
virtual bool is_running() const override { return m_process.has_value(); }
@ -44,26 +45,41 @@ private:
Optional<Core::Process> m_process;
};
ErrorOr<void> HttpEchoServerFixture::setup()
ErrorOr<void> HttpEchoServerFixture::setup(WebView::WebContentOptions& web_content_options)
{
auto script_path = LexicalPath::join(s_fixtures_path, m_script_path);
auto const script_path = LexicalPath::join(s_fixtures_path, m_script_path);
auto const arguments = Vector { script_path.string(), "--directory", Ladybird::Application::the().test_root_path };
// FIXME: Pick a more reasonable log path that is more observable
auto log_path = LexicalPath::join(Core::StandardPaths::tempfile_directory(), "http-test-server.log"sv).string();
auto const log_path = LexicalPath::join(Core::StandardPaths::tempfile_directory(), "http-test-server.log"sv).string();
auto arguments = Vector { script_path.string(), "start", "--directory", Ladybird::Application::the().test_root_path };
auto process_options = Core::ProcessSpawnOptions {
auto stdout_fds = TRY(Core::System::pipe2(0));
auto const process_options = Core::ProcessSpawnOptions {
.executable = Ladybird::Application::the().python_executable_path,
.search_for_executable_in_path = true,
.arguments = arguments,
.file_actions = {
Core::FileAction::OpenFile { ByteString::formatted("{}.stdout", log_path), Core::File::OpenMode::Write, STDOUT_FILENO },
Core::FileAction::OpenFile { ByteString::formatted("{}.stderr", log_path), Core::File::OpenMode::Write, STDERR_FILENO },
}
Core::FileAction::DupFd { stdout_fds[1], STDOUT_FILENO } }
};
m_process = TRY(Core::Process::spawn(process_options));
TRY(Core::System::close(stdout_fds[1]));
auto const stdout_file = MUST(Core::File::adopt_fd(stdout_fds[0], Core::File::OpenMode::Read));
auto buffer = MUST(ByteBuffer::create_uninitialized(5));
TRY(stdout_file->read_some(buffer));
auto const raw_output = ByteString { buffer, AK::ShouldChomp::NoChomp };
if (auto const maybe_port = raw_output.to_number<u16>(); maybe_port.has_value())
web_content_options.echo_server_port = maybe_port.value();
else
warnln("Failed to read echo server port from buffer: '{}'", raw_output);
return {};
}
@ -73,14 +89,17 @@ void HttpEchoServerFixture::teardown_impl()
auto script_path = LexicalPath::join(s_fixtures_path, m_script_path);
auto ret = Core::System::kill(m_process->pid(), SIGINT);
if (ret.is_error() && ret.error().code() != ESRCH) {
warnln("Failed to kill http-test-server.py: {}", ret.error());
m_process = {};
return;
if (auto kill_or_error = Core::System::kill(m_process->pid(), SIGINT); kill_or_error.is_error()) {
if (kill_or_error.error().code() != ESRCH) {
warnln("Failed to kill HTTP echo server, error: {}", kill_or_error.error());
m_process = {};
return;
}
}
MUST(m_process->wait_for_termination());
if (auto termination_or_error = m_process->wait_for_termination(); termination_or_error.is_error()) {
warnln("Failed to terminate HTTP echo server, error: {}", termination_or_error.error());
}
m_process = {};
}

View file

@ -18,7 +18,7 @@ class Fixture {
public:
virtual ~Fixture();
virtual ErrorOr<void> setup() = 0;
virtual ErrorOr<void> setup(WebView::WebContentOptions&) = 0;
void teardown()
{