void test_nghttp2_session_create_idle_stream(void) {
  nghttp2_session *session;
  nghttp2_session_callbacks callbacks;
  nghttp2_stream *stream2, *stream4, *stream8, *stream10;
  nghttp2_priority_spec pri_spec;
  int rv;
  int i;

  memset(&callbacks, 0, sizeof(callbacks));
  callbacks.send_callback = null_send_callback;

  nghttp2_session_server_new(&session, &callbacks, NULL);

  stream2 = open_sent_stream(session, 2);

  nghttp2_priority_spec_init(&pri_spec, 2, 111, 1);

  rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);

  CU_ASSERT(0 == rv);

  stream4 = nghttp2_session_get_stream_raw(session, 4);

  CU_ASSERT(4 == stream4->stream_id);
  CU_ASSERT(111 == stream4->weight);
  CU_ASSERT(stream2 == stream4->dep_prev);
  CU_ASSERT(stream4 == stream2->dep_next);

  /* If pri_spec->stream_id does not exist, and it is idle stream, it
     is created too */
  nghttp2_priority_spec_init(&pri_spec, 10, 109, 0);

  rv = nghttp2_session_create_idle_stream(session, 8, &pri_spec);

  CU_ASSERT(0 == rv);

  stream8 = nghttp2_session_get_stream_raw(session, 8);
  stream10 = nghttp2_session_get_stream_raw(session, 10);

  CU_ASSERT(8 == stream8->stream_id);
  CU_ASSERT(109 == stream8->weight);
  CU_ASSERT(10 == stream10->stream_id);
  CU_ASSERT(16 == stream10->weight);
  CU_ASSERT(stream10 == stream8->dep_prev);
  CU_ASSERT(&session->root == stream10->dep_prev);

  /* It is an error to attempt to create already existing idle
     stream */
  rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);

  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

  /* It is an error to depend on itself */
  pri_spec.stream_id = 6;

  rv = nghttp2_session_create_idle_stream(session, 6, &pri_spec);
  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

  /* It is an error to create root stream (0) as idle stream */
  rv = nghttp2_session_create_idle_stream(session, 0, &pri_spec);
  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

  /* It is an error to create non-idle stream */
  session->last_sent_stream_id = 20;
  pri_spec.stream_id = 2;

  rv = nghttp2_session_create_idle_stream(session, 18, &pri_spec);

  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

  nghttp2_session_del(session);

  /* Check that this works in client session too */
  nghttp2_session_client_new(&session, &callbacks, NULL);

  nghttp2_priority_spec_init(&pri_spec, 4, 99, 1);

  rv = nghttp2_session_create_idle_stream(session, 2, &pri_spec);

  CU_ASSERT(0 == rv);

  stream4 = nghttp2_session_get_stream_raw(session, 4);
  stream2 = nghttp2_session_get_stream_raw(session, 2);

  CU_ASSERT(NULL != stream4);
  CU_ASSERT(NULL != stream2);
  CU_ASSERT(&session->root == stream4->dep_prev);
  CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream4->weight);
  CU_ASSERT(stream4 == stream2->dep_prev);
  CU_ASSERT(99 == stream2->weight);

  nghttp2_session_del(session);

  /* Check that idle stream is reduced when nghttp2_session_send() is
     called. */
  nghttp2_session_server_new(&session, &callbacks, NULL);

  session->local_settings.max_concurrent_streams = 30;

  nghttp2_priority_spec_init(&pri_spec, 0, 16, 0);
  for (i = 0; i < 100; ++i) {
    rv = nghttp2_session_create_idle_stream(session, i * 2 + 1, &pri_spec);

    CU_ASSERT(0 == rv);

    nghttp2_priority_spec_init(&pri_spec, i * 2 + 1, 16, 0);
  }

  CU_ASSERT(100 == session->num_idle_streams);
  CU_ASSERT(0 == nghttp2_session_send(session));
  CU_ASSERT(30 == session->num_idle_streams);
  CU_ASSERT(141 == session->idle_stream_head->stream_id);

  nghttp2_session_del(session);

  /* Check that idle stream is reduced when nghttp2_session_mem_recv() is
     called. */
  nghttp2_session_client_new(&session, &callbacks, NULL);

  session->local_settings.max_concurrent_streams = 30;

  nghttp2_priority_spec_init(&pri_spec, 0, 16, 0);
  for (i = 0; i < 100; ++i) {
    rv = nghttp2_session_create_idle_stream(session, i * 2 + 1, &pri_spec);

    CU_ASSERT(0 == rv);

    nghttp2_priority_spec_init(&pri_spec, i * 2 + 1, 16, 0);
  }

  CU_ASSERT(100 == session->num_idle_streams);
  CU_ASSERT(0 == nghttp2_session_mem_recv(session, NULL, 0));
  CU_ASSERT(30 == session->num_idle_streams);
  CU_ASSERT(141 == session->idle_stream_head->stream_id);

  nghttp2_session_del(session);
}
void test_nghttp2_session_create_idle_stream(void) {
  nghttp2_session *session;
  nghttp2_session_callbacks callbacks;
  nghttp2_stream *stream2, *stream4, *stream8, *stream10;
  nghttp2_priority_spec pri_spec;
  int rv;
  int i;

  memset(&callbacks, 0, sizeof(callbacks));
  callbacks.send_callback = null_send_callback;

  nghttp2_session_server_new(&session, &callbacks, NULL);

  stream2 = open_sent_stream(session, 2);

  nghttp2_priority_spec_init(&pri_spec, 2, 111, 1);

  rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);

  CU_ASSERT(0 == rv);

  stream4 = nghttp2_session_get_stream_raw(session, 4);

  CU_ASSERT(4 == stream4->stream_id);
  CU_ASSERT(111 == stream4->weight);
  CU_ASSERT(stream2 == stream4->dep_prev);
  CU_ASSERT(stream4 == stream2->dep_next);

   
  nghttp2_priority_spec_init(&pri_spec, 10, 109, 0);

  rv = nghttp2_session_create_idle_stream(session, 8, &pri_spec);

  CU_ASSERT(0 == rv);

  stream8 = nghttp2_session_get_stream_raw(session, 8);
  stream10 = nghttp2_session_get_stream_raw(session, 10);

  CU_ASSERT(8 == stream8->stream_id);
  CU_ASSERT(109 == stream8->weight);
  CU_ASSERT(10 == stream10->stream_id);
  CU_ASSERT(16 == stream10->weight);
  CU_ASSERT(stream10 == stream8->dep_prev);
  CU_ASSERT(&session->root == stream10->dep_prev);

   
  rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);

  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

   
  pri_spec.stream_id = 6;

  rv = nghttp2_session_create_idle_stream(session, 6, &pri_spec);
  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

   
  rv = nghttp2_session_create_idle_stream(session, 0, &pri_spec);
  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

   
  session->last_sent_stream_id = 20;
  pri_spec.stream_id = 2;

  rv = nghttp2_session_create_idle_stream(session, 18, &pri_spec);

  CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);

  nghttp2_session_del(session);

   
  nghttp2_session_client_new(&session, &callbacks, NULL);

  nghttp2_priority_spec_init(&pri_spec, 4, 99, 1);

  rv = nghttp2_session_create_idle_stream(session, 2, &pri_spec);

  CU_ASSERT(0 == rv);

  stream4 = nghttp2_session_get_stream_raw(session, 4);
  stream2 = nghttp2_session_get_stream_raw(session, 2);

  CU_ASSERT(NULL != stream4);
  CU_ASSERT(NULL != stream2);
  CU_ASSERT(&session->root == stream4->dep_prev);
  CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream4->weight);
  CU_ASSERT(stream4 == stream2->dep_prev);
  CU_ASSERT(99 == stream2->weight);

  nghttp2_session_del(session);

   
  nghttp2_session_server_new(&session, &callbacks, NULL);

  session->local_settings.max_concurrent_streams = 30;

  nghttp2_priority_spec_init(&pri_spec, 0, 16, 0);
  for (i = 0; i < 100; ++i) {
    rv = nghttp2_session_create_idle_stream(session, i * 2 + 1, &pri_spec);

    CU_ASSERT(0 == rv);

    nghttp2_priority_spec_init(&pri_spec, i * 2 + 1, 16, 0);
  }

  CU_ASSERT(100 == session->num_idle_streams);
  CU_ASSERT(0 == nghttp2_session_send(session));
  CU_ASSERT(30 == session->num_idle_streams);
  CU_ASSERT(141 == session->idle_stream_head->stream_id);

  nghttp2_session_del(session);

   
  nghttp2_session_client_new(&session, &callbacks, NULL);

  session->local_settings.max_concurrent_streams = 30;

  nghttp2_priority_spec_init(&pri_spec, 0, 16, 0);
  for (i = 0; i < 100; ++i) {
    rv = nghttp2_session_create_idle_stream(session, i * 2 + 1, &pri_spec);

    CU_ASSERT(0 == rv);

    nghttp2_priority_spec_init(&pri_spec, i * 2 + 1, 16, 0);
  }

  CU_ASSERT(100 == session->num_idle_streams);
  CU_ASSERT(0 == nghttp2_session_mem_recv(session, NULL, 0));
  CU_ASSERT(30 == session->num_idle_streams);
  CU_ASSERT(141 == session->idle_stream_head->stream_id);

  nghttp2_session_del(session);
}