pull/36732/head
parent
05dbc8b4d3
commit
ea8b903e37
3 changed files with 171 additions and 3 deletions
@ -0,0 +1,148 @@ |
|||||||
|
// 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 "src/core/client_channel/load_balanced_call_destination.h" |
||||||
|
|
||||||
|
#include <atomic> |
||||||
|
#include <memory> |
||||||
|
#include <queue> |
||||||
|
|
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
#include "gmock/gmock.h" |
||||||
|
#include "gtest/gtest.h" |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
|
||||||
|
#include "test/core/call/yodel/yodel_test.h" |
||||||
|
|
||||||
|
using testing::StrictMock; |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
using EventEngine = grpc_event_engine::experimental::EventEngine; |
||||||
|
|
||||||
|
namespace { |
||||||
|
const absl::string_view kTestPath = "/test_method"; |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class LoadBalancedCallDestinationTest : public YodelTest { |
||||||
|
protected: |
||||||
|
using YodelTest::YodelTest; |
||||||
|
|
||||||
|
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() { |
||||||
|
auto poll = [this]() -> Poll<CallHandler> { |
||||||
|
auto handler = call_destination_->PopHandler(); |
||||||
|
if (handler.has_value()) return std::move(*handler); |
||||||
|
return Pending(); |
||||||
|
}; |
||||||
|
return TickUntil(absl::FunctionRef<Poll<CallHandler>()>(poll)); |
||||||
|
} |
||||||
|
|
||||||
|
LoadBalancedCallDestination& destination_under_test() { |
||||||
|
return *destination_under_test_; |
||||||
|
} |
||||||
|
|
||||||
|
ClientChannel::PickerObservable& picker() { return picker_; } |
||||||
|
|
||||||
|
private: |
||||||
|
class TestCallDestination final : public UnstartedCallDestination { |
||||||
|
public: |
||||||
|
void StartCall(UnstartedCallHandler unstarted_call_handler) override { |
||||||
|
handlers_.push( |
||||||
|
unstarted_call_handler.V2HackToStartCallWithoutACallFilterStack()); |
||||||
|
} |
||||||
|
|
||||||
|
absl::optional<CallHandler> PopHandler() { |
||||||
|
if (handlers_.empty()) return absl::nullopt; |
||||||
|
auto handler = std::move(handlers_.front()); |
||||||
|
handlers_.pop(); |
||||||
|
return handler; |
||||||
|
} |
||||||
|
|
||||||
|
void Orphaned() override {} |
||||||
|
|
||||||
|
private: |
||||||
|
std::queue<CallHandler> handlers_; |
||||||
|
}; |
||||||
|
|
||||||
|
void InitCoreConfiguration() override {} |
||||||
|
|
||||||
|
void Shutdown() override {} |
||||||
|
|
||||||
|
OrphanablePtr<ClientChannel> channel_; |
||||||
|
ClientChannel::PickerObservable picker_{nullptr}; |
||||||
|
RefCountedPtr<TestCallDestination> call_destination_ = |
||||||
|
MakeRefCounted<TestCallDestination>(); |
||||||
|
RefCountedPtr<LoadBalancedCallDestination> destination_under_test_ = |
||||||
|
MakeRefCounted<LoadBalancedCallDestination>(picker_); |
||||||
|
RefCountedPtr<CallArenaAllocator> call_arena_allocator_ = |
||||||
|
MakeRefCounted<CallArenaAllocator>( |
||||||
|
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( |
||||||
|
"test"), |
||||||
|
1024); |
||||||
|
}; |
||||||
|
|
||||||
|
#define LOAD_BALANCED_CALL_DESTINATION_TEST(name) \ |
||||||
|
YODEL_TEST(LoadBalancedCallDestinationTest, name) |
||||||
|
|
||||||
|
class MockPicker : public LoadBalancingPolicy::SubchannelPicker { |
||||||
|
public: |
||||||
|
MOCK_METHOD(LoadBalancingPolicy::PickResult, Pick, |
||||||
|
(LoadBalancingPolicy::PickArgs)); |
||||||
|
}; |
||||||
|
|
||||||
|
LOAD_BALANCED_CALL_DESTINATION_TEST(NoOp) {} |
||||||
|
|
||||||
|
LOAD_BALANCED_CALL_DESTINATION_TEST(CreateCall) { |
||||||
|
auto call = MakeCall(MakeClientInitialMetadata()); |
||||||
|
SpawnTestSeq(call.initiator, "initiator", |
||||||
|
[this, handler = std::move(call.handler)]() { |
||||||
|
destination_under_test().StartCall(handler); |
||||||
|
return Empty{}; |
||||||
|
}); |
||||||
|
WaitForAllPendingWork(); |
||||||
|
} |
||||||
|
|
||||||
|
LOAD_BALANCED_CALL_DESTINATION_TEST(StartCall) { |
||||||
|
auto call = MakeCall(MakeClientInitialMetadata()); |
||||||
|
SpawnTestSeq(call.initiator, "initiator", |
||||||
|
[this, handler = std::move(call.handler)]() { |
||||||
|
destination_under_test().StartCall(handler); |
||||||
|
return Empty{}; |
||||||
|
}); |
||||||
|
auto mock_picker = MakeRefCounted<StrictMock<MockPicker>>(); |
||||||
|
EXPECT_CALL(*mock_picker, Pick) |
||||||
|
.WillOnce([](LoadBalancingPolicy::PickArgs args) { |
||||||
|
return LoadBalancingPolicy::PickResult{args.subchannel}; |
||||||
|
}); |
||||||
|
picker().Set(mock_picker); |
||||||
|
auto handler = TickUntilCallStarted(); |
||||||
|
WaitForAllPendingWork(); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
Loading…
Reference in new issue