private void validateRequest(NettyRequest nettyRequest, RestMethod restMethod, String uri, HttpHeaders headers,
      Map<String, List<String>> params, Set<Cookie> httpCookies, MockChannel channel) {
    long contentLength =
        headers.contains(HttpHeaderNames.CONTENT_LENGTH) ? Long.parseLong(headers.get(HttpHeaderNames.CONTENT_LENGTH))
            : 0;
    assertTrue("Request channel is not open", nettyRequest.isOpen());
    assertEquals("Mismatch in content length", contentLength, nettyRequest.getSize());
    assertEquals("Mismatch in rest method", restMethod, nettyRequest.getRestMethod());
    assertEquals("Mismatch in path", uri.substring(0, uri.indexOf("?")), nettyRequest.getPath());
    assertEquals("Mismatch in uri", uri, nettyRequest.getUri());
    assertNotNull("There should have been a RestRequestMetricsTracker", nettyRequest.getMetricsTracker());
    assertFalse("Should not have been a multipart request", nettyRequest.isMultipart());
    RestRequest.RestRequestContext context = nettyRequest.getRestRequestContext();
    assertNotNull("Should have RestRequestContext", context);
    assertTrue(context instanceof NettyRequest.NettyRequestContext);
    assertSame(((NettyRequest.NettyRequestContext) context).getChannel(), channel);
    SSLSession sslSession = nettyRequest.getSSLSession();
    if (channel.pipeline().get(SslHandler.class) == null) {
      assertNull("Non-null SSLSession when pipeline does not contain an SslHandler", sslSession);
    } else {
      assertEquals("SSLSession does not match one from MockChannel", channel.getSSLEngine().getSession(), sslSession);
    }

    Set<javax.servlet.http.Cookie> actualCookies =
        (Set<javax.servlet.http.Cookie>) nettyRequest.getArgs().get(RestUtils.Headers.COOKIE);
    compareCookies(httpCookies, actualCookies);

    Map<String, List<String>> receivedArgs = new HashMap<String, List<String>>();
    for (Map.Entry<String, Object> e : nettyRequest.getArgs().entrySet()) {
      if (!e.getKey().equalsIgnoreCase(HttpHeaderNames.COOKIE.toString())) {
        if (!receivedArgs.containsKey(e.getKey())) {
          receivedArgs.put(e.getKey(), new LinkedList<String>());
        }

        if (e.getValue() != null) {
          List<String> values =
              Arrays.asList(e.getValue().toString().split(NettyRequest.MULTIPLE_HEADER_VALUE_DELIMITER));
          receivedArgs.get(e.getKey()).addAll(values);
        }
      }
    }
    Map<String, Integer> keyValueCount = new HashMap<String, Integer>();
    for (Map.Entry<String, List<String>> param : params.entrySet()) {
      boolean containsKey = receivedArgs.containsKey(param.getKey());
      if (DENY_LISTED_QUERY_PARAM_SET.contains(param.getKey())) {
        assertFalse("Should not contain deny listed key: " + param.getKey(), containsKey);
      } else {
        assertTrue("Did not find key: " + param.getKey(), containsKey);
        if (!keyValueCount.containsKey(param.getKey())) {
          keyValueCount.put(param.getKey(), 0);
        }

        if (param.getValue() != null) {
          boolean containsAllValues = receivedArgs.get(param.getKey()).containsAll(param.getValue());
          assertTrue("Did not find all values expected for key: " + param.getKey(), containsAllValues);
          keyValueCount.put(param.getKey(), keyValueCount.get(param.getKey()) + param.getValue().size());
        }
      }
    }

    for (Map.Entry<String, String> e : headers) {
      if (!e.getKey().equalsIgnoreCase(HttpHeaderNames.COOKIE.toString())) {
        // Make sure we have this key in receivedArgs
        assertTrue("Did not find key: " + e.getKey(), receivedArgs.containsKey(e.getKey()));
        // Now make sure we can find a case-insensitive key in the request
        String lowerKey = e.getKey().toLowerCase();
        assertTrue("Case insensitive key should exist for lower key" + e.getKey(),
            nettyRequest.getArgs().containsKey(lowerKey));
        String upperKey = e.getKey().toUpperCase();
        assertTrue("Case insensitive key should exist for upper key" + e.getKey(),
            nettyRequest.getArgs().containsKey(upperKey));
        if (!keyValueCount.containsKey(e.getKey())) {
          keyValueCount.put(e.getKey(), 0);
        }
        if (headers.get(e.getKey()) != null) {
          assertTrue("Did not find value '" + e.getValue() + "' expected for key: '" + e.getKey() + "'",
              receivedArgs.get(e.getKey()).contains(e.getValue()));
          keyValueCount.put(e.getKey(), keyValueCount.get(e.getKey()) + 1);
        }
      }
    }

    assertEquals("Number of args does not match", keyValueCount.size(), receivedArgs.size());
    for (Map.Entry<String, Integer> e : keyValueCount.entrySet()) {
      assertEquals("Value count for key " + e.getKey() + " does not match",
          e.getValue() == 0 ? 1 : e.getValue().intValue(), receivedArgs.get(e.getKey()).size());
    }

    assertEquals("Auto-read is in an invalid state",
        (!restMethod.equals(RestMethod.POST) && !restMethod.equals(RestMethod.PUT))
            || NettyRequest.bufferWatermark <= 0, channel.config().isAutoRead());
  }
Validates the various expected properties of the provided {@code nettyRequest}.
@param nettyRequest the {@link NettyRequest} that needs to be validated.
@param restMethod the expected {@link RestMethod} in {@code nettyRequest}.
@param uri the expected URI in {@code nettyRequest}.
@param headers the {@link HttpHeaders} passed with the request that need to be in {@link NettyRequest#getArgs()}.
@param params the parameters passed with the request that need to be in {@link NettyRequest#getArgs()}.
@param httpCookies Set of {@link Cookie} set in the request
@param channel the {@link MockChannel} over which the request was received.
ambry-rest/src/test/java/com/github/ambry/rest/NettyRequestTest.java