def test_https_h2_sni(https_test_server_fixture):
  """Tests that SNI indication works on https/h1."""
  # Verify success when we set the right host
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100",
      "--termination-predicate", "benchmark.http_2xx:2", "--request-header", ":authority: sni.com",
      "--h2"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "benchmark.http_2xx", 1)
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http2_total", 1)
  asserts.assertCounterEqual(counters, "ssl.handshake", 1)

  # Verify success when we set the right host
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100",
      "--termination-predicate", "benchmark.http_2xx:2", "--request-header", "host: sni.com", "--h2"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "benchmark.http_2xx", 1)
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http2_total", 1)
  asserts.assertCounterEqual(counters, "ssl.handshake", 1)

  # Verify failure when we set no host (will get plain http)
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100", "--h2"
  ],
                                                                expect_failure=True)

  # Verify failure when we provide both host and :authority: (will get plain http)
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100", "--h2",
      "--request-header", "host: sni.com", "--request-header", ":authority: sni.com"
  ],
                                                                expect_failure=True)
def test_https_h1_sni(https_test_server_fixture):
  """Test that SNI indication works on https/h1."""
  # Verify success when we set the right host
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100",
      "--termination-predicate", "benchmark.http_2xx:2", "--request-header", "host: sni.com"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "benchmark.http_2xx", 1)
  # It is possible that the # of upstream_cx > # of backend connections for H1
  # as new connections will spawn if the existing clients cannot keep up with the RPS.
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http1_total", 1)
  asserts.assertCounterGreaterEqual(counters, "ssl.handshake", 1)

  # Verify failure when we set no host (will get plain http)
  parsed_json, _ = https_test_server_fixture.runNighthawkClient(
      [https_test_server_fixture.getTestServerRootUri(), "--rps", "20", "--duration", "100"],
      expect_failure=True)

  # Verify success when we use plain http and don't request the sni host
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri().replace("https://", "http://"), "--rps",
      "100", "--duration", "20", "--termination-predicate", "benchmark.http_2xx:2"
  ],
                                                                expect_failure=False)

  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "benchmark.http_2xx", 1)
  # It is possible that the # of upstream_cx > # of backend connections for H1
  # as new connections will spawn if the existing clients cannot keep up with the RPS.
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http1_total", 1)
  asserts.assertNotIn("ssl.handshake", counters)
def _do_tls_configuration_test(https_test_server_fixture, cli_parameter,
                               use_h2):
    """Runs tests for different ciphers.

  For a given choice of (--tls-context, --transport-socket) x (H1, H2),
  run a series of traffic tests with different ciphers.

  Args:
    https_test_server_fixture: pytest.fixture that controls a test server and client
    cli_parameter: string, --tls-context or --transport-socket
    use_h2: boolean, whether to pass --h2
  """

    if cli_parameter == "--tls-context":
        json_template = "{common_tls_context:{tls_params:{cipher_suites:[\"-ALL:%s\"]}}}"
    else:
        json_template = (
            "{name:\"envoy.transport_sockets.tls\",typed_config:{" +
            "\"@type\":\"type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext\","
            +
            "common_tls_context:{tls_params:{cipher_suites:[\"-ALL:%s\"]}}}}")

    for cipher in [
            "ECDHE-RSA-AES128-SHA",
            "ECDHE-RSA-CHACHA20-POLY1305",
    ]:
        parsed_json, _ = https_test_server_fixture.runNighthawkClient(
            (["--h2"] if use_h2 else []) + [
                "--termination-predicate", "benchmark.http_2xx:0",
                cli_parameter, json_template % cipher,
                https_test_server_fixture.getTestServerRootUri()
            ])
        counters = https_test_server_fixture.getNighthawkCounterMapFromJson(
            parsed_json)
        assertCounterEqual(counters, "ssl.ciphers.%s" % cipher, 1)
def test_https_h2(https_test_server_fixture):
    """
  Runs the CLI configured to use HTTP/2 (using https) against our test server, and sanity
  checks statistics from both client and server.
  """
    parsed_json, _ = https_test_server_fixture.runNighthawkClient([
        "--h2",
        https_test_server_fixture.getTestServerRootUri(), "--rps", "100",
        "--duration", "100", "--termination-predicate",
        "benchmark.http_2xx:24", "--max-active-requests", "1"
    ])
    counters = https_test_server_fixture.getNighthawkCounterMapFromJson(
        parsed_json)
    assertCounterEqual(counters, "benchmark.http_2xx", 25)
    assertCounterEqual(counters, "upstream_cx_http2_total", 1)
    # Through emperical observation, 1030 has been determined to be the minimum of bytes
    # we can expect to have received when execution has stopped.
    assertCounterGreaterEqual(counters, "upstream_cx_rx_bytes_total", 1030)
    assertCounterEqual(counters, "upstream_cx_total", 1)
    assertCounterGreaterEqual(counters, "upstream_cx_tx_bytes_total", 403)
    assertCounterEqual(counters, "upstream_rq_pending_total", 1)
    assertCounterEqual(counters, "upstream_rq_total", 25)
    assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-AES128-GCM-SHA256", 1)
    assertCounterEqual(counters, "ssl.curves.X25519", 1)
    assertCounterEqual(counters, "ssl.handshake", 1)
    assertCounterEqual(counters, "ssl.sigalgs.rsa_pss_rsae_sha256", 1)
    assertCounterEqual(counters, "ssl.versions.TLSv1.2", 1)
    assertCounterEqual(counters, "default.total_match_count", 1)
    assertEqual(len(counters), 17)
def test_https_h1(https_test_server_fixture):
    """
  Runs the CLI configured to use HTTP/1 over https against our test server, and sanity
  checks statistics from both client and server.
  """
    parsed_json, _ = https_test_server_fixture.runNighthawkClient([
        https_test_server_fixture.getTestServerRootUri(), "--connections", "1",
        "--rps", "100", "--duration", "100", "--termination-predicate",
        "benchmark.http_2xx:24"
    ])
    counters = https_test_server_fixture.getNighthawkCounterMapFromJson(
        parsed_json)
    assertCounterEqual(counters, "benchmark.http_2xx", 25)
    assertCounterEqual(counters, "upstream_cx_http1_total", 1)
    assertCounterEqual(counters, "upstream_cx_rx_bytes_total", 3400)
    assertCounterEqual(counters, "upstream_cx_total", 1)
    assertCounterEqual(
        counters, "upstream_cx_tx_bytes_total", 1400
        if https_test_server_fixture.ip_version == IpVersion.IPV6 else 1500)
    assertCounterEqual(counters, "upstream_rq_pending_total", 1)
    assertCounterEqual(counters, "upstream_rq_total", 25)
    assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-AES128-GCM-SHA256", 1)
    assertCounterEqual(counters, "ssl.curves.X25519", 1)
    assertCounterEqual(counters, "ssl.handshake", 1)
    assertCounterEqual(counters, "ssl.sigalgs.rsa_pss_rsae_sha256", 1)
    assertCounterEqual(counters, "ssl.versions.TLSv1.2", 1)
    assertCounterEqual(counters, "default.total_match_count", 1)
    assertEqual(len(counters), 17)

    server_stats = https_test_server_fixture.getTestServerStatisticsJson()
    assertEqual(
        https_test_server_fixture.getServerStatFromJson(
            server_stats, "http.ingress_http.downstream_rq_2xx"), 25)
def test_https_h1(https_test_server_fixture):
  """Test h1 over https.

  Runs the CLI configured to use HTTP/1 over https against our test server, and sanity
  checks statistics from both client and server.
  """
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--connections", "1", "--rps", "100",
      "--duration", "100", "--termination-predicate", "benchmark.http_2xx:24"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterEqual(counters, "benchmark.http_2xx", 25)
  asserts.assertCounterEqual(counters, "upstream_cx_rx_bytes_total", 3400)
  # It is possible that the # of upstream_cx > # of backend connections for H1 as new connections
  # will spawn if the existing clients cannot keep up with the RPS.
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http1_total", 1)
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_total", 1)
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_tx_bytes_total", 500)
  asserts.assertCounterGreaterEqual(counters, "upstream_rq_pending_total", 1)
  asserts.assertCounterEqual(counters, "upstream_rq_total", 25)
  asserts.assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-AES128-GCM-SHA256", 1)
  asserts.assertCounterEqual(counters, "ssl.curves.X25519", 1)
  asserts.assertCounterEqual(counters, "ssl.handshake", 1)
  asserts.assertCounterEqual(counters, "ssl.sigalgs.rsa_pss_rsae_sha256", 1)
  asserts.assertCounterEqual(counters, "ssl.versions.TLSv1.2", 1)
  asserts.assertCounterEqual(counters, "default.total_match_count", 1)
  asserts.assertEqual(len(counters), 17)

  server_stats = https_test_server_fixture.getTestServerStatisticsJson()
  asserts.assertEqual(
      https_test_server_fixture.getServerStatFromJson(server_stats,
                                                      "http.ingress_http.downstream_rq_2xx"), 25)
def _do_tls_configuration_test(https_test_server_fixture, cli_parameter,
                               use_h2, ciphers):
    """Test with different ciphers.

  For a given choice of (--tls-context, --transport-socket) x (H1, H2),
  run a series of traffic tests with different ciphers.

  Args:
    https_test_server_fixture: pytest.fixture that controls a test server and client
    cli_parameter: string, --tls-context or --transport-socket
    use_h2: boolean, whether to pass --h2
    ciphers: list[string], list of ciphers to use with TLS
  """
    if cli_parameter == "--tls-context":
        json_template = "{common_tls_context:{tls_params:{cipher_suites:[\"-ALL:%s\"]}}}"
    else:
        json_template = "%s%s%s" % (
            "{name:\"envoy.transport_sockets.tls\",typed_config:{",
            "\"@type\":\"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext\",",
            "common_tls_context:{tls_params:{cipher_suites:[\"-ALL:%s\"]}}}}")

    for cipher in ciphers:
        parsed_json, _ = https_test_server_fixture.runNighthawkClient(
            (["--protocol", "http2"] if use_h2 else []) + [
                "--duration", "10", "--termination-predicate",
                "benchmark.http_2xx:0", cli_parameter, json_template % cipher,
                https_test_server_fixture.getTestServerRootUri()
            ])
        counters = https_test_server_fixture.getNighthawkCounterMapFromJson(
            parsed_json)
        asserts.assertCounterGreaterEqual(counters, "ssl.ciphers.%s" % cipher,
                                          1)
def test_https_log_verbosity(https_test_server_fixture):
  """Test that the specified log verbosity level is respected.

  This tests for a sentinel we know is only right when the level
  is set to 'trace'.
  """
  # TODO(oschaaf): this is kind of fragile. Can we improve?
  trace_level_sentinel = "nighthawk_service_zone"
  _, logs = https_test_server_fixture.runNighthawkClient(
      ["--duration 1", "--rps 1", "-v debug",
       https_test_server_fixture.getTestServerRootUri()])
  asserts.assertNotIn(trace_level_sentinel, logs)

  _, logs = https_test_server_fixture.runNighthawkClient(
      ["--duration 1", "--rps 1", "-v trace",
       https_test_server_fixture.getTestServerRootUri()])
  asserts.assertIn(trace_level_sentinel, logs)
示例#9
0
def test_https_h2_tls_context_configuration(https_test_server_fixture):
  """
  Verifies specifying tls cipher suites works with the h2 pool
  """
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      "--duration 1",
      "--tls-context {common_tls_context:{tls_params:{cipher_suites:[\"-ALL:ECDHE-RSA-AES128-SHA\"]}}}",
      https_test_server_fixture.getTestServerRootUri()
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-AES128-SHA", 1)

  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      "--h2", "--duration 1",
      "--tls-context {common_tls_context:{tls_params:{cipher_suites:[\"-ALL:ECDHE-RSA-CHACHA20-POLY1305\"]}}}",
      https_test_server_fixture.getTestServerRootUri()
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-CHACHA20-POLY1305", 1)
示例#10
0
def test_https_prefetching(https_test_server_fixture):
  """
  Test we prefetch connections. We test for 1 second at 1 rps, which should
  result in 1 connection max without prefetching. However, we specify 50 connections
  and the prefetching flag, so we ought to see 50 http1 connections created.
  """
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      "--duration 1", "--rps 1", "--prefetch-connections", "--connections 50",
      https_test_server_fixture.getTestServerRootUri()
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  assertCounterEqual(counters, "upstream_cx_http1_total", 50)
示例#11
0
def test_https_h2_multiple_connections(https_test_server_fixture):
    """
  Test that the experimental h2 pool uses multiple connections.
  """
    parsed_json, _ = https_test_server_fixture.runNighthawkClient([
        "--h2",
        https_test_server_fixture.getTestServerRootUri(), "--rps", "100",
        "--duration", "100", "--termination-predicate", "benchmark.http_2xx:9",
        "--max-active-requests", "1",
        "--experimental-h2-use-multiple-connections"
    ])
    counters = https_test_server_fixture.getNighthawkCounterMapFromJson(
        parsed_json)
    assertCounterEqual(counters, "benchmark.http_2xx", 10)
    assertCounterEqual(counters, "upstream_cx_http2_total", 10)
def test_drain(https_test_server_fixture):
  """Test that the pool drain timeout is effective, and we terminate in a timely fashion.

  Sets up the test server to delay replies 100 seconds. Our execution will only last 30 seconds, so we
  expect to observe no replies. Termination should be cut short by the drain timeout, which means
  that we should have results in approximately execution duration + drain timeout = 35 seconds.
  (the pool drain timeout is hard coded to 5 seconds as of writing this).
  If drain timeout is reached, a message will be logged to the user.
  """
  parsed_json, logs = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "20",
      "--request-header", "x-nighthawk-test-server-config: {static_delay: \"100s\"}"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http1_total", 1)
  asserts.assertNotIn("benchmark.http_2xx", counters)
  asserts.assertIn("Wait for the connection pool drain timed out, proceeding to hard shutdown",
                   logs)
def test_https_h2_multiple_connections(https_test_server_fixture):
  """Test that the experimental h2 pool uses multiple connections.

  The burst we send ensures we will need 10 connections right away, as we
  limit max active streams per connection to 1 by setting the experimental
  flag to use multiple h2 connections.
  """
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      "--h2",
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "100",
      "--termination-predicate", "benchmark.http_2xx:99", "--max-active-requests", "10",
      "--max-pending-requests", "10", "--max-concurrent-streams", "1", "--burst-size", "10"
  ])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  asserts.assertCounterGreaterEqual(counters, "benchmark.http_2xx", 100)
  # Empirical observation shows we may end up creating more then 10 connections.
  # This is stock Envoy h/2 pool behavior.
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http2_total", 10)
示例#14
0
def test_drain(https_test_server_fixture):
  """Test that the pool drain timeout is effective, and we terminate in a timely fashion.

  Sets up the test server to delay replies 100 seconds. Our execution will only last 3 seconds, so we
  expect to observe no replies. Termination should be cut short by the drain timeout, which means
  that we should have results in approximately execution duration + drain timeout = 8 seconds.
  (the pool drain timeout is hard coded to 5 seconds as of writing this).
  """
  t0 = time.time()
  parsed_json, _ = https_test_server_fixture.runNighthawkClient([
      https_test_server_fixture.getTestServerRootUri(), "--rps", "100", "--duration", "3",
      "--request-header", "x-nighthawk-test-server-config: {static_delay: \"100s\"}"
  ])
  t1 = time.time()
  time_delta = t1 - t0
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  assert time_delta < 40  # *lots* of slack to avoid failure in slow CI executions.
  asserts.assertCounterGreaterEqual(counters, "upstream_cx_http1_total", 1)
  asserts.assertNotIn("benchmark.http_2xx", counters)
示例#15
0
def test_https_h2(https_test_server_fixture):
  """
  Runs the CLI configured to use HTTP/2 (using https) against our test server, and sanity
  checks statistics from both client and server.
  """

  parsed_json, _ = https_test_server_fixture.runNighthawkClient(
      ["--h2", https_test_server_fixture.getTestServerRootUri()])
  counters = https_test_server_fixture.getNighthawkCounterMapFromJson(parsed_json)
  assertCounterEqual(counters, "benchmark.http_2xx", 25)
  assertCounterEqual(counters, "upstream_cx_http2_total", 1)
  assertCounterGreaterEqual(counters, "upstream_cx_rx_bytes_total", 1145)
  assertCounterEqual(counters, "upstream_cx_total", 1)
  assertCounterGreaterEqual(counters, "upstream_cx_tx_bytes_total", 403)
  assertCounterEqual(counters, "upstream_rq_pending_total", 1)
  assertCounterEqual(counters, "upstream_rq_total", 25)
  assertCounterEqual(counters, "ssl.ciphers.ECDHE-RSA-AES128-GCM-SHA256", 1)
  assertCounterEqual(counters, "ssl.curves.X25519", 1)
  assertCounterEqual(counters, "ssl.handshake", 1)
  assertCounterEqual(counters, "ssl.sigalgs.rsa_pss_rsae_sha256", 1)
  assertCounterEqual(counters, "ssl.versions.TLSv1.2", 1)
  assertCounterEqual(counters, "default.total_match_count", 1)
  assertEqual(len(counters), 17)