commit
a2227b3f99
8 changed files with 270 additions and 31 deletions
@ -0,0 +1,179 @@ |
||||
// Copyright 2024 gRPC 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
|
||||
//
|
||||
// http://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 <atomic> |
||||
#include <memory> |
||||
|
||||
#include "absl/status/status.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "gtest/gtest.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/client_channel/client_channel.h" |
||||
#include "src/core/client_channel/local_subchannel_pool.h" |
||||
#include "src/core/lib/address_utils/parse_address.h" |
||||
#include "src/core/lib/config/core_configuration.h" |
||||
#include "test/core/call/yodel/yodel_test.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
using EventEngine = grpc_event_engine::experimental::EventEngine; |
||||
|
||||
namespace { |
||||
const absl::string_view kTestPath = "/test_method"; |
||||
const absl::string_view kTestAddress = "ipv4:127.0.0.1:1234"; |
||||
const absl::string_view kDefaultAuthority = "test-authority"; |
||||
} // namespace
|
||||
|
||||
class ConnectedSubchannelTest : public YodelTest { |
||||
public: |
||||
protected: |
||||
using YodelTest::YodelTest; |
||||
|
||||
RefCountedPtr<ConnectedSubchannel> InitChannel(const ChannelArgs& args) { |
||||
grpc_resolved_address addr; |
||||
CHECK(grpc_parse_uri(URI::Parse(kTestAddress).value(), &addr)); |
||||
auto subchannel = Subchannel::Create(MakeOrphanable<TestConnector>(this), |
||||
addr, CompleteArgs(args)); |
||||
{ |
||||
ExecCtx exec_ctx; |
||||
subchannel->RequestConnection(); |
||||
} |
||||
return TickUntil<RefCountedPtr<ConnectedSubchannel>>( |
||||
[subchannel]() -> Poll<RefCountedPtr<ConnectedSubchannel>> { |
||||
auto connected_subchannel = subchannel->connected_subchannel(); |
||||
if (connected_subchannel != nullptr) return connected_subchannel; |
||||
return Pending(); |
||||
}); |
||||
} |
||||
|
||||
ClientMetadataHandle MakeClientInitialMetadata() { |
||||
auto client_initial_metadata = Arena::MakePooled<ClientMetadata>(); |
||||
client_initial_metadata->Set(HttpPathMetadata(), |
||||
Slice::FromCopiedString(kTestPath)); |
||||
return client_initial_metadata; |
||||
} |
||||
|
||||
CallInitiatorAndHandler MakeCall( |
||||
ClientMetadataHandle client_initial_metadata) { |
||||
return MakeCallPair( |
||||
std::move(client_initial_metadata), event_engine().get(), |
||||
call_arena_allocator_->MakeArena(), call_arena_allocator_, nullptr); |
||||
} |
||||
|
||||
CallHandler TickUntilCallStarted() { |
||||
return TickUntil<CallHandler>([this]() -> Poll<CallHandler> { |
||||
auto handler = PopHandler(); |
||||
if (handler.has_value()) return std::move(*handler); |
||||
return Pending(); |
||||
}); |
||||
} |
||||
|
||||
private: |
||||
class TestTransport final : public ClientTransport { |
||||
public: |
||||
explicit TestTransport(ConnectedSubchannelTest* test) : test_(test) {} |
||||
|
||||
void Orphan() override { |
||||
state_tracker_.SetState(GRPC_CHANNEL_SHUTDOWN, absl::OkStatus(), |
||||
"transport-orphaned"); |
||||
} |
||||
|
||||
FilterStackTransport* filter_stack_transport() override { return nullptr; } |
||||
ClientTransport* client_transport() override { return this; } |
||||
ServerTransport* server_transport() override { return nullptr; } |
||||
absl::string_view GetTransportName() const override { return "test"; } |
||||
void SetPollset(grpc_stream* stream, grpc_pollset* pollset) override {} |
||||
void SetPollsetSet(grpc_stream* stream, |
||||
grpc_pollset_set* pollset_set) override {} |
||||
void PerformOp(grpc_transport_op* op) override { |
||||
LOG(INFO) << "PerformOp: " << grpc_transport_op_string(op); |
||||
if (op->start_connectivity_watch != nullptr) { |
||||
state_tracker_.AddWatcher(op->start_connectivity_watch_state, |
||||
std::move(op->start_connectivity_watch)); |
||||
} |
||||
} |
||||
grpc_endpoint* GetEndpoint() override { return nullptr; } |
||||
|
||||
void StartCall(CallHandler call_handler) override { |
||||
test_->handlers_.push(std::move(call_handler)); |
||||
} |
||||
|
||||
private: |
||||
ConnectedSubchannelTest* const test_; |
||||
ConnectivityStateTracker state_tracker_{"test-transport"}; |
||||
}; |
||||
|
||||
class TestConnector final : public SubchannelConnector { |
||||
public: |
||||
explicit TestConnector(ConnectedSubchannelTest* test) : test_(test) {} |
||||
|
||||
void Connect(const Args& args, Result* result, |
||||
grpc_closure* notify) override { |
||||
result->channel_args = args.channel_args; |
||||
result->transport = MakeOrphanable<TestTransport>(test_).release(); |
||||
ExecCtx::Run(DEBUG_LOCATION, notify, absl::OkStatus()); |
||||
} |
||||
|
||||
void Shutdown(grpc_error_handle error) override {} |
||||
|
||||
private: |
||||
ConnectedSubchannelTest* const test_; |
||||
}; |
||||
|
||||
ChannelArgs CompleteArgs(const ChannelArgs& args) { |
||||
return args.SetObject(ResourceQuota::Default()) |
||||
.SetObject(std::static_pointer_cast<EventEngine>(event_engine())) |
||||
.SetObject(MakeRefCounted<LocalSubchannelPool>()) |
||||
.Set(GRPC_ARG_DEFAULT_AUTHORITY, kDefaultAuthority); |
||||
} |
||||
|
||||
void InitCoreConfiguration() override {} |
||||
|
||||
void Shutdown() override {} |
||||
|
||||
absl::optional<CallHandler> PopHandler() { |
||||
if (handlers_.empty()) return absl::nullopt; |
||||
auto handler = std::move(handlers_.front()); |
||||
handlers_.pop(); |
||||
return handler; |
||||
} |
||||
|
||||
std::queue<CallHandler> handlers_; |
||||
RefCountedPtr<CallArenaAllocator> call_arena_allocator_ = |
||||
MakeRefCounted<CallArenaAllocator>( |
||||
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( |
||||
"test"), |
||||
1024); |
||||
}; |
||||
|
||||
#define CONNECTED_SUBCHANNEL_CHANNEL_TEST(name) \ |
||||
YODEL_TEST(ConnectedSubchannelTest, name) |
||||
|
||||
CONNECTED_SUBCHANNEL_CHANNEL_TEST(NoOp) { InitChannel(ChannelArgs()); } |
||||
|
||||
CONNECTED_SUBCHANNEL_CHANNEL_TEST(StartCall) { |
||||
auto channel = InitChannel(ChannelArgs()); |
||||
auto call = MakeCall(MakeClientInitialMetadata()); |
||||
SpawnTestSeq( |
||||
call.handler, "start-call", [channel, handler = call.handler]() mutable { |
||||
channel->unstarted_call_destination()->StartCall(std::move(handler)); |
||||
return Empty{}; |
||||
}); |
||||
auto handler = TickUntilCallStarted(); |
||||
WaitForAllPendingWork(); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
Loading…
Reference in new issue