blob: 0bc7a69e0348f402c7774caf67e1e2d60e385dc2 [file] [log] [blame]
//
//
// Copyright 2016 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 <stddef.h>
#include <algorithm>
#include <vector>
#include "absl/log/log.h"
#include "absl/strings/str_format.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
#include <grpc/impl/channel_arg_names.h>
#include <grpc/status.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/slice/slice.h"
#include "test/core/end2end/end2end_tests.h"
namespace grpc_core {
namespace {
const int kNumCalls = 8;
const int kClientBaseTag = 1000;
const int kServerStartBaseTag = 2000;
const int kServerRecvBaseTag = 3000;
const int kServerEndBaseTag = 4000;
template <typename F>
auto MakeVec(F init) {
std::vector<decltype(init(0))> v;
v.reserve(kNumCalls);
for (int i = 0; i < kNumCalls; ++i) {
v.push_back(init(i));
}
return v;
}
CORE_END2END_TEST(ResourceQuotaTest, ResourceQuota) {
if (IsEventEngineListenerEnabled()) {
GTEST_SKIP() << "Not with event engine listener";
}
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("test_server");
grpc_resource_quota_resize(resource_quota, 1024 * 1024);
InitServer(ChannelArgs().Set(
GRPC_ARG_RESOURCE_QUOTA,
ChannelArgs::Pointer(resource_quota, grpc_resource_quota_arg_vtable())));
InitClient(ChannelArgs());
// Create large request and response bodies. These are big enough to require
// multiple round trips to deliver to the peer, and their exact contents of
// will be verified on completion.
auto requests = MakeVec([](int) { return RandomSlice(128 * 1024); });
auto server_calls =
MakeVec([this](int i) { return RequestCall(kServerRecvBaseTag + i); });
IncomingMetadata server_metadata[kNumCalls];
IncomingStatusOnClient server_status[kNumCalls];
IncomingMessage client_message[kNumCalls];
IncomingCloseOnServer client_close[kNumCalls];
enum class SeenServerCall {
kNotSeen = 0,
kSeenWithSuccess,
kSeenWithFailure
};
// Yep, this really initializes all the elements.
SeenServerCall seen_server_call[kNumCalls] = {SeenServerCall::kNotSeen};
auto client_calls =
MakeVec([this, &requests, &server_metadata, &server_status](int i) {
auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create();
c.NewBatch(kClientBaseTag + i)
.SendInitialMetadata({}, GRPC_INITIAL_METADATA_WAIT_FOR_READY)
.SendMessage(requests[i].Ref())
.SendCloseFromClient()
.RecvInitialMetadata(server_metadata[i])
.RecvStatusOnClient(server_status[i]);
return c;
});
for (int i = 0; i < kNumCalls; i++) {
Expect(kClientBaseTag + i, true);
Expect(
kServerRecvBaseTag + i,
MaybePerformAction{[this, &seen_server_call, &server_calls,
&client_message, &client_close, i](bool success) {
seen_server_call[i] = success ? SeenServerCall::kSeenWithSuccess
: SeenServerCall::kSeenWithFailure;
if (!success) return;
server_calls[i]
.NewBatch(kServerStartBaseTag + i)
.RecvMessage(client_message[i])
.SendInitialMetadata({});
Expect(kServerStartBaseTag + i,
PerformAction{[&server_calls, &client_close, i](bool) {
server_calls[i]
.NewBatch(kServerEndBaseTag + i)
.RecvCloseOnServer(client_close[i])
.SendStatusFromServer(GRPC_STATUS_OK, "xyz", {});
}});
Expect(kServerEndBaseTag + i, true);
}});
}
Step();
int cancelled_calls_on_client = 0;
int cancelled_calls_on_server = 0;
int deadline_exceeded = 0;
int unavailable = 0;
for (int i = 0; i < kNumCalls; i++) {
switch (server_status[i].status()) {
case GRPC_STATUS_RESOURCE_EXHAUSTED:
cancelled_calls_on_client++;
break;
case GRPC_STATUS_DEADLINE_EXCEEDED:
deadline_exceeded++;
break;
case GRPC_STATUS_UNAVAILABLE:
unavailable++;
break;
case GRPC_STATUS_OK:
break;
default:
Crash(absl::StrFormat("Unexpected status code: %d",
server_status[i].status()));
}
if (seen_server_call[i] == SeenServerCall::kSeenWithSuccess &&
client_close[i].was_cancelled()) {
cancelled_calls_on_server++;
}
}
LOG(INFO) << "Done. " << kNumCalls
<< " total calls: " << cancelled_calls_on_server
<< " cancelled at server, " << cancelled_calls_on_client
<< " cancelled at client, " << deadline_exceeded << " timed out, "
<< unavailable << " unavailable.";
ShutdownServerAndNotify(0);
Expect(0, PerformAction{[this](bool success) {
EXPECT_TRUE(success);
DestroyServer();
}});
for (size_t i = 0; i < kNumCalls; i++) {
if (seen_server_call[i] == SeenServerCall::kNotSeen) {
Expect(kServerRecvBaseTag + i, false);
}
}
Step();
}
} // namespace
} // namespace grpc_core