/** * Copyright 2016 Yahoo Inc. * * 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. */ package com.yahoo.pulsar.broker.web; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.fail; import java.util.Optional; import javax.servlet.FilterChain; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.WebApplicationException; import org.mockito.Matchers; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import com.yahoo.pulsar.broker.PulsarService; import com.yahoo.pulsar.broker.authentication.AuthenticationService; import com.yahoo.pulsar.broker.service.BrokerService; import com.yahoo.pulsar.zookeeper.ZooKeeperCache; public class ApiVersionFilterTest { private PulsarService pulsar; private ZooKeeperCache localCache; private HttpServletRequest req; private HttpServletResponse resp; private FilterChain chain; @BeforeMethod public void perTestSetup() { pulsar = mock(PulsarService.class); localCache = mock(ZooKeeperCache.class); req = mock(HttpServletRequest.class); resp = mock(HttpServletResponse.class); chain = mock(FilterChain.class); } /** * Test that if the client reports a valid version, the request is allowed. */ @Test public void testClientWithValidVersion() throws Exception { ApiVersionFilter filter = new ApiVersionFilter(pulsar, false); // Set up mock behaviour for the test. when(pulsar.getLocalZkCache()).thenReturn(localCache); when(localCache.getData(eq("/minApiVersion"), Matchers.anyObject())).thenReturn(Optional.of("1.0")); when(req.getHeader("pulsar-client-version")).thenReturn("1.0"); filter.doFilter(req, resp, chain); verify(chain).doFilter(req, resp); } /** * Test that if the client reports a version lower than the minApiVersion, the request is rejected. */ @Test public void testClientWithLowVersion() throws Exception { ApiVersionFilter filter = new ApiVersionFilter(pulsar, false); // Set up mock behaviour for the test. when(pulsar.getLocalZkCache()).thenReturn(localCache); when(localCache.getData(eq("/minApiVersion"), Matchers.anyObject())).thenReturn(Optional.of("1.0")); when(req.getHeader("pulsar-client-version")).thenReturn("0.9"); filter.doFilter(req, resp, chain); verify(resp).sendError(HttpServletResponse.SC_BAD_REQUEST, "Unsuported Client version"); verify(chain, never()).doFilter(req, resp); } /** * Test that if the min client version cannot be determined from ZooKeeper, the request is allowed. */ @Test public void testZKReadFailureAllowsAccess() throws Exception { ApiVersionFilter filter = new ApiVersionFilter(pulsar, false); // Set up mock behaviour for the test. when(pulsar.getLocalZkCache()).thenReturn(localCache); doThrow(new RuntimeException()).when(localCache).getData(eq("/minApiVersion"), Matchers.anyObject()); when(req.getHeader("pulsar-client-version")).thenReturn("0.9"); filter.doFilter(req, resp, chain); verify(chain).doFilter(req, resp); } /** * Test that if the either the min client version or the reported version is incorrectly formatted, the request is * allowed. */ @Test public void testBadVersionFormatRequestIsAllowed() throws Exception { ApiVersionFilter filter = new ApiVersionFilter(pulsar, false); // Set up mock behaviour for the test. when(pulsar.getLocalZkCache()).thenReturn(localCache); when(localCache.getData(eq("/minApiVersion"), Matchers.anyObject())).thenReturn(Optional.of("foo")); when(req.getHeader("pulsar-client-version")).thenReturn("0.9"); filter.doFilter(req, resp, chain); verify(chain).doFilter(req, resp); } /** * Test that if the client version is not reported, the allowUnversionedClients field is used to determine the * response. */ @Test public void testDefaultVersionAssumedOnUnreportedVersion() throws Exception { ApiVersionFilter filter1 = new ApiVersionFilter(pulsar, true); ApiVersionFilter filter2 = new ApiVersionFilter(pulsar, false); // Set up mock behaviour for the test. when(pulsar.getLocalZkCache()).thenReturn(localCache); when(localCache.getData(eq("/minApiVersion"), Matchers.anyObject())).thenReturn(Optional.of("1.0")); // Returning null here will simulate the client not sending a version, // which should cause the response to be determined by the // allowUnversionedClients field. when(req.getHeader("pulsar-client-version")).thenReturn(null); filter1.doFilter(req, resp, chain); filter2.doFilter(req, resp, chain); verify(chain).doFilter(req, resp); } @Test public void testVipStatus() { VipStatus vipStatus = spy(new VipStatus()); vipStatus.setPulsar(pulsar); when(pulsar.getStatusFilePath()).thenReturn("testFile.html"); try { vipStatus.checkStatus(); fail(); } catch (WebApplicationException e) { // Ok } } @Test public void testAuthFilterTest() throws Exception { BrokerService nativeService = mock(BrokerService.class); AuthenticationService authService = mock(AuthenticationService.class); doReturn(nativeService).when(pulsar).getBrokerService(); doReturn(authService).when(nativeService).getAuthenticationService(); doReturn("test-role").when(authService).authenticateHttpRequest(mock(HttpServletRequest.class)); AuthenticationFilter filter = new AuthenticationFilter(pulsar); HttpServletRequest request = mock(HttpServletRequest.class); ServletResponse response = null; doNothing().when(request).setAttribute(anyString(), anyObject()); filter.doFilter(request, response, chain); } }