blob: b9e395346617680e37ee428819abe81e86d03a1a [file] [log] [blame]
// Copyright 2022 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/lib/fidl/contrib/fpromise/client.h"
#include <fidl/test.basic.protocol/cpp/fidl.h>
#include <fidl/test.error.methods/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/executor.h>
#include <lib/fpromise/promise.h>
#include <zxtest/zxtest.h>
namespace {
const std::string kExpectedReply = "7";
struct EchoServer : fidl::Server<test_basic_protocol::ValueEcho> {
void Echo(EchoRequest& request, EchoCompleter::Sync& completer) override {
completer.Reply(request.s());
}
};
TEST(Client, Promisify) {
auto server = std::make_unique<EchoServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_basic_protocol::ValueEcho>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<test_basic_protocol::ValueEchoEchoResponse, fidl::Error> p =
fidl_fpromise::as_promise(client->Echo({kExpectedReply}));
auto task = p.then(
[&](fpromise::result<test_basic_protocol::ValueEchoEchoResponse, fidl::Error>& result) {
ASSERT_TRUE(result.is_ok());
ASSERT_EQ(kExpectedReply, result.value());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
TEST(Client, PromisifyChaining) {
auto server = std::make_unique<EchoServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_basic_protocol::ValueEcho>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
// Chain another continuation which operates on the FIDL result.
auto p = fidl_fpromise::as_promise(client->Echo({kExpectedReply}))
.and_then([&](const test_basic_protocol::ValueEchoEchoResponse& payload) {
return fpromise::ok(std::stoi(payload.s()));
});
// |p| is now transformed to a promise that resolves to a string.
auto task = p.then([&](fpromise::result<int, fidl::Error>& result) {
ASSERT_TRUE(result.is_ok());
ASSERT_EQ(7, result.value());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
TEST(Client, PromisifyTransportError) {
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_basic_protocol::ValueEcho>::Create();
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<test_basic_protocol::ValueEchoEchoResponse, fidl::Error> p =
fidl_fpromise::as_promise(client->Echo({kExpectedReply}));
endpoints.server.reset();
auto task = p.then(
[&](fpromise::result<test_basic_protocol::ValueEchoEchoResponse, fidl::Error>& result) {
ASSERT_TRUE(result.is_error());
ASSERT_TRUE(result.error().is_peer_closed());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
class ErrorServer : public fidl::Server<test_error_methods::ErrorMethods> {
void NoArgsPrimitiveError(NoArgsPrimitiveErrorRequest& request,
NoArgsPrimitiveErrorCompleter::Sync& completer) final {
completer.Reply(fit::error(42));
}
void ManyArgsCustomError(ManyArgsCustomErrorRequest& request,
ManyArgsCustomErrorCompleter::Sync& completer) final {
completer.Reply(fit::error(test_error_methods::MyError::kBadError));
}
};
TEST(Client, PromisifyApplicationErrorMethodCasePrimitiveError) {
auto server = std::make_unique<ErrorServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_error_methods::ErrorMethods>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<void, fidl::ErrorsIn<test_error_methods::ErrorMethods::NoArgsPrimitiveError>>
p = fidl_fpromise::as_promise(client->NoArgsPrimitiveError({{.should_error = true}}));
endpoints.server.reset();
auto task = p.then(
[&](fpromise::result<
void, fidl::ErrorsIn<test_error_methods::ErrorMethods::NoArgsPrimitiveError>>& result) {
ASSERT_TRUE(result.is_error());
ASSERT_TRUE(result.error().is_domain_error());
ASSERT_EQ(42, result.error().domain_error());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
TEST(Client, PromisifyApplicationErrorMethodCaseCustomError) {
auto server = std::make_unique<ErrorServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_error_methods::ErrorMethods>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<test_error_methods::ErrorMethodsManyArgsCustomErrorResponse,
fidl::ErrorsIn<test_error_methods::ErrorMethods::ManyArgsCustomError>>
p = fidl_fpromise::as_promise(client->ManyArgsCustomError({{.should_error = true}}));
auto task = p.then(
[&](fpromise::result<test_error_methods::ErrorMethodsManyArgsCustomErrorResponse,
fidl::ErrorsIn<test_error_methods::ErrorMethods::ManyArgsCustomError>>&
result) {
ASSERT_TRUE(result.is_error());
ASSERT_TRUE(result.error().is_domain_error());
ASSERT_EQ(test_error_methods::MyError::kBadError, result.error().domain_error());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
class SuccessServer : public fidl::Server<test_error_methods::ErrorMethods> {
void NoArgsPrimitiveError(NoArgsPrimitiveErrorRequest& request,
NoArgsPrimitiveErrorCompleter::Sync& completer) final {
completer.Reply(fit::ok());
}
void ManyArgsCustomError(ManyArgsCustomErrorRequest& request,
ManyArgsCustomErrorCompleter::Sync& completer) final {
completer.Reply(fit::ok(
test_error_methods::ErrorMethodsManyArgsCustomErrorResponse{{.a = 1, .b = 2, .c = 3}}));
}
};
TEST(Client, PromisifyApplicationErrorMethodCaseNoArgsSuccess) {
auto server = std::make_unique<SuccessServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_error_methods::ErrorMethods>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<void, fidl::ErrorsIn<test_error_methods::ErrorMethods::NoArgsPrimitiveError>>
p = fidl_fpromise::as_promise(client->NoArgsPrimitiveError({{.should_error = false}}));
auto task = p.then(
[&](fpromise::result<
void, fidl::ErrorsIn<test_error_methods::ErrorMethods::NoArgsPrimitiveError>>& result) {
ASSERT_TRUE(result.is_ok());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
TEST(Client, PromisifyApplicationErrorMethodCaseManyArgsSuccess) {
auto server = std::make_unique<SuccessServer>();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async::Executor executor(loop.dispatcher());
auto endpoints = fidl::Endpoints<test_error_methods::ErrorMethods>::Create();
fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), server.get());
fidl::Client client(std::move(endpoints.client), loop.dispatcher());
fpromise::promise<test_error_methods::ErrorMethodsManyArgsCustomErrorResponse,
fidl::ErrorsIn<test_error_methods::ErrorMethods::ManyArgsCustomError>>
p = fidl_fpromise::as_promise(client->ManyArgsCustomError({{.should_error = false}}));
auto task = p.then(
[&](fpromise::result<test_error_methods::ErrorMethodsManyArgsCustomErrorResponse,
fidl::ErrorsIn<test_error_methods::ErrorMethods::ManyArgsCustomError>>&
result) {
ASSERT_TRUE(result.is_ok());
ASSERT_EQ(test_error_methods::ErrorMethodsManyArgsCustomErrorResponse(1, 2, 3),
result.value());
loop.Quit();
});
executor.schedule_task(std::move(task));
ASSERT_STATUS(ZX_ERR_CANCELED, loop.Run());
}
} // namespace