334 lines
11 KiB
C++
334 lines
11 KiB
C++
// Copyright 2021 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_rpc/raw/client_reader_writer.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_rpc/raw/client_testing.h"
|
|
#include "pw_rpc/writer.h"
|
|
#include "pw_rpc_test_protos/test.raw_rpc.pb.h"
|
|
|
|
namespace pw::rpc {
|
|
namespace {
|
|
|
|
using test::pw_rpc::raw::TestService;
|
|
|
|
void FailIfCalled(Status) { FAIL(); }
|
|
void FailIfOnNextCalled(ConstByteSpan) { FAIL(); }
|
|
void FailIfOnCompletedCalled(ConstByteSpan, Status) { FAIL(); }
|
|
|
|
TEST(RawUnaryReceiver, DefaultConstructed) {
|
|
RawUnaryReceiver call;
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
|
|
call.set_on_completed([](ConstByteSpan, Status) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientWriter, DefaultConstructed) {
|
|
RawClientWriter call;
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Write({}));
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.CloseClientStream());
|
|
|
|
call.set_on_completed([](ConstByteSpan, Status) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientReader, DefaultConstructed) {
|
|
RawClientReader call;
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
|
|
call.set_on_completed([](Status) {});
|
|
call.set_on_next([](ConstByteSpan) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientReaderWriter, DefaultConstructed) {
|
|
RawClientReaderWriter call;
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Write({}));
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.CloseClientStream());
|
|
|
|
call.set_on_completed([](Status) {});
|
|
call.set_on_next([](ConstByteSpan) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawUnaryReceiver, Closed) {
|
|
RawClientTestContext ctx;
|
|
RawUnaryReceiver call = TestService::TestUnaryRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
{},
|
|
FailIfOnCompletedCalled,
|
|
FailIfCalled);
|
|
ASSERT_EQ(OkStatus(), call.Cancel());
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
|
|
call.set_on_completed([](ConstByteSpan, Status) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientWriter, Closed) {
|
|
RawClientTestContext ctx;
|
|
RawClientWriter call = TestService::TestClientStreamRpc(
|
|
ctx.client(), ctx.channel().id(), FailIfOnCompletedCalled, FailIfCalled);
|
|
ASSERT_EQ(OkStatus(), call.Cancel());
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Write({}));
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.CloseClientStream());
|
|
|
|
call.set_on_completed([](ConstByteSpan, Status) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientReader, Closed) {
|
|
RawClientTestContext ctx;
|
|
RawClientReader call = TestService::TestServerStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
{},
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
FailIfCalled);
|
|
ASSERT_EQ(OkStatus(), call.Cancel());
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
|
|
call.set_on_completed([](Status) {});
|
|
call.set_on_next([](ConstByteSpan) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientReaderWriter, Closed) {
|
|
RawClientTestContext ctx;
|
|
RawClientReaderWriter call =
|
|
TestService::TestBidirectionalStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
FailIfCalled);
|
|
ASSERT_EQ(OkStatus(), call.Cancel());
|
|
|
|
ASSERT_FALSE(call.active());
|
|
EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId);
|
|
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Write({}));
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.Cancel());
|
|
EXPECT_EQ(Status::FailedPrecondition(), call.CloseClientStream());
|
|
|
|
call.set_on_completed([](Status) {});
|
|
call.set_on_next([](ConstByteSpan) {});
|
|
call.set_on_error([](Status) {});
|
|
}
|
|
|
|
TEST(RawClientReaderWriter, Move_InactiveToActive_EndsClientStream) {
|
|
RawClientTestContext ctx;
|
|
|
|
RawClientReaderWriter active_call =
|
|
TestService::TestBidirectionalStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
FailIfCalled);
|
|
|
|
ASSERT_EQ(ctx.output().total_packets(), 1u); // Sent the request
|
|
|
|
RawClientReaderWriter inactive_call;
|
|
|
|
active_call = std::move(inactive_call);
|
|
|
|
EXPECT_EQ(ctx.output().total_packets(), 2u); // Sent CLIENT_STREAM_END
|
|
EXPECT_EQ(
|
|
ctx.output()
|
|
.client_stream_end_packets<TestService::TestBidirectionalStreamRpc>(),
|
|
1u);
|
|
|
|
EXPECT_FALSE(active_call.active());
|
|
// NOLINTNEXTLINE(bugprone-use-after-move)
|
|
EXPECT_FALSE(inactive_call.active());
|
|
}
|
|
|
|
TEST(RawUnaryReceiver, Move_InactiveToActive_SilentlyCloses) {
|
|
RawClientTestContext ctx;
|
|
|
|
RawUnaryReceiver active_call =
|
|
TestService::TestUnaryRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
{},
|
|
FailIfOnCompletedCalled,
|
|
FailIfCalled);
|
|
|
|
ASSERT_EQ(ctx.output().total_packets(), 1u); // Sent the request
|
|
|
|
RawUnaryReceiver inactive_call;
|
|
|
|
active_call = std::move(inactive_call);
|
|
|
|
EXPECT_EQ(ctx.output().total_packets(), 1u); // No more packets
|
|
|
|
EXPECT_FALSE(active_call.active());
|
|
// NOLINTNEXTLINE(bugprone-use-after-move)
|
|
EXPECT_FALSE(inactive_call.active());
|
|
}
|
|
|
|
TEST(RawUnaryReceiver, Move_ActiveToActive) {
|
|
RawClientTestContext ctx;
|
|
|
|
RawUnaryReceiver active_call_1 =
|
|
TestService::TestUnaryRpc(ctx.client(), ctx.channel().id(), {});
|
|
|
|
RawUnaryReceiver active_call_2 =
|
|
TestService::TestAnotherUnaryRpc(ctx.client(), ctx.channel().id(), {});
|
|
|
|
ASSERT_EQ(ctx.output().total_packets(), 2u); // Sent the requests
|
|
ASSERT_TRUE(active_call_1.active());
|
|
ASSERT_TRUE(active_call_2.active());
|
|
|
|
active_call_2 = std::move(active_call_1);
|
|
|
|
EXPECT_EQ(ctx.output().total_packets(), 2u); // No more packets
|
|
|
|
// NOLINTNEXTLINE(bugprone-use-after-move)
|
|
EXPECT_FALSE(active_call_1.active());
|
|
EXPECT_TRUE(active_call_2.active());
|
|
}
|
|
|
|
TEST(RawClientReaderWriter, NewCallCancelsPreviousAndCallsErrorCallback) {
|
|
RawClientTestContext ctx;
|
|
|
|
Status error;
|
|
RawClientReaderWriter active_call_1 = TestService::TestBidirectionalStreamRpc(
|
|
ctx.client(),
|
|
ctx.channel().id(),
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
[&error](Status status) { error = status; });
|
|
|
|
ASSERT_TRUE(active_call_1.active());
|
|
|
|
RawClientReaderWriter active_call_2 =
|
|
TestService::TestBidirectionalStreamRpc(ctx.client(), ctx.channel().id());
|
|
|
|
EXPECT_FALSE(active_call_1.active());
|
|
EXPECT_TRUE(active_call_2.active());
|
|
EXPECT_EQ(error, Status::Cancelled());
|
|
}
|
|
|
|
TEST(RawClientReader, NoClientStream_OutOfScope_SilentlyCloses) {
|
|
RawClientTestContext ctx;
|
|
|
|
{
|
|
RawClientReader call = TestService::TestServerStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
{},
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
FailIfCalled);
|
|
ASSERT_EQ(ctx.output().total_packets(), 1u); // Sent the request
|
|
}
|
|
|
|
EXPECT_EQ(ctx.output().total_packets(), 1u); // No more packets
|
|
}
|
|
|
|
TEST(RawClientWriter, WithClientStream_OutOfScope_SendsClientStreamEnd) {
|
|
RawClientTestContext ctx;
|
|
|
|
{
|
|
RawClientWriter call =
|
|
TestService::TestClientStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
FailIfOnCompletedCalled,
|
|
FailIfCalled);
|
|
ASSERT_EQ(ctx.output().total_packets(), 1u); // Sent the request
|
|
}
|
|
|
|
EXPECT_EQ(ctx.output().total_packets(), 2u); // Sent CLIENT_STREAM_END
|
|
EXPECT_EQ(ctx.output()
|
|
.client_stream_end_packets<TestService::TestClientStreamRpc>(),
|
|
1u);
|
|
}
|
|
|
|
constexpr const char kWriterData[] = "20X6";
|
|
|
|
void WriteAsWriter(Writer& writer) {
|
|
ASSERT_TRUE(writer.active());
|
|
ASSERT_EQ(writer.channel_id(), RawClientTestContext<>::kDefaultChannelId);
|
|
|
|
EXPECT_EQ(OkStatus(), writer.Write(std::as_bytes(std::span(kWriterData))));
|
|
}
|
|
|
|
TEST(RawClientWriter, UsableAsWriter) {
|
|
RawClientTestContext ctx;
|
|
RawClientWriter call = TestService::TestClientStreamRpc(
|
|
ctx.client(), ctx.channel().id(), FailIfOnCompletedCalled, FailIfCalled);
|
|
|
|
WriteAsWriter(call);
|
|
|
|
EXPECT_STREQ(reinterpret_cast<const char*>(
|
|
ctx.output()
|
|
.payloads<TestService::TestClientStreamRpc>()
|
|
.back()
|
|
.data()),
|
|
kWriterData);
|
|
}
|
|
|
|
TEST(RawClientReaderWriter, UsableAsWriter) {
|
|
RawClientTestContext ctx;
|
|
RawClientReaderWriter call =
|
|
TestService::TestBidirectionalStreamRpc(ctx.client(),
|
|
ctx.channel().id(),
|
|
FailIfOnNextCalled,
|
|
FailIfCalled,
|
|
FailIfCalled);
|
|
|
|
WriteAsWriter(call);
|
|
|
|
EXPECT_STREQ(reinterpret_cast<const char*>(
|
|
ctx.output()
|
|
.payloads<TestService::TestBidirectionalStreamRpc>()
|
|
.back()
|
|
.data()),
|
|
kWriterData);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::rpc
|