/** * Copyright (C) 2012-2017 the original author or authors. * * 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 ninja; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayOutputStream; import ninja.utils.HttpCacheToolkit; import ninja.utils.MimeTypes; import ninja.utils.NinjaProperties; import ninja.utils.ResponseStreams; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class AssetsControllerTest { @Mock MimeTypes mimeTypes; @Mock HttpCacheToolkit httpCacheToolkit; @Mock Context contextRenderable; @Captor ArgumentCaptor<Result> resultCaptor; @Mock ResponseStreams responseStreams; @Mock NinjaProperties ninjaProperties; AssetsController assetsController; @Before public void before() { assetsController = new AssetsController( new AssetsControllerHelper(), httpCacheToolkit, mimeTypes, ninjaProperties); } @Test public void testServeStatic404() throws Exception { when(contextRenderable.getRequestPath()).thenReturn("notAvailable"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); renderable.render(contextRenderable, result); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(Results.notFound().getStatusCode(), resultCaptor.getValue().getStatusCode()); } @Test public void testServeStaticSecurityClassesWithoutSlash() throws Exception { when(contextRenderable.getRequestPath()).thenReturn("ninja/Ninja.class"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); renderable.render(contextRenderable, result); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(Results.notFound().getStatusCode(), resultCaptor.getValue().getStatusCode()); } @Test public void testServeStaticSecurityClassesAbsolute() throws Exception { when(contextRenderable.getRequestPath()).thenReturn("/ninja/Ninja.class"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); renderable.render(contextRenderable, result); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(Results.notFound().getStatusCode(), resultCaptor.getValue().getStatusCode()); } @Test public void testServeStaticSecurityNoRelativPathWorks() throws Exception { //This theoretically could work as robots.txt is there.. // But it should when(contextRenderable.getRequestPath()).thenReturn("/assets/../../conf/heroku.conf"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); renderable.render(contextRenderable, result); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(Results.notFound().getStatusCode(), resultCaptor.getValue().getStatusCode()); } @Test public void testServeStaticDirectory() throws Exception { AssetsControllerHelper assetsControllerHelper = Mockito.mock(AssetsControllerHelper.class, Mockito.CALLS_REAL_METHODS); assetsController = new AssetsController( assetsControllerHelper, httpCacheToolkit, mimeTypes, ninjaProperties); when(contextRenderable.getRequestPath()).thenReturn("/"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); renderable.render(contextRenderable, result); verify(assetsControllerHelper).isDirectoryURL(this.getClass().getResource("/assets/")); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(Results.notFound().getStatusCode(), resultCaptor.getValue().getStatusCode()); } @Test public void testServeStatic304NotModified() throws Exception { when(contextRenderable.getRequestPath()).thenReturn( "/assets/testasset.txt"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); Result result = Results.ok(); // manually set to not modified => asset controller should // only finalize, but not stream result.status(Result.SC_304_NOT_MODIFIED); renderable.render(contextRenderable, result); // test streaming of resource: // => not modified: // check etag has been called verify(httpCacheToolkit).addEtag(Mockito.eq(contextRenderable), Mockito.eq(result), Mockito.anyLong()); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); // make sure we get the correct result... assertEquals(Result.SC_304_NOT_MODIFIED, resultCaptor.getValue() .getStatusCode()); } @Test public void testStaticDirectoryIsFileSystemInDevMode() throws Exception { // some more setup needed: Mockito.when(ninjaProperties.isDev()).thenReturn(true); AssetsControllerHelper assetsControllerHelper = Mockito.mock(AssetsControllerHelper.class, Mockito.CALLS_REAL_METHODS); assetsController = new AssetsController( assetsControllerHelper, httpCacheToolkit, mimeTypes, ninjaProperties); when(contextRenderable.getRequestPath()).thenReturn( "/assets/testasset-not-existent.txt"); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, Results.ok()); verify(assetsControllerHelper).normalizePathWithoutLeadingSlash("/assets/testasset-not-existent.txt", true); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(404, resultCaptor.getValue().getStatusCode()); } @Test public void testStaticDirectoryClassPathWhenFileNotInFileSystemInDevMode() throws Exception { // some more setup needed: Mockito.when(ninjaProperties.isDev()).thenReturn(true); AssetsControllerHelper assetsControllerHelper = Mockito.mock(AssetsControllerHelper.class, Mockito.CALLS_REAL_METHODS); assetsController = new AssetsController( assetsControllerHelper, httpCacheToolkit, mimeTypes, ninjaProperties); when(contextRenderable.getRequestPath()).thenReturn( "/assets/testasset.txt"); when(contextRenderable.finalizeHeadersWithoutFlashAndSessionCookie(Mockito.any(Result.class))).thenReturn( responseStreams); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(responseStreams.getOutputStream()).thenReturn( byteArrayOutputStream); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, Results.ok()); verify(assetsControllerHelper).normalizePathWithoutLeadingSlash("/assets/testasset.txt", true); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); assertEquals(200, resultCaptor.getValue().getStatusCode()); } @Test public void testStaticDirectoryIsClassPathInProdMode() throws Exception { // some more setup needed: Mockito.when(ninjaProperties.isDev()).thenReturn(false); AssetsControllerHelper assetsControllerHelper = Mockito.mock(AssetsControllerHelper.class, Mockito.CALLS_REAL_METHODS); assetsController = new AssetsController( assetsControllerHelper, httpCacheToolkit, mimeTypes, ninjaProperties); when(contextRenderable.getRequestPath()).thenReturn( "/assets/testasset.txt"); when(contextRenderable.finalizeHeadersWithoutFlashAndSessionCookie(Mockito.any(Result.class))).thenReturn( responseStreams); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(responseStreams.getOutputStream()).thenReturn( byteArrayOutputStream); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, Results.ok()); verify(assetsControllerHelper).normalizePathWithoutLeadingSlash("/assets/testasset.txt", true); } @Test public void testServeStaticNormalOperationModifiedNoCaching() throws Exception { Result result = Results.ok(); when(contextRenderable.getRequestPath()).thenReturn( "/assets/testasset.txt"); when(mimeTypes.getContentType(Mockito.eq(contextRenderable), Mockito.anyString())).thenReturn("mimetype"); when(contextRenderable.finalizeHeadersWithoutFlashAndSessionCookie(Mockito.eq(result))).thenReturn( responseStreams); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(responseStreams.getOutputStream()).thenReturn( byteArrayOutputStream); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, result); // test streaming of resource: // => not modified: // check etag has been called verify(httpCacheToolkit).addEtag(Mockito.eq(contextRenderable), Mockito.eq(result), Mockito.anyLong()); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); // make sure we get the correct result... assertEquals(Result.SC_200_OK, resultCaptor.getValue().getStatusCode()); // we mocked this one: assertEquals("mimetype", result.getContentType()); // make sure the content is okay... assertEquals("testasset", byteArrayOutputStream.toString()); } @Test public void testServeStaticRobotsTxt() throws Exception { Result result = Results.ok(); when(contextRenderable.getRequestPath()).thenReturn( "/robots.txt"); when(mimeTypes.getContentType(Mockito.eq(contextRenderable), Mockito.anyString())).thenReturn("mimetype"); when(contextRenderable.finalizeHeadersWithoutFlashAndSessionCookie(Mockito.eq(result))).thenReturn( responseStreams); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(responseStreams.getOutputStream()).thenReturn( byteArrayOutputStream); Result result2 = assetsController.serveStatic(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, result); // test streaming of resource: // => not modified: // check etag has been called verify(httpCacheToolkit).addEtag(Mockito.eq(contextRenderable), Mockito.eq(result), Mockito.anyLong()); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); // make sure we get the correct result... assertEquals(Result.SC_200_OK, resultCaptor.getValue().getStatusCode()); // we mocked this one: assertEquals("mimetype", result.getContentType()); String content = byteArrayOutputStream.toString(); assertThat(content, containsString("User-agent: *")); assertThat(content, containsString("Disallow: /")); } @Test public void testServeWebJars() throws Exception { AssetsControllerHelper assetsControllerHelper = Mockito.mock(AssetsControllerHelper.class, Mockito.CALLS_REAL_METHODS); assetsController = new AssetsController( assetsControllerHelper, httpCacheToolkit, mimeTypes, ninjaProperties); Result result = Results.ok(); when(contextRenderable.getRequestPath()).thenReturn( "/webjar_asset.txt"); when(contextRenderable.finalizeHeadersWithoutFlashAndSessionCookie(Mockito.eq(result))).thenReturn( responseStreams); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(responseStreams.getOutputStream()).thenReturn( byteArrayOutputStream); Result result2 = assetsController.serveWebJars(); Renderable renderable = (Renderable) result2.getRenderable(); renderable.render(contextRenderable, result); verify(contextRenderable).finalizeHeadersWithoutFlashAndSessionCookie(resultCaptor.capture()); // make sure we get the correct result... assertEquals(Result.SC_200_OK, resultCaptor.getValue().getStatusCode()); assertEquals("webjar_asset", byteArrayOutputStream.toString()); verify(assetsControllerHelper).normalizePathWithoutLeadingSlash("/webjar_asset.txt", true); } }