xref: /aosp_15_r20/external/grpc-grpc/test/core/end2end/tests/retry_transparent_goaway.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 // Copyright 2017 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <memory>
18 #include <new>
19 
20 #include "absl/status/status.h"
21 #include "absl/types/optional.h"
22 #include "gtest/gtest.h"
23 
24 #include <grpc/impl/channel_arg_names.h>
25 #include <grpc/status.h>
26 
27 #include "src/core/lib/channel/channel_fwd.h"
28 #include "src/core/lib/channel/channel_stack.h"
29 #include "src/core/lib/config/core_configuration.h"
30 #include "src/core/lib/gprpp/status_helper.h"
31 #include "src/core/lib/gprpp/time.h"
32 #include "src/core/lib/iomgr/call_combiner.h"
33 #include "src/core/lib/iomgr/closure.h"
34 #include "src/core/lib/iomgr/error.h"
35 #include "src/core/lib/surface/channel_stack_type.h"
36 #include "src/core/lib/transport/metadata_batch.h"
37 #include "src/core/lib/transport/transport.h"
38 #include "test/core/end2end/end2end_tests.h"
39 
40 namespace grpc_core {
41 namespace {
42 
43 // A filter that, for the first call it sees, will fail all batches except
44 // for cancellations, so that the call fails with an error whose
45 // StreamNetworkState is kNotSeenByServer.
46 // All subsequent calls are allowed through without failures.
47 class FailFirstCallFilter {
48  public:
49   static grpc_channel_filter kFilterVtable;
50 
51  private:
52   class CallData {
53    public:
Init(grpc_call_element * elem,const grpc_call_element_args * args)54     static grpc_error_handle Init(grpc_call_element* elem,
55                                   const grpc_call_element_args* args) {
56       new (elem->call_data) CallData(args);
57       return absl::OkStatus();
58     }
59 
Destroy(grpc_call_element * elem,const grpc_call_final_info *,grpc_closure *)60     static void Destroy(grpc_call_element* elem,
61                         const grpc_call_final_info* /*final_info*/,
62                         grpc_closure* /*ignored*/) {
63       auto* calld = static_cast<CallData*>(elem->call_data);
64       calld->~CallData();
65     }
66 
StartTransportStreamOpBatch(grpc_call_element * elem,grpc_transport_stream_op_batch * batch)67     static void StartTransportStreamOpBatch(
68         grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
69       auto* chand = static_cast<FailFirstCallFilter*>(elem->channel_data);
70       auto* calld = static_cast<CallData*>(elem->call_data);
71       if (!chand->seen_call_) {
72         calld->fail_ = true;
73         chand->seen_call_ = true;
74       }
75       if (calld->fail_) {
76         if (batch->recv_trailing_metadata) {
77           batch->payload->recv_trailing_metadata.recv_trailing_metadata->Set(
78               GrpcStreamNetworkState(),
79               GrpcStreamNetworkState::kNotSeenByServer);
80         }
81         if (!batch->cancel_stream) {
82           grpc_transport_stream_op_batch_finish_with_failure(
83               batch,
84               grpc_error_set_int(
85                   GRPC_ERROR_CREATE("FailFirstCallFilter failing batch"),
86                   StatusIntProperty::kRpcStatus, GRPC_STATUS_UNAVAILABLE),
87               calld->call_combiner_);
88           return;
89         }
90       }
91       grpc_call_next_op(elem, batch);
92     }
93 
94    private:
CallData(const grpc_call_element_args * args)95     explicit CallData(const grpc_call_element_args* args)
96         : call_combiner_(args->call_combiner) {}
97 
98     CallCombiner* call_combiner_;
99     bool fail_ = false;
100   };
101 
Init(grpc_channel_element * elem,grpc_channel_element_args *)102   static grpc_error_handle Init(grpc_channel_element* elem,
103                                 grpc_channel_element_args* /*args*/) {
104     new (elem->channel_data) FailFirstCallFilter();
105     return absl::OkStatus();
106   }
107 
Destroy(grpc_channel_element * elem)108   static void Destroy(grpc_channel_element* elem) {
109     auto* chand = static_cast<FailFirstCallFilter*>(elem->channel_data);
110     chand->~FailFirstCallFilter();
111   }
112 
113   bool seen_call_ = false;
114 };
115 
116 grpc_channel_filter FailFirstCallFilter::kFilterVtable = {
117     CallData::StartTransportStreamOpBatch,
118     nullptr,
119     nullptr,
120     grpc_channel_next_op,
121     sizeof(CallData),
122     CallData::Init,
123     grpc_call_stack_ignore_set_pollset_or_pollset_set,
124     CallData::Destroy,
125     sizeof(FailFirstCallFilter),
126     Init,
127     grpc_channel_stack_no_post_init,
128     Destroy,
129     grpc_channel_next_get_info,
130     "FailFirstCallFilter",
131 };
132 
133 // Tests transparent retries when the call was never sent out on the wire.
CORE_END2END_TEST(RetryTest,TransparentGoaway)134 CORE_END2END_TEST(RetryTest, TransparentGoaway) {
135   CoreConfiguration::RegisterBuilder([](CoreConfiguration::Builder* builder) {
136     builder->channel_init()
137         ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL,
138                          &FailFirstCallFilter::kFilterVtable)
139         // Skip on proxy (which explicitly disables retries).
140         .IfChannelArg(GRPC_ARG_ENABLE_RETRIES, true);
141   });
142   auto c =
143       NewClientCall("/service/method").Timeout(Duration::Minutes(1)).Create();
144   EXPECT_NE(c.GetPeer(), absl::nullopt);
145   // Start a batch containing send ops.
146   c.NewBatch(1)
147       .SendInitialMetadata({})
148       .SendMessage("foo")
149       .SendCloseFromClient();
150   // Start a batch containing recv ops.
151   CoreEnd2endTest::IncomingStatusOnClient server_status;
152   CoreEnd2endTest::IncomingMetadata server_initial_metadata;
153   CoreEnd2endTest::IncomingMessage server_message;
154   c.NewBatch(2)
155       .RecvInitialMetadata(server_initial_metadata)
156       .RecvMessage(server_message)
157       .RecvStatusOnClient(server_status);
158   // Client send ops should now complete.
159   Expect(1, true);
160   Step();
161   // Server should get a call.
162   auto s = RequestCall(101);
163   Expect(101, true);
164   Step();
165   // Server receives the request.
166   CoreEnd2endTest::IncomingMessage client_message;
167   s.NewBatch(102).RecvMessage(client_message);
168   Expect(102, true);
169   Step();
170   // Server sends a response with status OK.
171   CoreEnd2endTest::IncomingCloseOnServer client_close;
172   s.NewBatch(103)
173       .RecvCloseOnServer(client_close)
174       .SendInitialMetadata({})
175       .SendMessage("bar")
176       .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {});
177   // In principle, the server batch should complete before the client
178   // recv ops batch, but in the proxy fixtures, there are multiple threads
179   // involved, so the completion order tends to be a little racy.
180   Expect(103, true);
181   Expect(2, true);
182   Step();
183   EXPECT_EQ(server_status.status(), GRPC_STATUS_OK);
184   EXPECT_EQ(server_status.message(), "xyz");
185   EXPECT_EQ(s.method(), "/service/method");
186   EXPECT_FALSE(client_close.was_cancelled());
187   EXPECT_EQ(server_message.payload(), "bar");
188   EXPECT_EQ(client_message.payload(), "foo");
189   // Make sure the "grpc-previous-rpc-attempts" header was NOT sent, since
190   // we don't do that for transparent retries.
191   EXPECT_EQ(s.GetInitialMetadata("grpc-previous-rpc-attempts"), absl::nullopt);
192 }
193 
194 }  // namespace
195 }  // namespace grpc_core
196