/* * #%L * Wisdom-Framework * %% * Copyright (C) 2013 - 2014 Wisdom Framework * %% * 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. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.wisdom.framework.filters.test; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.net.HttpHeaders; import org.junit.Test; import org.wisdom.api.configuration.Configuration; import org.wisdom.api.http.*; import org.wisdom.api.interception.RequestContext; import org.wisdom.api.router.Route; import org.wisdom.framework.filters.BalancerFilter; import org.wisdom.framework.filters.BalancerMember; import org.wisdom.framework.filters.DefaultBalancerMember; import org.wisdom.test.parents.FakeContext; import org.wisdom.test.parents.FakeRequest; import org.wisdom.test.parents.WisdomUnitTest; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class BalancerFilterTest extends WisdomUnitTest { @Test public void testRoundRobin() throws Exception { BalancerMember member1 = new DefaultBalancerMember("member-1", "http://perdu.com", "balancer"); BalancerMember member2 = new DefaultBalancerMember("member-2", "http://perdus.com", "balancer"); BalancerFilter balancer = new BalancerFilter() { @Override public String getName() { return "balancer"; } @Override protected boolean followRedirect(String method) { return true; } }; balancer.addMember(member1); balancer.addMember(member2); Route route = mock(Route.class); RequestContext rc = mock(RequestContext.class); FakeContext context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive"); FakeRequest request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); Result result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); } @Test public void testMemberDynamism() throws Exception { BalancerMember member1 = new DefaultBalancerMember("member-1", "http://perdu.com", "balancer"); BalancerMember member2 = new DefaultBalancerMember("member-2", "http://perdus.com", "balancer"); BalancerFilter balancer = new BalancerFilter() { @Override public String getName() { return "balancer"; } @Override protected boolean followRedirect(String method) { return true; } }; balancer.addMember(member1); balancer.addMember(member2); Route route = mock(Route.class); RequestContext rc = mock(RequestContext.class); FakeContext context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive"); FakeRequest request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); Result result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); // Remove member1 balancer.removeMember(member1); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); //Re-add member 1 balancer.addMember(member1); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); } @Test public void testStickySession() throws Exception { BalancerMember member1 = new DefaultBalancerMember("member-1", "http://perdu.com", "balancer"); BalancerMember member2 = new DefaultBalancerMember("member-2", "http://perdus.com", "balancer"); BalancerFilter balancer = new BalancerFilter() { @Override public String getName() { return "balancer"; } @Override public boolean getStickySession() { return true; } @Override protected boolean followRedirect(String method) { return true; } }; balancer.addMember(member1); balancer.addMember(member2); Route route = mock(Route.class); RequestContext rc = mock(RequestContext.class); FakeContext context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive").setParameter("_balancer", "member-2"); FakeRequest request = new FakeRequest(context) .method(HttpMethod.GET) .uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); Result result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); context.setParameter("_balancer", "member-1"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); } @Test public void testFallbackOnStickySession() throws Exception { BalancerMember member1 = new DefaultBalancerMember("member-1", "http://perdu.com", "balancer"); BalancerMember member2 = new DefaultBalancerMember("member-2", "http://perdus.com", "balancer"); BalancerFilter balancer = new BalancerFilter() { @Override public String getName() { return "balancer"; } @Override public boolean getStickySession() { return true; } @Override protected boolean followRedirect(String method) { return true; } }; balancer.addMember(member1); balancer.addMember(member2); Route route = mock(Route.class); RequestContext rc = mock(RequestContext.class); FakeContext context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive").setParameter("_balancer", "member-2"); FakeRequest request = new FakeRequest(context) .method(HttpMethod.GET) .uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); Result result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Perdus sur Internet"); context.setParameter("_balancer", "member-1"); request = new FakeRequest(context).method(HttpMethod.GET).uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); // remove member - 2 balancer.removeMember(member2); context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive") .setParameter("_balancer", "member-2"); request = new FakeRequest(context) .method(HttpMethod.GET) .uri("/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); result = ((AsyncResult) balancer.call(route, rc)).callable().call(); // Fallback to member-1 assertThat(result).isNotNull(); assertThat(result.getStatusCode()).isEqualTo(Status.OK); assertThat(streamToString(result)).contains("Vous Etes Perdu"); } @Test public void testBalancerConfiguration() { Configuration configuration = mock(Configuration.class); when(configuration.get("prefix")).thenReturn("/proxy"); when(configuration.getOrDie("name")).thenReturn("balancer"); when(configuration.getBooleanWithDefault("stickySession", false)) .thenReturn(true); when(configuration.getBooleanWithDefault("proxyPassReverse", false)) .thenReturn(true); BalancerFilter balancer = new BalancerFilter(configuration); assertThat(balancer.getName()).isEqualTo("balancer"); assertThat(balancer.getProxyPassReverse()).isTrue(); assertThat(balancer.getStickySession()).isTrue(); } @Test public void testReverseRoutingHeaderModification() { Configuration configuration = mock(Configuration.class); when(configuration.get("prefix")).thenReturn("/app"); when(configuration.getOrDie("name")).thenReturn("balancer"); when(configuration.getBooleanWithDefault("stickySession", false)) .thenReturn(true); when(configuration.getBooleanWithDefault("proxyPassReverse", false)) .thenReturn(true); BalancerFilter balancer = new BalancerFilter(configuration); BalancerMember member1 = new DefaultBalancerMember("member-1", "http://foo.com", "balancer"); balancer.addMember(member1); RequestContext rc = mock(RequestContext.class); FakeContext context = new FakeContext(); context.setPath("/").setHeader(HttpHeaders.CONNECTION, "keep-alive"); FakeRequest request = new FakeRequest(context) .method(HttpMethod.GET) .uri("http://localhost:9000/app/"); when(rc.context()).thenReturn(context); when(rc.request()).thenReturn(request); Multimap<String, String> headers = ArrayListMultimap.create(); headers.put(HeaderNames.LOCATION, "http://foo.com/my/path?q=v#test"); headers.put(HeaderNames.CONTENT_LOCATION, "http://foo.com/my/path"); balancer.updateHeaders(rc, headers); assertThat(headers.entries()).hasSize(2); assertThat(headers.containsEntry(HeaderNames.LOCATION, "http://localhost:9000/my/path?q=v#test")).isTrue(); assertThat(headers.containsEntry(HeaderNames.CONTENT_LOCATION, "http://localhost:9000/my/path")).isTrue(); } }