xref: /aosp_15_r20/external/grpc-grpc/src/objective-c/tests/CFStreamTests/CFStreamEndpointTests.mm (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker/*
2*cc02d7e2SAndroid Build Coastguard Worker *
3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2018 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker *
5*cc02d7e2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker *
9*cc02d7e2SAndroid Build Coastguard Worker *     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker *
11*cc02d7e2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker * limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker *
17*cc02d7e2SAndroid Build Coastguard Worker */
18*cc02d7e2SAndroid Build Coastguard Worker
19*cc02d7e2SAndroid Build Coastguard Worker#import <XCTest/XCTest.h>
20*cc02d7e2SAndroid Build Coastguard Worker
21*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/iomgr/port.h"
22*cc02d7e2SAndroid Build Coastguard Worker
23*cc02d7e2SAndroid Build Coastguard Worker#ifdef GRPC_CFSTREAM
24*cc02d7e2SAndroid Build Coastguard Worker
25*cc02d7e2SAndroid Build Coastguard Worker#include <limits.h>
26*cc02d7e2SAndroid Build Coastguard Worker
27*cc02d7e2SAndroid Build Coastguard Worker#include <netinet/in.h>
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard Worker#include <grpc/grpc.h>
30*cc02d7e2SAndroid Build Coastguard Worker#include <grpc/impl/codegen/sync.h>
31*cc02d7e2SAndroid Build Coastguard Worker#include <grpc/support/sync.h>
32*cc02d7e2SAndroid Build Coastguard Worker
33*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/address_utils/parse_address.h"
34*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/address_utils/sockaddr_utils.h"
35*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
36*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/iomgr/endpoint.h"
37*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/iomgr/resolve_address.h"
38*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/iomgr/tcp_client.h"
39*cc02d7e2SAndroid Build Coastguard Worker#include "src/core/lib/resource_quota/api.h"
40*cc02d7e2SAndroid Build Coastguard Worker#include "test/core/util/test_config.h"
41*cc02d7e2SAndroid Build Coastguard Worker
42*cc02d7e2SAndroid Build Coastguard Worker#include <chrono>
43*cc02d7e2SAndroid Build Coastguard Worker#include <future>
44*cc02d7e2SAndroid Build Coastguard Worker
45*cc02d7e2SAndroid Build Coastguard Workerstatic const int kConnectTimeout = 5;
46*cc02d7e2SAndroid Build Coastguard Workerstatic const int kWriteTimeout = 5;
47*cc02d7e2SAndroid Build Coastguard Workerstatic const int kReadTimeout = 5;
48*cc02d7e2SAndroid Build Coastguard Worker
49*cc02d7e2SAndroid Build Coastguard Workerstatic const int kBufferSize = 10000;
50*cc02d7e2SAndroid Build Coastguard Worker
51*cc02d7e2SAndroid Build Coastguard Workerstatic const int kRunLoopTimeout = 1;
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard Workerstatic void set_error_handle_promise(void *arg, grpc_error_handle error) {
54*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> *p = static_cast<std::promise<grpc_error_handle> *>(arg);
55*cc02d7e2SAndroid Build Coastguard Worker  p->set_value(error);
56*cc02d7e2SAndroid Build Coastguard Worker}
57*cc02d7e2SAndroid Build Coastguard Worker
58*cc02d7e2SAndroid Build Coastguard Workerstatic void init_event_closure(grpc_closure *closure,
59*cc02d7e2SAndroid Build Coastguard Worker                               std::promise<grpc_error_handle> *error_handle) {
60*cc02d7e2SAndroid Build Coastguard Worker  GRPC_CLOSURE_INIT(closure, set_error_handle_promise, static_cast<void *>(error_handle),
61*cc02d7e2SAndroid Build Coastguard Worker                    grpc_schedule_on_exec_ctx);
62*cc02d7e2SAndroid Build Coastguard Worker}
63*cc02d7e2SAndroid Build Coastguard Worker
64*cc02d7e2SAndroid Build Coastguard Workerstatic bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const char *buffer,
65*cc02d7e2SAndroid Build Coastguard Worker                                             size_t buffer_len) {
66*cc02d7e2SAndroid Build Coastguard Worker  if (slices->length != buffer_len) {
67*cc02d7e2SAndroid Build Coastguard Worker    return false;
68*cc02d7e2SAndroid Build Coastguard Worker  }
69*cc02d7e2SAndroid Build Coastguard Worker
70*cc02d7e2SAndroid Build Coastguard Worker  for (int i = 0; i < slices->count; i++) {
71*cc02d7e2SAndroid Build Coastguard Worker    grpc_slice slice = slices->slices[i];
72*cc02d7e2SAndroid Build Coastguard Worker    if (0 != memcmp(buffer, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice))) {
73*cc02d7e2SAndroid Build Coastguard Worker      return false;
74*cc02d7e2SAndroid Build Coastguard Worker    }
75*cc02d7e2SAndroid Build Coastguard Worker    buffer += GRPC_SLICE_LENGTH(slice);
76*cc02d7e2SAndroid Build Coastguard Worker  }
77*cc02d7e2SAndroid Build Coastguard Worker
78*cc02d7e2SAndroid Build Coastguard Worker  return true;
79*cc02d7e2SAndroid Build Coastguard Worker}
80*cc02d7e2SAndroid Build Coastguard Worker
81*cc02d7e2SAndroid Build Coastguard Worker@interface CFStreamEndpointTests : XCTestCase
82*cc02d7e2SAndroid Build Coastguard Worker
83*cc02d7e2SAndroid Build Coastguard Worker@end
84*cc02d7e2SAndroid Build Coastguard Worker
85*cc02d7e2SAndroid Build Coastguard Worker@implementation CFStreamEndpointTests {
86*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint *ep_;
87*cc02d7e2SAndroid Build Coastguard Worker  int svr_fd_;
88*cc02d7e2SAndroid Build Coastguard Worker}
89*cc02d7e2SAndroid Build Coastguard Worker
90*cc02d7e2SAndroid Build Coastguard Worker- (BOOL)waitForEvent:(std::future<grpc_error_handle> *)event timeout:(int)timeout {
91*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx::Get()->Flush();
92*cc02d7e2SAndroid Build Coastguard Worker  return event->wait_for(std::chrono::seconds(timeout)) != std::future_status::timeout;
93*cc02d7e2SAndroid Build Coastguard Worker}
94*cc02d7e2SAndroid Build Coastguard Worker
95*cc02d7e2SAndroid Build Coastguard Worker+ (void)setUp {
96*cc02d7e2SAndroid Build Coastguard Worker  grpc_init();
97*cc02d7e2SAndroid Build Coastguard Worker}
98*cc02d7e2SAndroid Build Coastguard Worker
99*cc02d7e2SAndroid Build Coastguard Worker+ (void)tearDown {
100*cc02d7e2SAndroid Build Coastguard Worker  grpc_shutdown();
101*cc02d7e2SAndroid Build Coastguard Worker}
102*cc02d7e2SAndroid Build Coastguard Worker
103*cc02d7e2SAndroid Build Coastguard Worker- (void)setUp {
104*cc02d7e2SAndroid Build Coastguard Worker  self.continueAfterFailure = NO;
105*cc02d7e2SAndroid Build Coastguard Worker
106*cc02d7e2SAndroid Build Coastguard Worker  // Set up CFStream connection before testing the endpoint
107*cc02d7e2SAndroid Build Coastguard Worker
108*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
109*cc02d7e2SAndroid Build Coastguard Worker
110*cc02d7e2SAndroid Build Coastguard Worker  int svr_fd;
111*cc02d7e2SAndroid Build Coastguard Worker  int r;
112*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> connected_promise;
113*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure done;
114*cc02d7e2SAndroid Build Coastguard Worker
115*cc02d7e2SAndroid Build Coastguard Worker  gpr_log(GPR_DEBUG, "test_succeeds");
116*cc02d7e2SAndroid Build Coastguard Worker
117*cc02d7e2SAndroid Build Coastguard Worker  auto resolved_addr = grpc_core::StringToSockaddr("127.0.0.1:0");
118*cc02d7e2SAndroid Build Coastguard Worker  struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(resolved_addr->addr);
119*cc02d7e2SAndroid Build Coastguard Worker
120*cc02d7e2SAndroid Build Coastguard Worker  /* create a phony server */
121*cc02d7e2SAndroid Build Coastguard Worker  svr_fd = socket(AF_INET, SOCK_STREAM, 0);
122*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertGreaterThanOrEqual(svr_fd, 0);
123*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(bind(svr_fd, (struct sockaddr *)addr, (socklen_t)resolved_addr->len), 0);
124*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(listen(svr_fd, 1), 0);
125*cc02d7e2SAndroid Build Coastguard Worker
126*cc02d7e2SAndroid Build Coastguard Worker  /* connect to it */
127*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(getsockname(svr_fd, (struct sockaddr *)addr, (socklen_t *)&resolved_addr->len), 0);
128*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&done, &connected_promise);
129*cc02d7e2SAndroid Build Coastguard Worker  auto args =
130*cc02d7e2SAndroid Build Coastguard Worker      grpc_core::CoreConfiguration::Get().channel_args_preconditioning().PreconditionChannelArgs(
131*cc02d7e2SAndroid Build Coastguard Worker          nullptr);
132*cc02d7e2SAndroid Build Coastguard Worker  grpc_tcp_client_connect(&done, &ep_, nullptr,
133*cc02d7e2SAndroid Build Coastguard Worker                          grpc_event_engine::experimental::ChannelArgsEndpointConfig(args),
134*cc02d7e2SAndroid Build Coastguard Worker                          &*resolved_addr, grpc_core::Timestamp::InfFuture());
135*cc02d7e2SAndroid Build Coastguard Worker
136*cc02d7e2SAndroid Build Coastguard Worker  /* await the connection */
137*cc02d7e2SAndroid Build Coastguard Worker  do {
138*cc02d7e2SAndroid Build Coastguard Worker    resolved_addr->len = sizeof(addr);
139*cc02d7e2SAndroid Build Coastguard Worker    r = accept(svr_fd, reinterpret_cast<struct sockaddr *>(addr),
140*cc02d7e2SAndroid Build Coastguard Worker               reinterpret_cast<socklen_t *>(&resolved_addr->len));
141*cc02d7e2SAndroid Build Coastguard Worker  } while (r == -1 && errno == EINTR);
142*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertGreaterThanOrEqual(r, 0, @"connection failed with return code %@ and errno %@", @(r),
143*cc02d7e2SAndroid Build Coastguard Worker                              @(errno));
144*cc02d7e2SAndroid Build Coastguard Worker  svr_fd_ = r;
145*cc02d7e2SAndroid Build Coastguard Worker
146*cc02d7e2SAndroid Build Coastguard Worker  /* wait for the connection callback to finish */
147*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> connected_future = connected_promise.get_future();
148*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&connected_future timeout:kConnectTimeout], YES);
149*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(connected_future.get(), absl::OkStatus());
150*cc02d7e2SAndroid Build Coastguard Worker}
151*cc02d7e2SAndroid Build Coastguard Worker
152*cc02d7e2SAndroid Build Coastguard Worker- (void)tearDown {
153*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
154*cc02d7e2SAndroid Build Coastguard Worker  close(svr_fd_);
155*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_destroy(ep_);
156*cc02d7e2SAndroid Build Coastguard Worker}
157*cc02d7e2SAndroid Build Coastguard Worker
158*cc02d7e2SAndroid Build Coastguard Worker- (void)testReadWrite {
159*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
160*cc02d7e2SAndroid Build Coastguard Worker
161*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure read_done;
162*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer read_slices;
163*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer read_one_slice;
164*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> write_promise;
165*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure write_done;
166*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer write_slices;
167*cc02d7e2SAndroid Build Coastguard Worker
168*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice slice;
169*cc02d7e2SAndroid Build Coastguard Worker  char write_buffer[kBufferSize];
170*cc02d7e2SAndroid Build Coastguard Worker  char read_buffer[kBufferSize];
171*cc02d7e2SAndroid Build Coastguard Worker  size_t recv_size = 0;
172*cc02d7e2SAndroid Build Coastguard Worker
173*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&write_slices);
174*cc02d7e2SAndroid Build Coastguard Worker  slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize);
175*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_add(&write_slices, slice);
176*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&write_done, &write_promise);
177*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr, /*max_frame_size=*/INT_MAX);
178*cc02d7e2SAndroid Build Coastguard Worker
179*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> write_future = write_promise.get_future();
180*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&write_future timeout:kWriteTimeout], YES);
181*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(write_future.get(), absl::OkStatus());
182*cc02d7e2SAndroid Build Coastguard Worker
183*cc02d7e2SAndroid Build Coastguard Worker  while (recv_size < kBufferSize) {
184*cc02d7e2SAndroid Build Coastguard Worker    ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
185*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertGreaterThanOrEqual(size, 0);
186*cc02d7e2SAndroid Build Coastguard Worker    recv_size += size;
187*cc02d7e2SAndroid Build Coastguard Worker  }
188*cc02d7e2SAndroid Build Coastguard Worker
189*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(recv_size, kBufferSize);
190*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0);
191*cc02d7e2SAndroid Build Coastguard Worker  ssize_t send_size = send(svr_fd_, read_buffer, kBufferSize, 0);
192*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertGreaterThanOrEqual(send_size, 0);
193*cc02d7e2SAndroid Build Coastguard Worker
194*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&read_slices);
195*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&read_one_slice);
196*cc02d7e2SAndroid Build Coastguard Worker  while (read_slices.length < kBufferSize) {
197*cc02d7e2SAndroid Build Coastguard Worker    std::promise<grpc_error_handle> read_promise;
198*cc02d7e2SAndroid Build Coastguard Worker    init_event_closure(&read_done, &read_promise);
199*cc02d7e2SAndroid Build Coastguard Worker    grpc_endpoint_read(ep_, &read_one_slice, &read_done, /*urgent=*/false,
200*cc02d7e2SAndroid Build Coastguard Worker                       /*min_progress_size=*/1);
201*cc02d7e2SAndroid Build Coastguard Worker    std::future<grpc_error_handle> read_future = read_promise.get_future();
202*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertEqual([self waitForEvent:&read_future timeout:kReadTimeout], YES);
203*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertEqual(read_future.get(), absl::OkStatus());
204*cc02d7e2SAndroid Build Coastguard Worker    grpc_slice_buffer_move_into(&read_one_slice, &read_slices);
205*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertLessThanOrEqual(read_slices.length, kBufferSize);
206*cc02d7e2SAndroid Build Coastguard Worker  }
207*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertTrue(compare_slice_buffer_with_buffer(&read_slices, read_buffer, kBufferSize));
208*cc02d7e2SAndroid Build Coastguard Worker
209*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_shutdown(ep_, absl::OkStatus());
210*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&read_slices);
211*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&write_slices);
212*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&read_one_slice);
213*cc02d7e2SAndroid Build Coastguard Worker}
214*cc02d7e2SAndroid Build Coastguard Worker
215*cc02d7e2SAndroid Build Coastguard Worker- (void)testShutdownBeforeRead {
216*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
217*cc02d7e2SAndroid Build Coastguard Worker
218*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> read_promise;
219*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure read_done;
220*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer read_slices;
221*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> write_promise;
222*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure write_done;
223*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer write_slices;
224*cc02d7e2SAndroid Build Coastguard Worker
225*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice slice;
226*cc02d7e2SAndroid Build Coastguard Worker  char write_buffer[kBufferSize];
227*cc02d7e2SAndroid Build Coastguard Worker  char read_buffer[kBufferSize];
228*cc02d7e2SAndroid Build Coastguard Worker  size_t recv_size = 0;
229*cc02d7e2SAndroid Build Coastguard Worker
230*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&read_slices);
231*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&read_done, &read_promise);
232*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_read(ep_, &read_slices, &read_done, /*urgent=*/false,
233*cc02d7e2SAndroid Build Coastguard Worker                     /*min_progress_size=*/1);
234*cc02d7e2SAndroid Build Coastguard Worker
235*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&write_slices);
236*cc02d7e2SAndroid Build Coastguard Worker  slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize);
237*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_add(&write_slices, slice);
238*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&write_done, &write_promise);
239*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr, /*max_frame_size=*/INT_MAX);
240*cc02d7e2SAndroid Build Coastguard Worker
241*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> write_future = write_promise.get_future();
242*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&write_future timeout:kWriteTimeout], YES);
243*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(write_future.get(), absl::OkStatus());
244*cc02d7e2SAndroid Build Coastguard Worker
245*cc02d7e2SAndroid Build Coastguard Worker  while (recv_size < kBufferSize) {
246*cc02d7e2SAndroid Build Coastguard Worker    ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
247*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertGreaterThanOrEqual(size, 0);
248*cc02d7e2SAndroid Build Coastguard Worker    recv_size += size;
249*cc02d7e2SAndroid Build Coastguard Worker  }
250*cc02d7e2SAndroid Build Coastguard Worker
251*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(recv_size, kBufferSize);
252*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0);
253*cc02d7e2SAndroid Build Coastguard Worker
254*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> read_future = read_promise.get_future();
255*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&read_future timeout:kReadTimeout], NO);
256*cc02d7e2SAndroid Build Coastguard Worker
257*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_shutdown(ep_, absl::OkStatus());
258*cc02d7e2SAndroid Build Coastguard Worker
259*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx::Get()->Flush();
260*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&read_future timeout:kReadTimeout], YES);
261*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertNotEqual(read_future.get(), absl::OkStatus());
262*cc02d7e2SAndroid Build Coastguard Worker
263*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&read_slices);
264*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&write_slices);
265*cc02d7e2SAndroid Build Coastguard Worker}
266*cc02d7e2SAndroid Build Coastguard Worker
267*cc02d7e2SAndroid Build Coastguard Worker- (void)testRemoteClosed {
268*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
269*cc02d7e2SAndroid Build Coastguard Worker
270*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> read_promise;
271*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure read_done;
272*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer read_slices;
273*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> write_promise;
274*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure write_done;
275*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer write_slices;
276*cc02d7e2SAndroid Build Coastguard Worker
277*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice slice;
278*cc02d7e2SAndroid Build Coastguard Worker  char write_buffer[kBufferSize];
279*cc02d7e2SAndroid Build Coastguard Worker  char read_buffer[kBufferSize];
280*cc02d7e2SAndroid Build Coastguard Worker  size_t recv_size = 0;
281*cc02d7e2SAndroid Build Coastguard Worker
282*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&read_done, &read_promise);
283*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&read_slices);
284*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_read(ep_, &read_slices, &read_done, /*urgent=*/false,
285*cc02d7e2SAndroid Build Coastguard Worker                     /*min_progress_size=*/1);
286*cc02d7e2SAndroid Build Coastguard Worker
287*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&write_slices);
288*cc02d7e2SAndroid Build Coastguard Worker  slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize);
289*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_add(&write_slices, slice);
290*cc02d7e2SAndroid Build Coastguard Worker
291*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&write_done, &write_promise);
292*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_write(ep_, &write_slices, &write_done, nullptr, /*max_frame_size=*/INT_MAX);
293*cc02d7e2SAndroid Build Coastguard Worker
294*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> write_future = write_promise.get_future();
295*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&write_future timeout:kWriteTimeout], YES);
296*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(write_future.get(), absl::OkStatus());
297*cc02d7e2SAndroid Build Coastguard Worker
298*cc02d7e2SAndroid Build Coastguard Worker  while (recv_size < kBufferSize) {
299*cc02d7e2SAndroid Build Coastguard Worker    ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0);
300*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertGreaterThanOrEqual(size, 0);
301*cc02d7e2SAndroid Build Coastguard Worker    recv_size += size;
302*cc02d7e2SAndroid Build Coastguard Worker  }
303*cc02d7e2SAndroid Build Coastguard Worker
304*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(recv_size, kBufferSize);
305*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0);
306*cc02d7e2SAndroid Build Coastguard Worker
307*cc02d7e2SAndroid Build Coastguard Worker  close(svr_fd_);
308*cc02d7e2SAndroid Build Coastguard Worker
309*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> read_future = read_promise.get_future();
310*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&read_future timeout:kReadTimeout], YES);
311*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertNotEqual(read_future.get(), absl::OkStatus());
312*cc02d7e2SAndroid Build Coastguard Worker
313*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_shutdown(ep_, absl::OkStatus());
314*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&read_slices);
315*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&write_slices);
316*cc02d7e2SAndroid Build Coastguard Worker}
317*cc02d7e2SAndroid Build Coastguard Worker
318*cc02d7e2SAndroid Build Coastguard Worker- (void)testRemoteReset {
319*cc02d7e2SAndroid Build Coastguard Worker  grpc_core::ExecCtx exec_ctx;
320*cc02d7e2SAndroid Build Coastguard Worker
321*cc02d7e2SAndroid Build Coastguard Worker  std::promise<grpc_error_handle> read_promise;
322*cc02d7e2SAndroid Build Coastguard Worker  grpc_closure read_done;
323*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer read_slices;
324*cc02d7e2SAndroid Build Coastguard Worker
325*cc02d7e2SAndroid Build Coastguard Worker  init_event_closure(&read_done, &read_promise);
326*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_init(&read_slices);
327*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_read(ep_, &read_slices, &read_done, /*urgent=*/false,
328*cc02d7e2SAndroid Build Coastguard Worker                     /*min_progress_size=*/1);
329*cc02d7e2SAndroid Build Coastguard Worker
330*cc02d7e2SAndroid Build Coastguard Worker  struct linger so_linger;
331*cc02d7e2SAndroid Build Coastguard Worker  so_linger.l_onoff = 1;
332*cc02d7e2SAndroid Build Coastguard Worker  so_linger.l_linger = 0;
333*cc02d7e2SAndroid Build Coastguard Worker  setsockopt(svr_fd_, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
334*cc02d7e2SAndroid Build Coastguard Worker
335*cc02d7e2SAndroid Build Coastguard Worker  close(svr_fd_);
336*cc02d7e2SAndroid Build Coastguard Worker
337*cc02d7e2SAndroid Build Coastguard Worker  std::future<grpc_error_handle> read_future = read_promise.get_future();
338*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertEqual([self waitForEvent:&read_future timeout:kReadTimeout], YES);
339*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertNotEqual(read_future.get(), absl::OkStatus());
340*cc02d7e2SAndroid Build Coastguard Worker
341*cc02d7e2SAndroid Build Coastguard Worker  grpc_endpoint_shutdown(ep_, absl::OkStatus());
342*cc02d7e2SAndroid Build Coastguard Worker  grpc_slice_buffer_reset_and_unref(&read_slices);
343*cc02d7e2SAndroid Build Coastguard Worker}
344*cc02d7e2SAndroid Build Coastguard Worker
345*cc02d7e2SAndroid Build Coastguard Worker@end
346*cc02d7e2SAndroid Build Coastguard Worker
347*cc02d7e2SAndroid Build Coastguard Worker#else  // GRPC_CFSTREAM
348*cc02d7e2SAndroid Build Coastguard Worker
349*cc02d7e2SAndroid Build Coastguard Worker// Phony test suite
350*cc02d7e2SAndroid Build Coastguard Worker@interface CFStreamEndpointTests : XCTestCase
351*cc02d7e2SAndroid Build Coastguard Worker@end
352*cc02d7e2SAndroid Build Coastguard Worker
353*cc02d7e2SAndroid Build Coastguard Worker@implementation CFStreamEndpointTests
354*cc02d7e2SAndroid Build Coastguard Worker- (void)setUp {
355*cc02d7e2SAndroid Build Coastguard Worker  [super setUp];
356*cc02d7e2SAndroid Build Coastguard Worker}
357*cc02d7e2SAndroid Build Coastguard Worker
358*cc02d7e2SAndroid Build Coastguard Worker- (void)tearDown {
359*cc02d7e2SAndroid Build Coastguard Worker  [super tearDown];
360*cc02d7e2SAndroid Build Coastguard Worker}
361*cc02d7e2SAndroid Build Coastguard Worker
362*cc02d7e2SAndroid Build Coastguard Worker@end
363*cc02d7e2SAndroid Build Coastguard Worker
364*cc02d7e2SAndroid Build Coastguard Worker#endif  // GRPC_CFSTREAM
365