xref: /aosp_15_r20/external/grpc-grpc/src/core/resolver/fake/fake_resolver.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 // Copyright 2016 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 // This is similar to the sockaddr resolver, except that it supports a
18 // bunch of query args that are useful for dependency injection in tests.
19 
20 #include <grpc/support/port_platform.h>
21 
22 #include "src/core/resolver/fake/fake_resolver.h"
23 
24 #include <memory>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "absl/strings/string_view.h"
29 
30 #include <grpc/support/log.h>
31 
32 #include "src/core/lib/channel/channel_args.h"
33 #include "src/core/lib/config/core_configuration.h"
34 #include "src/core/lib/gpr/useful.h"
35 #include "src/core/lib/gprpp/debug_location.h"
36 #include "src/core/lib/gprpp/orphanable.h"
37 #include "src/core/lib/gprpp/work_serializer.h"
38 #include "src/core/resolver/resolver_factory.h"
39 #include "src/core/lib/uri/uri_parser.h"
40 
41 namespace grpc_core {
42 
43 // This cannot be in an anonymous namespace, because it is a friend of
44 // FakeResolverResponseGenerator.
45 class FakeResolver final : public Resolver {
46  public:
47   explicit FakeResolver(ResolverArgs args);
48 
49   void StartLocked() override;
50 
51   void RequestReresolutionLocked() override;
52 
53  private:
54   friend class FakeResolverResponseGenerator;
55 
56   void ShutdownLocked() override;
57 
58   void MaybeSendResultLocked();
59 
60   // passed-in parameters
61   std::shared_ptr<WorkSerializer> work_serializer_;
62   std::unique_ptr<ResultHandler> result_handler_;
63   ChannelArgs channel_args_;
64   RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
65   // The next resolution result to be returned, if any.  Present when we
66   // get a result before the resolver is started.
67   absl::optional<Result> next_result_;
68   // True after the call to StartLocked().
69   bool started_ = false;
70   // True after the call to ShutdownLocked().
71   bool shutdown_ = false;
72 };
73 
FakeResolver(ResolverArgs args)74 FakeResolver::FakeResolver(ResolverArgs args)
75     : work_serializer_(std::move(args.work_serializer)),
76       result_handler_(std::move(args.result_handler)),
77       channel_args_(
78           // Channels sharing the same subchannels may have different resolver
79           // response generators. If we don't remove this arg, subchannel pool
80           // will create new subchannels for the same address instead of
81           // reusing existing ones because of different values of this channel
82           // arg. Can't just use GRPC_ARG_NO_SUBCHANNEL_PREFIX, since
83           // that can't be passed into the channel from test code.
84           args.args.Remove(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR)),
85       response_generator_(
86           args.args.GetObjectRef<FakeResolverResponseGenerator>()) {
87   if (response_generator_ != nullptr) {
88     response_generator_->SetFakeResolver(RefAsSubclass<FakeResolver>());
89   }
90 }
91 
StartLocked()92 void FakeResolver::StartLocked() {
93   started_ = true;
94   MaybeSendResultLocked();
95 }
96 
RequestReresolutionLocked()97 void FakeResolver::RequestReresolutionLocked() {
98   // Re-resolution can't happen until after we return an initial result.
99   GPR_ASSERT(response_generator_ != nullptr);
100   response_generator_->ReresolutionRequested();
101 }
102 
ShutdownLocked()103 void FakeResolver::ShutdownLocked() {
104   shutdown_ = true;
105   if (response_generator_ != nullptr) {
106     response_generator_->SetFakeResolver(nullptr);
107     response_generator_.reset();
108   }
109 }
110 
MaybeSendResultLocked()111 void FakeResolver::MaybeSendResultLocked() {
112   if (!started_ || shutdown_) return;
113   if (next_result_.has_value()) {
114     // When both next_results_ and channel_args_ contain an arg with the same
115     // name, use the one in next_results_.
116     next_result_->args = next_result_->args.UnionWith(channel_args_);
117     result_handler_->ReportResult(std::move(*next_result_));
118     next_result_.reset();
119   }
120 }
121 
122 //
123 // FakeResolverResponseGenerator
124 //
125 
FakeResolverResponseGenerator()126 FakeResolverResponseGenerator::FakeResolverResponseGenerator() {}
127 
~FakeResolverResponseGenerator()128 FakeResolverResponseGenerator::~FakeResolverResponseGenerator() {}
129 
SetResponseAndNotify(Resolver::Result result,Notification * notify_when_set)130 void FakeResolverResponseGenerator::SetResponseAndNotify(
131     Resolver::Result result, Notification* notify_when_set) {
132   RefCountedPtr<FakeResolver> resolver;
133   {
134     MutexLock lock(&mu_);
135     if (resolver_ == nullptr) {
136       result_ = std::move(result);
137       if (notify_when_set != nullptr) notify_when_set->Notify();
138       return;
139     }
140     resolver = resolver_;
141   }
142   SendResultToResolver(std::move(resolver), std::move(result), notify_when_set);
143 }
144 
SetFakeResolver(RefCountedPtr<FakeResolver> resolver)145 void FakeResolverResponseGenerator::SetFakeResolver(
146     RefCountedPtr<FakeResolver> resolver) {
147   Resolver::Result result;
148   {
149     MutexLock lock(&mu_);
150     resolver_ = resolver;
151     if (resolver_set_cv_ != nullptr) resolver_set_cv_->SignalAll();
152     if (resolver == nullptr) return;
153     if (!result_.has_value()) return;
154     result = std::move(*result_);
155     result_.reset();
156   }
157   SendResultToResolver(std::move(resolver), std::move(result), nullptr);
158 }
159 
SendResultToResolver(RefCountedPtr<FakeResolver> resolver,Resolver::Result result,Notification * notify_when_set)160 void FakeResolverResponseGenerator::SendResultToResolver(
161     RefCountedPtr<FakeResolver> resolver, Resolver::Result result,
162     Notification* notify_when_set) {
163   auto* resolver_ptr = resolver.get();
164   resolver_ptr->work_serializer_->Run(
165       [resolver = std::move(resolver), result = std::move(result),
166        notify_when_set]() mutable {
167         if (!resolver->shutdown_) {
168           resolver->next_result_ = std::move(result);
169           resolver->MaybeSendResultLocked();
170         }
171         if (notify_when_set != nullptr) notify_when_set->Notify();
172       },
173       DEBUG_LOCATION);
174 }
175 
WaitForResolverSet(absl::Duration timeout)176 bool FakeResolverResponseGenerator::WaitForResolverSet(absl::Duration timeout) {
177   MutexLock lock(&mu_);
178   if (resolver_ == nullptr) {
179     CondVar condition;
180     resolver_set_cv_ = &condition;
181     condition.WaitWithTimeout(&mu_, timeout);
182     resolver_set_cv_ = nullptr;
183   }
184   return resolver_ != nullptr;
185 }
186 
WaitForReresolutionRequest(absl::Duration timeout)187 bool FakeResolverResponseGenerator::WaitForReresolutionRequest(
188     absl::Duration timeout) {
189   MutexLock lock(&reresolution_mu_);
190   if (!reresolution_requested_) {
191     CondVar condition;
192     reresolution_cv_ = &condition;
193     condition.WaitWithTimeout(&reresolution_mu_, timeout);
194     reresolution_cv_ = nullptr;
195   }
196   return std::exchange(reresolution_requested_, false);
197 }
198 
ReresolutionRequested()199 void FakeResolverResponseGenerator::ReresolutionRequested() {
200   MutexLock lock(&reresolution_mu_);
201   reresolution_requested_ = true;
202   if (reresolution_cv_ != nullptr) reresolution_cv_->SignalAll();
203 }
204 
205 namespace {
206 
ResponseGeneratorChannelArgCopy(void * p)207 void* ResponseGeneratorChannelArgCopy(void* p) {
208   auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
209   generator->Ref().release();
210   return p;
211 }
212 
ResponseGeneratorChannelArgDestroy(void * p)213 void ResponseGeneratorChannelArgDestroy(void* p) {
214   auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
215   generator->Unref();
216 }
217 
ResponseGeneratorChannelArgCmp(void * a,void * b)218 int ResponseGeneratorChannelArgCmp(void* a, void* b) {
219   return QsortCompare(a, b);
220 }
221 
222 }  // namespace
223 
224 const grpc_arg_pointer_vtable
225     FakeResolverResponseGenerator::kChannelArgPointerVtable = {
226         ResponseGeneratorChannelArgCopy, ResponseGeneratorChannelArgDestroy,
227         ResponseGeneratorChannelArgCmp};
228 
229 //
230 // Factory
231 //
232 
233 namespace {
234 
235 class FakeResolverFactory final : public ResolverFactory {
236  public:
scheme() const237   absl::string_view scheme() const override { return "fake"; }
238 
IsValidUri(const URI &) const239   bool IsValidUri(const URI& /*uri*/) const override { return true; }
240 
CreateResolver(ResolverArgs args) const241   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
242     return MakeOrphanable<FakeResolver>(std::move(args));
243   }
244 };
245 
246 }  // namespace
247 
RegisterFakeResolver(CoreConfiguration::Builder * builder)248 void RegisterFakeResolver(CoreConfiguration::Builder* builder) {
249   builder->resolver_registry()->RegisterResolverFactory(
250       std::make_unique<FakeResolverFactory>());
251 }
252 
253 }  // namespace grpc_core
254 
grpc_resolver_fake_shutdown()255 void grpc_resolver_fake_shutdown() {}
256