示例#1
0
static void verify_partial_carnage_round_robin(
    const servers_fixture *f, grpc_channel *client,
    const request_sequences *sequences, const size_t num_iters) {
  int *expected_connection_sequence;
  size_t i;
  const size_t expected_seq_length = f->num_servers;

  /* verify conn. seq. expectation */
  /* get the first sequence of "num_servers" elements */
  expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
  memcpy(expected_connection_sequence, sequences->connections,
         sizeof(int) * expected_seq_length);

  for (i = 0; i < num_iters / 2; i++) {
    const int actual = sequences->connections[i];
    const int expected = expected_connection_sequence[i % expected_seq_length];
    if (actual != expected) {
      print_failed_expectations(expected_connection_sequence,
                                sequences->connections, expected_seq_length,
                                num_iters);
      abort();
    }
  }

  /* second half of the iterations go without response */
  for (; i < num_iters; i++) {
    GPR_ASSERT(sequences->connections[i] == -1);
  }

  /* We can assert that the first client channel state should be READY, when all
   * servers were available */
  grpc_connectivity_state actual = sequences->connectivity_states[0];
  grpc_connectivity_state expected = GRPC_CHANNEL_READY;
  if (actual != expected) {
    gpr_log(GPR_ERROR,
            "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
            "at iteration #%d",
            grpc_connectivity_state_name(expected),
            grpc_connectivity_state_name(actual), 0);
    abort();
  }

  /* ... and that the last one shouldn't be READY (or SHUTDOWN): all servers are
   * gone. It may be all other states (IDLE, CONNECTING, TRANSIENT_FAILURE), as
   * the policy transitions while attempting to reconnect. */
  actual = sequences->connectivity_states[num_iters - 1];
  for (i = 0; i < sequences->n; i++) {
    if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) {
      gpr_log(GPR_ERROR,
              "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state "
              "'%s' at iteration #%d.",
              grpc_connectivity_state_name(actual), (int)i);
      abort();
    }
  }
  gpr_free(expected_connection_sequence);
}
示例#2
0
/* At the start of the second iteration, all but the first and last servers (as
 * given in "f") are killed */
static void verify_vanishing_floor_round_robin(
    const servers_fixture *f, grpc_channel *client,
    const request_sequences *sequences, const size_t num_iters) {
  int *expected_connection_sequence;
  const size_t expected_seq_length = 2;
  size_t i;

  /* verify conn. seq. expectation */
  /* copy the first full sequence (without -1s) */
  expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
  memcpy(expected_connection_sequence, sequences->connections + 2,
         expected_seq_length * sizeof(int));

  /* first two elements of the sequence should be [0 (1st server), -1 (failure)]
   */
  GPR_ASSERT(sequences->connections[0] == 0);
  GPR_ASSERT(sequences->connections[1] == -1);

  /* the next two element must be [3, 0], repeating from that point: the 3 is
   * brought forth by servers 1 and 2 disappearing after the intial pick of 0 */
  GPR_ASSERT(sequences->connections[2] == 3);
  GPR_ASSERT(sequences->connections[3] == 0);

  /* make sure that the expectation obliges */
  for (i = 2; i < num_iters; i++) {
    const int actual = sequences->connections[i];
    const int expected = expected_connection_sequence[i % expected_seq_length];
    if (actual != expected) {
      print_failed_expectations(expected_connection_sequence,
                                sequences->connections, expected_seq_length,
                                num_iters);
      abort();
    }
  }

  /* There's always at least one subchannel READY (connected), therefore the
   * overall state of the client channel is READY at all times. */
  for (i = 0; i < sequences->n; i++) {
    const grpc_connectivity_state actual = sequences->connectivity_states[i];
    const grpc_connectivity_state expected = GRPC_CHANNEL_READY;
    if (actual != expected) {
      gpr_log(GPR_ERROR,
              "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
              "at iteration #%d",
              grpc_connectivity_state_name(expected),
              grpc_connectivity_state_name(actual), (int)i);
      abort();
    }
  }

  gpr_free(expected_connection_sequence);
}
示例#3
0
bool grpc_connectivity_state_notify_on_state_change(
    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
    grpc_connectivity_state *current, grpc_closure *notify) {
  grpc_connectivity_state cur =
      (grpc_connectivity_state)gpr_atm_no_barrier_load(
          &tracker->current_state_atm);
  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
    if (current == NULL) {
      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
              tracker->name, notify);
    } else {
      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
              tracker->name, grpc_connectivity_state_name(*current),
              grpc_connectivity_state_name(cur), notify);
    }
  }
  if (current == NULL) {
    grpc_connectivity_state_watcher *w = tracker->watchers;
    if (w != NULL && w->notify == notify) {
      GRPC_CLOSURE_SCHED(exec_ctx, notify, GRPC_ERROR_CANCELLED);
      tracker->watchers = w->next;
      gpr_free(w);
      return false;
    }
    while (w != NULL) {
      grpc_connectivity_state_watcher *rm_candidate = w->next;
      if (rm_candidate != NULL && rm_candidate->notify == notify) {
        GRPC_CLOSURE_SCHED(exec_ctx, notify, GRPC_ERROR_CANCELLED);
        w->next = w->next->next;
        gpr_free(rm_candidate);
        return false;
      }
      w = w->next;
    }
    return false;
  } else {
    if (cur != *current) {
      *current = cur;
      GRPC_CLOSURE_SCHED(exec_ctx, notify,
                         GRPC_ERROR_REF(tracker->current_error));
    } else {
      grpc_connectivity_state_watcher *w =
          (grpc_connectivity_state_watcher *)gpr_malloc(sizeof(*w));
      w->current = current;
      w->notify = notify;
      w->next = tracker->watchers;
      tracker->watchers = w;
    }
    return cur == GRPC_CHANNEL_IDLE;
  }
}
static void test_connectivity_state_name(void) {
  gpr_log(GPR_DEBUG, "test_connectivity_state_name");
  GPR_ASSERT(0 ==
             strcmp(grpc_connectivity_state_name(GRPC_CHANNEL_IDLE), "IDLE"));
  GPR_ASSERT(0 == strcmp(grpc_connectivity_state_name(GRPC_CHANNEL_CONNECTING),
                         "CONNECTING"));
  GPR_ASSERT(0 ==
             strcmp(grpc_connectivity_state_name(GRPC_CHANNEL_READY), "READY"));
  GPR_ASSERT(
      0 == strcmp(grpc_connectivity_state_name(GRPC_CHANNEL_TRANSIENT_FAILURE),
                  "TRANSIENT_FAILURE"));
  GPR_ASSERT(0 == strcmp(grpc_connectivity_state_name(GRPC_CHANNEL_SHUTDOWN),
                         "SHUTDOWN"));
}
示例#5
0
static void verify_total_carnage_round_robin(const servers_fixture *f,
                                             grpc_channel *client,
                                             const request_sequences *sequences,
                                             const size_t num_iters) {
  for (size_t i = 0; i < num_iters; i++) {
    const int actual = sequences->connections[i];
    const int expected = -1;
    if (actual != expected) {
      gpr_log(
          GPR_ERROR,
          "CONNECTION SEQUENCE FAILURE: expected %d, got %d at iteration #%d",
          expected, actual, (int)i);
      abort();
    }
  }

  /* No server is ever available. There should be no READY states (or SHUTDOWN).
   * Note that all other states (IDLE, CONNECTING, TRANSIENT_FAILURE) are still
   * possible, as the policy transitions while attempting to reconnect. */
  for (size_t i = 0; i < sequences->n; i++) {
    const grpc_connectivity_state actual = sequences->connectivity_states[i];
    if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) {
      gpr_log(GPR_ERROR,
              "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state "
              "'%s' at iteration #%d.",
              grpc_connectivity_state_name(actual), (int)i);
      abort();
    }
  }
}
示例#6
0
int grpc_connectivity_state_notify_on_state_change(
    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
    grpc_connectivity_state *current, grpc_closure *notify) {
  if (grpc_connectivity_state_trace) {
    if (current == NULL) {
      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
              tracker->name, notify);
    } else {
      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
              tracker->name, grpc_connectivity_state_name(*current),
              grpc_connectivity_state_name(tracker->current_state), notify);
    }
  }
  if (current == NULL) {
    grpc_connectivity_state_watcher *w = tracker->watchers;
    if (w != NULL && w->notify == notify) {
      grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
      tracker->watchers = w->next;
      gpr_free(w);
      return 0;
    }
    while (w != NULL) {
      grpc_connectivity_state_watcher *rm_candidate = w->next;
      if (rm_candidate != NULL && rm_candidate->notify == notify) {
        grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
        w->next = w->next->next;
        gpr_free(rm_candidate);
        return 0;
      }
      w = w->next;
    }
    return 0;
  } else {
    if (tracker->current_state != *current) {
      *current = tracker->current_state;
      grpc_exec_ctx_sched(exec_ctx, notify,
                          GRPC_ERROR_REF(tracker->current_error), NULL);
    } else {
      grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
      w->current = current;
      w->notify = notify;
      w->next = tracker->watchers;
      tracker->watchers = w;
    }
    return tracker->current_state == GRPC_CHANNEL_IDLE;
  }
}
示例#7
0
grpc_connectivity_state grpc_connectivity_state_check(
    grpc_connectivity_state_tracker *tracker) {
  if (grpc_connectivity_state_trace) {
    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
            grpc_connectivity_state_name(tracker->current_state));
  }
  return tracker->current_state;
}
示例#8
0
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
                                 grpc_connectivity_state_tracker *tracker,
                                 grpc_connectivity_state state,
                                 grpc_error *error, const char *reason) {
  grpc_connectivity_state cur =
      (grpc_connectivity_state)gpr_atm_no_barrier_load(
          &tracker->current_state_atm);
  grpc_connectivity_state_watcher *w;
  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
    const char *error_string = grpc_error_string(error);
    gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker,
            tracker->name, grpc_connectivity_state_name(cur),
            grpc_connectivity_state_name(state), reason, error, error_string);
  }
  switch (state) {
    case GRPC_CHANNEL_INIT:
    case GRPC_CHANNEL_CONNECTING:
    case GRPC_CHANNEL_IDLE:
    case GRPC_CHANNEL_READY:
      GPR_ASSERT(error == GRPC_ERROR_NONE);
      break;
    case GRPC_CHANNEL_SHUTDOWN:
    case GRPC_CHANNEL_TRANSIENT_FAILURE:
      GPR_ASSERT(error != GRPC_ERROR_NONE);
      break;
  }
  GRPC_ERROR_UNREF(tracker->current_error);
  tracker->current_error = error;
  if (cur == state) {
    return;
  }
  GPR_ASSERT(cur != GRPC_CHANNEL_SHUTDOWN);
  gpr_atm_no_barrier_store(&tracker->current_state_atm, state);
  while ((w = tracker->watchers) != NULL) {
    *w->current = state;
    tracker->watchers = w->next;
    if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
      gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name,
              w->notify);
    }
    GRPC_CLOSURE_SCHED(exec_ctx, w->notify,
                       GRPC_ERROR_REF(tracker->current_error));
    gpr_free(w);
  }
}
示例#9
0
static void verify_vanilla_round_robin(const servers_fixture *f,
                                       grpc_channel *client,
                                       const request_sequences *sequences,
                                       const size_t num_iters) {
  const size_t expected_seq_length = f->num_servers;

  /* verify conn. seq. expectation */
  /* get the first sequence of "num_servers" elements */
  int *expected_connection_sequence =
      gpr_malloc(sizeof(int) * expected_seq_length);
  memcpy(expected_connection_sequence, sequences->connections,
         sizeof(int) * expected_seq_length);

  for (size_t i = 0; i < num_iters; i++) {
    const int actual = sequences->connections[i];
    const int expected = expected_connection_sequence[i % expected_seq_length];
    if (actual != expected) {
      gpr_log(
          GPR_ERROR,
          "CONNECTION SEQUENCE FAILURE: expected %d, got %d at iteration #%d",
          expected, actual, (int)i);
      abort();
    }
  }

  /* All servers are available, therefore all client subchannels are READY, even
   * when we only need one for the client channel state to be READY */
  for (size_t i = 0; i < sequences->n; i++) {
    const grpc_connectivity_state actual = sequences->connectivity_states[i];
    const grpc_connectivity_state expected = GRPC_CHANNEL_READY;
    if (actual != expected) {
      gpr_log(GPR_ERROR,
              "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
              "at iteration #%d",
              grpc_connectivity_state_name(expected),
              grpc_connectivity_state_name(actual), (int)i);
      abort();
    }
  }

  gpr_free(expected_connection_sequence);
}
示例#10
0
grpc_connectivity_state grpc_connectivity_state_check(
    grpc_connectivity_state_tracker *tracker, grpc_error **error) {
  if (grpc_connectivity_state_trace) {
    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
            grpc_connectivity_state_name(tracker->current_state));
  }
  if (error != NULL) {
    *error = GRPC_ERROR_REF(tracker->current_error);
  }
  return tracker->current_state;
}
示例#11
0
int grpc_connectivity_state_notify_on_state_change(
    grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current,
    grpc_iomgr_closure *notify) {
    if (grpc_connectivity_state_trace) {
        gpr_log(GPR_DEBUG, "CONWATCH: %s: from %s [cur=%s]", tracker->name,
                grpc_connectivity_state_name(*current),
                grpc_connectivity_state_name(tracker->current_state));
    }
    if (tracker->current_state != *current) {
        *current = tracker->current_state;
        grpc_iomgr_add_callback(notify);
    } else {
        grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
        w->current = current;
        w->notify = notify;
        w->next = tracker->watchers;
        tracker->watchers = w;
    }
    return tracker->current_state == GRPC_CHANNEL_IDLE;
}
示例#12
0
grpc_connectivity_state grpc_connectivity_state_check(
    grpc_connectivity_state_tracker *tracker) {
  grpc_connectivity_state cur =
      (grpc_connectivity_state)gpr_atm_no_barrier_load(
          &tracker->current_state_atm);
  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
            grpc_connectivity_state_name(cur));
  }
  return cur;
}
示例#13
0
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
                                 grpc_connectivity_state_tracker *tracker,
                                 grpc_connectivity_state state,
                                 const char *reason) {
  grpc_connectivity_state_watcher *w;
  if (grpc_connectivity_state_trace) {
    gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
            grpc_connectivity_state_name(tracker->current_state),
            grpc_connectivity_state_name(state), reason);
  }
  if (tracker->current_state == state) {
    return;
  }
  GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE);
  tracker->current_state = state;
  while ((w = tracker->watchers) != NULL) {
    *w->current = tracker->current_state;
    tracker->watchers = w->next;
    grpc_exec_ctx_enqueue(exec_ctx, w->notify, 1);
    gpr_free(w);
  }
}
示例#14
0
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
                                 grpc_connectivity_state_tracker *tracker,
                                 grpc_connectivity_state state,
                                 grpc_error *error, const char *reason) {
  grpc_connectivity_state_watcher *w;
  if (grpc_connectivity_state_trace) {
    const char *error_string = grpc_error_string(error);
    gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker,
            tracker->name, grpc_connectivity_state_name(tracker->current_state),
            grpc_connectivity_state_name(state), reason, error, error_string);
    grpc_error_free_string(error_string);
  }
  switch (state) {
    case GRPC_CHANNEL_CONNECTING:
    case GRPC_CHANNEL_IDLE:
    case GRPC_CHANNEL_READY:
      GPR_ASSERT(error == GRPC_ERROR_NONE);
      break;
    case GRPC_CHANNEL_SHUTDOWN:
    case GRPC_CHANNEL_TRANSIENT_FAILURE:
      GPR_ASSERT(error != GRPC_ERROR_NONE);
      break;
  }
  GRPC_ERROR_UNREF(tracker->current_error);
  tracker->current_error = error;
  if (tracker->current_state == state) {
    return;
  }
  GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_SHUTDOWN);
  tracker->current_state = state;
  while ((w = tracker->watchers) != NULL) {
    *w->current = tracker->current_state;
    tracker->watchers = w->next;
    grpc_exec_ctx_sched(exec_ctx, w->notify,
                        GRPC_ERROR_REF(tracker->current_error), NULL);
    gpr_free(w);
  }
}
示例#15
0
grpc_connectivity_state grpc_connectivity_state_get(
    grpc_connectivity_state_tracker *tracker, grpc_error **error) {
  grpc_connectivity_state cur =
      (grpc_connectivity_state)gpr_atm_no_barrier_load(
          &tracker->current_state_atm);
  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
            grpc_connectivity_state_name(cur));
  }
  if (error != NULL) {
    *error = GRPC_ERROR_REF(tracker->current_error);
  }
  return cur;
}
示例#16
0
char *grpc_transport_op_string(grpc_transport_op *op) {
  char *tmp;
  char *out;
  bool first = true;

  gpr_strvec b;
  gpr_strvec_init(&b);

  if (op->on_connectivity_state_change != NULL) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    if (op->connectivity_state != NULL) {
      gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:from=%s",
                   op->on_connectivity_state_change,
                   grpc_connectivity_state_name(*op->connectivity_state));
      gpr_strvec_add(&b, tmp);
    } else {
      gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:unsubscribe",
                   op->on_connectivity_state_change);
      gpr_strvec_add(&b, tmp);
    }
  }

  if (op->disconnect_with_error != GRPC_ERROR_NONE) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    const char *err = grpc_error_string(op->disconnect_with_error);
    gpr_asprintf(&tmp, "DISCONNECT:%s", err);
    gpr_strvec_add(&b, tmp);
    grpc_error_free_string(err);
  }

  if (op->send_goaway) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    char *msg = op->goaway_message == NULL
                    ? "null"
                    : grpc_dump_slice(*op->goaway_message,
                                      GPR_DUMP_ASCII | GPR_DUMP_HEX);
    gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg);
    if (op->goaway_message != NULL) gpr_free(msg);
    gpr_strvec_add(&b, tmp);
  }

  if (op->set_accept_stream) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    gpr_asprintf(&tmp, "SET_ACCEPT_STREAM:%p(%p,...)", op->set_accept_stream_fn,
                 op->set_accept_stream_user_data);
    gpr_strvec_add(&b, tmp);
  }

  if (op->bind_pollset != NULL) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET"));
  }

  if (op->bind_pollset_set != NULL) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET_SET"));
  }

  if (op->send_ping != NULL) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = false;
    gpr_strvec_add(&b, gpr_strdup("SEND_PING"));
  }

  out = gpr_strvec_flatten(&b, NULL);
  gpr_strvec_destroy(&b);

  return out;
}
示例#17
0
static void verify_rebirth_round_robin(const servers_fixture *f,
                                       grpc_channel *client,
                                       const request_sequences *sequences,
                                       const size_t num_iters) {
  dump_array("actual_connection_sequence", sequences->connections, num_iters);

  /* first iteration succeeds */
  GPR_ASSERT(sequences->connections[0] != -1);
  /* then we fail for a while... */
  GPR_ASSERT(sequences->connections[1] == -1);
  /* ... but should be up eventually */
  size_t first_iter_back_up = ~0ul;
  for (size_t i = 2; i < sequences->n; ++i) {
    if (sequences->connections[i] != -1) {
      first_iter_back_up = i;
      break;
    }
  }
  GPR_ASSERT(first_iter_back_up != ~0ul);

  /* We can assert that the first client channel state should be READY, when all
   * servers were available; same thing for the last one. In the middle
   * somewhere there must exist at least one TRANSIENT_FAILURE */
  grpc_connectivity_state actual = sequences->connectivity_states[0];
  grpc_connectivity_state expected = GRPC_CHANNEL_READY;
  if (actual != expected) {
    gpr_log(GPR_ERROR,
            "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
            "at iteration #%d",
            grpc_connectivity_state_name(expected),
            grpc_connectivity_state_name(actual), 0);
    abort();
  }

  actual = sequences->connectivity_states[num_iters - 1];
  expected = GRPC_CHANNEL_READY;
  if (actual != expected) {
    gpr_log(GPR_ERROR,
            "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
            "at iteration #%d",
            grpc_connectivity_state_name(expected),
            grpc_connectivity_state_name(actual), (int)num_iters - 1);
    abort();
  }

  bool found_failure_status = false;
  for (size_t i = 1; i < sequences->n - 1; i++) {
    if (sequences->connectivity_states[i] == GRPC_CHANNEL_TRANSIENT_FAILURE) {
      found_failure_status = true;
      break;
    }
  }
  if (!found_failure_status) {
    gpr_log(
        GPR_ERROR,
        "CONNECTIVITY STATUS SEQUENCE FAILURE: "
        "GRPC_CHANNEL_TRANSIENT_FAILURE status not found. Got the following "
        "instead:");
    for (size_t i = 0; i < num_iters; i++) {
      gpr_log(GPR_ERROR, "[%d]: %s", (int)i,
              grpc_connectivity_state_name(sequences->connectivity_states[i]));
    }
  }
}