blob: 789a05d94d70ff3cdf21b730adc397faf5079f86 [file] [log] [blame]
//
//
// Copyright 2018 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 <initializer_list>
#include <memory>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "gtest/gtest.h"
#include <grpc/status.h>
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/transport/transport.h"
#include "test/core/end2end/end2end_tests.h"
namespace grpc_core {
namespace {
//******************************************************************************
// Test context filter
//
struct call_data {
grpc_call_context_element* context;
};
grpc_error_handle init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
call_data* calld = static_cast<call_data*>(elem->call_data);
calld->context = args->context;
LOG(INFO) << "init_call_elem(): context=" << args->context;
return absl::OkStatus();
}
void start_transport_stream_op_batch(grpc_call_element* elem,
grpc_transport_stream_op_batch* batch) {
call_data* calld = static_cast<call_data*>(elem->call_data);
// If batch payload context is not null (which will happen in some
// cancellation cases), make sure we get the same context here that we
// saw in init_call_elem().
LOG(INFO) << "start_transport_stream_op_batch(): context="
<< batch->payload->context;
if (batch->payload->context != nullptr) {
CHECK(calld->context == batch->payload->context);
}
grpc_call_next_op(elem, batch);
}
void destroy_call_elem(grpc_call_element* /*elem*/,
const grpc_call_final_info* /*final_info*/,
grpc_closure* /*ignored*/) {}
grpc_error_handle init_channel_elem(grpc_channel_element* /*elem*/,
grpc_channel_element_args* /*args*/) {
return absl::OkStatus();
}
void destroy_channel_elem(grpc_channel_element* /*elem*/) {}
const grpc_channel_filter test_filter = {
start_transport_stream_op_batch, nullptr, nullptr, grpc_channel_next_op,
sizeof(call_data), init_call_elem,
grpc_call_stack_ignore_set_pollset_or_pollset_set, destroy_call_elem, 0,
init_channel_elem, grpc_channel_stack_no_post_init, destroy_channel_elem,
grpc_channel_next_get_info,
// Want to add the filter as close to the end as possible, to
// make sure that all of the filters work well together.
// However, we can't add it at the very end, because the
// connected channel filter must be the last one.
// Channel init code falls back to lexical ordering of filters if there are
// otherwise no dependencies, so we leverage that.
"zzzzzzz_filter_context"};
// Simple request to test that filters see a consistent view of the
// call context.
CORE_END2END_TEST(CoreEnd2endTest, FilterContext) {
SKIP_IF_CHAOTIC_GOOD();
CoreConfiguration::RegisterBuilder([](CoreConfiguration::Builder* builder) {
for (auto type : {GRPC_CLIENT_CHANNEL, GRPC_CLIENT_SUBCHANNEL,
GRPC_CLIENT_DIRECT_CHANNEL, GRPC_SERVER_CHANNEL}) {
if (type == GRPC_SERVER_CHANNEL && IsPromiseBasedServerCallEnabled()) {
continue;
}
builder->channel_init()->RegisterFilter(type, &test_filter);
}
});
auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create();
CoreEnd2endTest::IncomingStatusOnClient server_status;
CoreEnd2endTest::IncomingMetadata server_initial_metadata;
c.NewBatch(1)
.SendInitialMetadata({})
.SendMessage("hello world")
.SendCloseFromClient()
.RecvInitialMetadata(server_initial_metadata)
.RecvStatusOnClient(server_status);
auto s = RequestCall(101);
Expect(101, true);
Step();
CoreEnd2endTest::IncomingCloseOnServer client_close;
s.NewBatch(102)
.SendInitialMetadata({})
.SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {})
.RecvCloseOnServer(client_close);
Expect(102, true);
Expect(1, true);
Step();
EXPECT_EQ(server_status.status(), GRPC_STATUS_UNIMPLEMENTED);
EXPECT_EQ(server_status.message(), "xyz");
}
} // namespace
} // namespace grpc_core