C/C++ API Reference
Loading...
Searching...
No Matches
test_helpers.h
1// Copyright 2022 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <chrono>
17
18#include "pw_assert/assert.h"
19#include "pw_chrono/system_clock.h"
20#include "pw_rpc/internal/fake_channel_output.h"
21#include "pw_rpc/method_info.h"
22#include "pw_status/status.h"
23#include "pw_sync/counting_semaphore.h"
24#include "pw_thread/yield.h"
25
26namespace pw::rpc::test {
27
29
30// Wait until the provided RawFakeChannelOutput, NanopbFakeChannelOutput or
31// PwpbFakeChannelOutput receives the specified number of packets.
32template <unsigned kTimeoutSeconds = 10, typename Function>
33void WaitForPackets(internal::test::FakeChannelOutput& output,
34 int count,
35 Function&& run_before) {
36 sync::CountingSemaphore sem;
37 output.set_on_send([&sem](ConstByteSpan, Status) { sem.release(); });
38
39 run_before();
40
41 for (int i = 0; i < count; ++i) {
42 PW_ASSERT(sem.try_acquire_for(std::chrono::seconds(kTimeoutSeconds)));
43 }
44
45 output.set_on_send(nullptr);
46}
47
48// Checks that kMethod was called in client_context (which is a
49// PwpbClientTestContext or a NanopbClientTestContext) and sends the response
50// and status back.
51//
52// If no kMethod was called in timeout duration - returns
53// DEADLINE_EXCEEDED. Otherwise returns OK.
54//
55// Example: Let's say we are testing an RPC service (my::MyService) that as part
56// of the call (GetData) handling does another RPC call to a different service
57// (other::OtherService::GetPart). my::MyService constructor accepts the
58// other::OtherService::Client as an argument. To be able to test it we need to
59// provide a prepared response when request is sent.
60//
61// pw::rpc::PwpbClientTestContext client_context;
62// other::pw_rpc::pwpb::OtherService::Client other_service_client(
63// client_context.client(), client_context.channel().id());
64//
65// PW_PWPB_TEST_METHOD_CONTEXT(MyService, GetData)
66// context(other_service_client);
67// context.call({});
68//
69// ASSERT_EQ(pw::rpc::test::SendResponseIfCalled<
70// other::pw_rpc::pwpb::OtherService::GetPart>(client_context,
71// {.value = 42}),
72// pw::OkStatus());
73//
74// // At this point we have GetData handler received the response for GetPart.
75template <auto kMethod, typename Context>
76Status SendResponseIfCalled(
77 Context& client_context,
78 const MethodResponseType<kMethod>& response,
79 Status status = OkStatus(),
81 chrono::SystemClock::for_at_least(std::chrono::milliseconds(100))) {
82 const auto start_time = chrono::SystemClock::now();
83 while (chrono::SystemClock::now() - start_time < timeout) {
84 const auto count =
85 client_context.output().template total_payloads<kMethod>();
86 if (count > 0) {
87 client_context.server().template SendResponse<kMethod>(response, status);
88 return OkStatus();
89 }
90 this_thread::yield();
91 }
93}
94
95// Shortcut for SendResponseIfCalled(client_context, {}, status, timeout).
96template <auto kMethod, typename Context>
97Status SendResponseIfCalled(
98 Context& client_context,
99 Status status = OkStatus(),
101 chrono::SystemClock::for_at_least(std::chrono::milliseconds(100))) {
102 return SendResponseIfCalled<kMethod, Context>(
103 client_context, {}, status, timeout);
104}
105
107
108} // namespace pw::rpc::test
static constexpr Status DeadlineExceeded()
Deadline passed before operation completed.
Definition: status.h:136
static constexpr duration for_at_least(std::chrono::duration< Rep, Period > d)
Definition: system_clock.h:125
static time_point now() noexcept
This is thread and IRQ safe. This must be provided by the backend.
Definition: system_clock.h:117
std::chrono::duration< rep, period > duration
Alias for durations representable with this clock.
Definition: system_clock.h:90
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:73
constexpr Status OkStatus()
Definition: status.h:297