mirror of https://github.com/grpc/grpc.git
[promises] Re-enable C++ end2end tests (with fixes) (#32837)
Makes some awkward fixes to compression filter, call, connected channel to hold the semantics we have upheld now in tests. Once the fixes described here https://github.com/grpc/grpc/blob/master/src/core/lib/channel/connected_channel.cc#L636 are in this gets a lot less ad-hoc, but that's likely going to be post-landing promises client & server side. We specifically need special handling for server side cancellation in response to reads wrt the inproc transport - which doesn't track cancellation thoroughly enough itself. <!-- If you know who should review your pull request, please assign it to that person, otherwise the pull request would get assigned randomly. If your pull request is for a specific language, please add the appropriate lang label. --> --------- Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/33008/head
parent
65a2a895af
commit
ad41fe96b6
18 changed files with 300 additions and 13 deletions
@ -0,0 +1,95 @@ |
|||||||
|
// Copyright 2023 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H |
||||||
|
#define GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <type_traits> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
namespace promise_detail { |
||||||
|
|
||||||
|
template <typename A, typename B> |
||||||
|
class TwoPartyPrioritizedRace { |
||||||
|
public: |
||||||
|
using Result = decltype(std::declval<A>()()); |
||||||
|
|
||||||
|
explicit TwoPartyPrioritizedRace(A a, B b) |
||||||
|
: a_(std::move(a)), b_(std::move(b)) {} |
||||||
|
|
||||||
|
Result operator()() { |
||||||
|
// Check the priority promise.
|
||||||
|
auto p = a_(); |
||||||
|
if (p.ready()) return p; |
||||||
|
// Check the other promise.
|
||||||
|
p = b_(); |
||||||
|
if (p.ready()) { |
||||||
|
// re-poll a to see if it's also completed.
|
||||||
|
auto q = a_(); |
||||||
|
if (q.ready()) { |
||||||
|
// both are ready, but a is prioritized
|
||||||
|
return q; |
||||||
|
} |
||||||
|
} |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
A a_; |
||||||
|
B b_; |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename... Promises> |
||||||
|
class PrioritizedRace; |
||||||
|
|
||||||
|
template <typename Promise, typename... Promises> |
||||||
|
class PrioritizedRace<Promise, Promises...> |
||||||
|
: public TwoPartyPrioritizedRace<Promise, PrioritizedRace<Promises...>> { |
||||||
|
public: |
||||||
|
using Result = decltype(std::declval<Promise>()()); |
||||||
|
explicit PrioritizedRace(Promise promise, Promises... promises) |
||||||
|
: TwoPartyPrioritizedRace<Promise, PrioritizedRace<Promises...>>( |
||||||
|
std::move(promise), |
||||||
|
PrioritizedRace<Promises...>(std::move(promises)...)) {} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename Promise> |
||||||
|
class PrioritizedRace<Promise> { |
||||||
|
public: |
||||||
|
using Result = decltype(std::declval<Promise>()()); |
||||||
|
explicit PrioritizedRace(Promise promise) : promise_(std::move(promise)) {} |
||||||
|
Result operator()() { return promise_(); } |
||||||
|
|
||||||
|
private: |
||||||
|
Promise promise_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace promise_detail
|
||||||
|
|
||||||
|
/// Run all the promises until one is non-pending.
|
||||||
|
/// Once there's a non-pending promise, repoll all the promises before that.
|
||||||
|
/// Return the result from the lexically first non-pending promise.
|
||||||
|
template <typename... Promises> |
||||||
|
promise_detail::PrioritizedRace<Promises...> PrioritizedRace( |
||||||
|
Promises... promises) { |
||||||
|
return promise_detail::PrioritizedRace<Promises...>(std::move(promises)...); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H
|
@ -0,0 +1,80 @@ |
|||||||
|
// Copyright 2023 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/lib/promise/prioritized_race.h" |
||||||
|
|
||||||
|
#include "gtest/gtest.h" |
||||||
|
|
||||||
|
#include "src/core/lib/promise/poll.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
Poll<int> instant() { return 1; } |
||||||
|
Poll<int> never() { return Pending(); } |
||||||
|
|
||||||
|
TEST(PrioritizedRaceTest, Race1) { |
||||||
|
EXPECT_EQ(PrioritizedRace(instant)(), Poll<int>(1)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(PrioritizedRaceTest, Race2A) { |
||||||
|
EXPECT_EQ(PrioritizedRace(instant, never)(), Poll<int>(1)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(PrioritizedRaceTest, Race2B) { |
||||||
|
EXPECT_EQ(PrioritizedRace(never, instant)(), Poll<int>(1)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(PrioritizedRaceTest, PrioritizedCompletion2A) { |
||||||
|
int first_polls = 0; |
||||||
|
int second_polls = 0; |
||||||
|
auto r = PrioritizedRace( |
||||||
|
[&first_polls]() -> Poll<int> { |
||||||
|
++first_polls; |
||||||
|
return 1; |
||||||
|
}, |
||||||
|
[&second_polls]() { |
||||||
|
++second_polls; |
||||||
|
return 2; |
||||||
|
})(); |
||||||
|
EXPECT_EQ(r, Poll<int>(1)); |
||||||
|
// First promise completes immediately, so second promise is never polled.
|
||||||
|
EXPECT_EQ(first_polls, 1); |
||||||
|
EXPECT_EQ(second_polls, 0); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(PrioritizedRaceTest, PrioritizedCompletion2B) { |
||||||
|
int first_polls = 0; |
||||||
|
int second_polls = 0; |
||||||
|
auto r = PrioritizedRace( |
||||||
|
[&first_polls]() -> Poll<int> { |
||||||
|
++first_polls; |
||||||
|
if (first_polls > 1) return 1; |
||||||
|
return Pending{}; |
||||||
|
}, |
||||||
|
[&second_polls]() { |
||||||
|
++second_polls; |
||||||
|
return 2; |
||||||
|
})(); |
||||||
|
EXPECT_EQ(r, Poll<int>(1)); |
||||||
|
// First promise completes after second promise is polled.
|
||||||
|
EXPECT_EQ(first_polls, 2); |
||||||
|
EXPECT_EQ(second_polls, 1); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
return RUN_ALL_TESTS(); |
||||||
|
} |
Loading…
Reference in new issue