// Copyright 2022 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/pwpb/client_reader_writer.h" #include #include "gtest/gtest.h" #include "pw_rpc/pwpb/client_testing.h" #include "pw_rpc_test_protos/test.rpc.pwpb.h" PW_MODIFY_DIAGNOSTICS_PUSH(); PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers"); namespace pw::rpc { namespace { using test::pw_rpc::pwpb::TestService; namespace TestRequest = ::pw::rpc::test::pwpb::TestRequest; namespace TestResponse = ::pw::rpc::test::pwpb::TestResponse; namespace TestStreamResponse = ::pw::rpc::test::pwpb::TestStreamResponse; void FailIfCalled(Status) { FAIL(); } template void FailIfOnNextCalled(const T&) { FAIL(); } template void FailIfOnCompletedCalled(const T&, Status) { FAIL(); } TEST(PwpbUnaryReceiver, DefaultConstructed) { PwpbUnaryReceiver call; ASSERT_FALSE(call.active()); EXPECT_EQ(call.channel_id(), Channel::kUnassignedChannelId); EXPECT_EQ(Status::FailedPrecondition(), call.Cancel()); call.set_on_completed([](const TestResponse::Message&, Status) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientWriter, DefaultConstructed) { PwpbClientWriter 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([](const TestStreamResponse::Message&, Status) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientReader, DefaultConstructed) { PwpbClientReader 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([](const TestStreamResponse::Message&) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientReaderWriter, DefaultConstructed) { PwpbClientReaderWriter 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([](const TestStreamResponse::Message&) {}); call.set_on_error([](Status) {}); } TEST(PwpbUnaryReceiver, Closed) { PwpbClientTestContext ctx; PwpbUnaryReceiver 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([](const TestResponse::Message&, Status) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientWriter, Closed) { PwpbClientTestContext ctx; PwpbClientWriter 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([](const TestStreamResponse::Message&, Status) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientReader, Closed) { PwpbClientTestContext ctx; PwpbClientReader 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([](const TestStreamResponse::Message&) {}); call.set_on_error([](Status) {}); } TEST(PwpbClientReaderWriter, Closed) { PwpbClientTestContext ctx; PwpbClientReaderWriter 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([](const TestStreamResponse::Message&) {}); call.set_on_error([](Status) {}); } TEST(PwpbUnaryReceiver, CallbacksMoveCorrectly) { PwpbClientTestContext ctx; struct { TestResponse::Message payload = {.value = 12345678}; std::optional status; } reply; PwpbUnaryReceiver call_2; { PwpbUnaryReceiver call_1 = TestService::TestUnaryRpc( ctx.client(), ctx.channel().id(), {}, [&reply](const TestResponse::Message& response, Status status) { reply.payload = response; reply.status = status; }); call_2 = std::move(call_1); } ctx.server().SendResponse({.value = 9000}, Status::NotFound()); EXPECT_EQ(reply.payload.value, 9000); EXPECT_EQ(reply.status, Status::NotFound()); } TEST(PwpbClientReaderWriter, CallbacksMoveCorrectly) { PwpbClientTestContext ctx; TestStreamResponse::Message payload = {.chunk = {}, .number = 13579}; PwpbClientReaderWriter call_2; { PwpbClientReaderWriter call_1 = TestService::TestBidirectionalStreamRpc( ctx.client(), ctx.channel().id(), [&payload](const TestStreamResponse::Message& response) { payload = response; }); call_2 = std::move(call_1); } ctx.server().SendServerStream( {.chunk = {}, .number = 5050}); EXPECT_EQ(payload.number, 5050u); } } // namespace } // namespace pw::rpc PW_MODIFY_DIAGNOSTICS_POP();