| /* |
| * |
| * 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. |
| * |
| */ |
| |
| #import <XCTest/XCTest.h> |
| |
| #include "src/core/lib/iomgr/port.h" |
| |
| #ifdef GRPC_CFSTREAM |
| |
| #include <netinet/in.h> |
| |
| #include <grpc/grpc.h> |
| #include <grpc/impl/codegen/sync.h> |
| #include <grpc/support/sync.h> |
| |
| #include "src/core/lib/address_utils/parse_address.h" |
| #include "src/core/lib/address_utils/sockaddr_utils.h" |
| #include "src/core/lib/event_engine/channel_args_endpoint_config.h" |
| #include "src/core/lib/iomgr/endpoint.h" |
| #include "src/core/lib/iomgr/resolve_address.h" |
| #include "src/core/lib/iomgr/tcp_client.h" |
| #include "src/core/lib/resource_quota/api.h" |
| #include "test/core/util/test_config.h" |
| |
| static gpr_mu g_mu; |
| static int g_connections_complete = 0; |
| static grpc_endpoint* g_connecting = nullptr; |
| |
| static void finish_connection() { |
| gpr_mu_lock(&g_mu); |
| g_connections_complete++; |
| gpr_mu_unlock(&g_mu); |
| } |
| |
| static void must_succeed(void* arg, grpc_error_handle error) { |
| GPR_ASSERT(g_connecting != nullptr); |
| GPR_ASSERT(error.ok()); |
| grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE("must_succeed called")); |
| grpc_endpoint_destroy(g_connecting); |
| g_connecting = nullptr; |
| finish_connection(); |
| } |
| |
| static void must_fail(void* arg, grpc_error_handle error) { |
| GPR_ASSERT(g_connecting == nullptr); |
| GPR_ASSERT(!error.ok()); |
| NSLog(@"%s", grpc_core::StatusToString(error).c_str()); |
| finish_connection(); |
| } |
| |
| @interface CFStreamClientTests : XCTestCase |
| |
| @end |
| |
| @implementation CFStreamClientTests |
| |
| + (void)setUp { |
| grpc_init(); |
| gpr_mu_init(&g_mu); |
| } |
| |
| + (void)tearDown { |
| grpc_shutdown(); |
| } |
| |
| - (void)testSucceeds { |
| int svr_fd; |
| int r; |
| int connections_complete_before; |
| grpc_closure done; |
| grpc_core::ExecCtx exec_ctx; |
| |
| gpr_log(GPR_DEBUG, "test_succeeds"); |
| |
| auto resolved_addr = grpc_core::StringToSockaddr("127.0.0.1:0"); |
| GPR_ASSERT(resolved_addr.ok()); |
| struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(resolved_addr->addr); |
| |
| /* create a phony server */ |
| svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
| GPR_ASSERT(svr_fd >= 0); |
| GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr*)addr, (socklen_t)resolved_addr->len)); |
| GPR_ASSERT(0 == listen(svr_fd, 1)); |
| |
| gpr_mu_lock(&g_mu); |
| connections_complete_before = g_connections_complete; |
| gpr_mu_unlock(&g_mu); |
| |
| /* connect to it */ |
| GPR_ASSERT(getsockname(svr_fd, (struct sockaddr*)addr, (socklen_t*)&resolved_addr->len) == 0); |
| GRPC_CLOSURE_INIT(&done, must_succeed, nullptr, grpc_schedule_on_exec_ctx); |
| auto args = |
| grpc_core::CoreConfiguration::Get().channel_args_preconditioning().PreconditionChannelArgs( |
| nullptr); |
| grpc_tcp_client_connect(&done, &g_connecting, nullptr, |
| grpc_event_engine::experimental::ChannelArgsEndpointConfig(args), |
| &*resolved_addr, grpc_core::Timestamp::InfFuture()); |
| |
| /* await the connection */ |
| do { |
| resolved_addr->len = sizeof(addr); |
| r = accept(svr_fd, reinterpret_cast<struct sockaddr*>(addr), |
| reinterpret_cast<socklen_t*>(&resolved_addr->len)); |
| } while (r == -1 && errno == EINTR); |
| GPR_ASSERT(r >= 0); |
| close(r); |
| |
| grpc_core::ExecCtx::Get()->Flush(); |
| |
| /* wait for the connection callback to finish */ |
| gpr_mu_lock(&g_mu); |
| NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:5]; |
| while (connections_complete_before == g_connections_complete) { |
| gpr_mu_unlock(&g_mu); |
| [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline]; |
| gpr_mu_lock(&g_mu); |
| } |
| XCTAssertGreaterThan(g_connections_complete, connections_complete_before); |
| |
| gpr_mu_unlock(&g_mu); |
| } |
| |
| - (void)testFails { |
| grpc_core::ExecCtx exec_ctx; |
| |
| int connections_complete_before; |
| grpc_closure done; |
| int svr_fd; |
| |
| gpr_log(GPR_DEBUG, "test_fails"); |
| |
| auto resolved_addr = grpc_core::StringToSockaddr("127.0.0.1:0"); |
| GPR_ASSERT(resolved_addr.ok()); |
| struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(resolved_addr->addr); |
| |
| svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
| GPR_ASSERT(svr_fd >= 0); |
| GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr*)addr, (socklen_t)resolved_addr->len)); |
| GPR_ASSERT(0 == listen(svr_fd, 1)); |
| GPR_ASSERT(getsockname(svr_fd, (struct sockaddr*)addr, (socklen_t*)&resolved_addr->len) == 0); |
| close(svr_fd); |
| |
| gpr_mu_lock(&g_mu); |
| connections_complete_before = g_connections_complete; |
| gpr_mu_unlock(&g_mu); |
| |
| /* connect to a broken address */ |
| GRPC_CLOSURE_INIT(&done, must_fail, nullptr, grpc_schedule_on_exec_ctx); |
| auto args = |
| grpc_core::CoreConfiguration::Get().channel_args_preconditioning().PreconditionChannelArgs( |
| nullptr); |
| grpc_tcp_client_connect(&done, &g_connecting, nullptr, |
| grpc_event_engine::experimental::ChannelArgsEndpointConfig(args), |
| &*resolved_addr, grpc_core::Timestamp::InfFuture()); |
| |
| grpc_core::ExecCtx::Get()->Flush(); |
| |
| /* wait for the connection callback to finish */ |
| gpr_mu_lock(&g_mu); |
| NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:5]; |
| while (g_connections_complete == connections_complete_before) { |
| gpr_mu_unlock(&g_mu); |
| [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline]; |
| gpr_mu_lock(&g_mu); |
| } |
| |
| XCTAssertGreaterThan(g_connections_complete, connections_complete_before); |
| |
| gpr_mu_unlock(&g_mu); |
| } |
| |
| @end |
| |
| #else // GRPC_CFSTREAM |
| |
| // Phony test suite |
| @interface CFStreamClientTests : XCTestCase |
| |
| @end |
| |
| @implementation CFStreamClientTests |
| |
| - (void)setUp { |
| [super setUp]; |
| } |
| |
| - (void)tearDown { |
| [super tearDown]; |
| } |
| |
| @end |
| |
| #endif // GRPC_CFSTREAM |