/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ package com.github.ambry.rest; import com.codahale.metrics.MetricRegistry; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultLastHttpContent; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpUtil; import java.io.IOException; import junit.framework.Assert; import org.junit.Test; import static org.junit.Assert.*; public class HealthCheckHandlerTest { private final RestServerState restServerState; private final String healthCheckUri = "/healthCheck"; private final String goodStr = "GOOD"; private final String badStr = "BAD"; public HealthCheckHandlerTest() { this.restServerState = new RestServerState(healthCheckUri); } /** * Tests for the common case request handling flow for health check requests. * @throws java.io.IOException */ @Test public void requestHandleWithHealthCheckRequestTest() throws IOException { // test with keep alive testHealthCheckRequest(HttpMethod.GET, true, true); testHealthCheckRequest(HttpMethod.GET, false, true); // test without keep alive testHealthCheckRequest(HttpMethod.GET, true, false); testHealthCheckRequest(HttpMethod.GET, false, false); } /** * Tests non health check requests handling * @throws IOException */ @Test public void requestHandleWithNonHealthCheckRequestTest() throws IOException { testNonHealthCheckRequest(HttpMethod.POST, "POST"); testNonHealthCheckRequest(HttpMethod.GET, "GET"); testNonHealthCheckRequest(HttpMethod.DELETE, "DELETE"); } /** * Does a test to see that a health check request results in expected response from the health check handler * @param httpMethod the {@link HttpMethod} for the request. * @param keepAlive true if keep alive has to be set in the request, false otherwise * @throws IOException */ private void testHealthCheckRequest(HttpMethod httpMethod, boolean isServiceUp, boolean keepAlive) throws IOException { EmbeddedChannel channel = createChannel(); for (int i = 0; i < 2; i++) { if (isServiceUp) { restServerState.markServiceUp(); } HttpRequest request = RestTestUtils.createRequest(httpMethod, healthCheckUri, null); HttpUtil.setKeepAlive(request, keepAlive); FullHttpResponse response = sendRequestAndGetResponse(channel, request); HttpResponseStatus httpResponseStatus = (isServiceUp) ? HttpResponseStatus.OK : HttpResponseStatus.SERVICE_UNAVAILABLE; assertEquals("Unexpected response status", httpResponseStatus, response.status()); String expectedStr = (isServiceUp) ? goodStr : badStr; assertEquals("Unexpected content", expectedStr, RestTestUtils.getContentString(response)); restServerState.markServiceDown(); if (keepAlive && isServiceUp) { Assert.assertTrue("Channel should not be closed ", channel.isOpen()); } else { Assert.assertFalse("Channel should have been closed by now ", channel.isOpen()); channel = createChannel(); } } channel.close(); } /** * Does a test to see that a non health check request results in expected responses * @param httpMethod the {@link HttpMethod} for the request. * @param uri Uri to be used during the request * @throws IOException */ private void testNonHealthCheckRequest(HttpMethod httpMethod, String uri) throws IOException { EmbeddedChannel channel = createChannel(); HttpRequest request = RestTestUtils.createRequest(httpMethod, uri, null); FullHttpResponse response = sendRequestAndGetResponse(channel, request); assertEquals("Unexpected response status", HttpResponseStatus.OK, response.status()); assertEquals("Unexpected content", httpMethod.toString(), RestTestUtils.getContentString(response)); channel.close(); } /** * Sends request to the passed in channel and returns the response * @param channel to which the request has to be sent * @param request {@link HttpRequest} which has to be sent to the passed in channel * @return the HttpResponse in response to the request sent to the channel */ private FullHttpResponse sendRequestAndGetResponse(EmbeddedChannel channel, HttpRequest request) { channel.writeInbound(request); channel.writeInbound(new DefaultLastHttpContent()); return channel.readOutbound(); } // helpers // general /** * Creates an {@link EmbeddedChannel} that incorporates an instance of {@link HealthCheckHandler} * and {@link EchoMethodHandler}. * @return an {@link EmbeddedChannel} that incorporates an instance of {@link HealthCheckHandler} * and {@link EchoMethodHandler}. */ private EmbeddedChannel createChannel() { return new EmbeddedChannel(new HealthCheckHandler(restServerState, new NettyMetrics(new MetricRegistry())), new EchoMethodHandler()); } }