From e56d6504c04ab684f9986dec788b013ae46a538a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 12 Apr 2019 14:32:17 +0200 Subject: [PATCH] Add unit tests --- .../api/v2/resources/LogoutRedirection.java | 1 + scm-ui/src/modules/auth.js | 5 +- scm-ui/src/modules/auth.test.js | 40 +++++++++++++++- .../resources/AuthenticationResourceTest.java | 46 ++++++++++++++++--- 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/LogoutRedirection.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/LogoutRedirection.java index c0b59d4dac..84fe2ddf7b 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/LogoutRedirection.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/LogoutRedirection.java @@ -6,6 +6,7 @@ import java.net.URI; import java.util.Optional; @ExtensionPoint(multi = false) +@FunctionalInterface public interface LogoutRedirection { Optional afterLogoutRedirectTo(); } diff --git a/scm-ui/src/modules/auth.js b/scm-ui/src/modules/auth.js index ecd529f735..8b22c8a0c5 100644 --- a/scm-ui/src/modules/auth.js +++ b/scm-ui/src/modules/auth.js @@ -204,10 +204,9 @@ export const logout = (link: string, history: History) => { }) .then(json => { if (json && json.logoutRedirect) { - location.href = json.logoutRedirect; - } else { - dispatch(logoutSuccess()); + window.location.assign(json.logoutRedirect); } + dispatch(logoutSuccess()); }) .then(() => { dispatch(fetchIndexResources()); diff --git a/scm-ui/src/modules/auth.test.js b/scm-ui/src/modules/auth.test.js index 1d7cb5096e..199d369022 100644 --- a/scm-ui/src/modules/auth.test.js +++ b/scm-ui/src/modules/auth.test.js @@ -26,7 +26,7 @@ import reducer, { FETCH_ME, LOGOUT, getLoginFailure, - getLogoutFailure + getLogoutFailure, } from "./auth"; import configureMockStore from "redux-mock-store"; @@ -224,6 +224,44 @@ describe("auth actions", () => { }); }); + it("should dispatch logout success and redirect", () => { + fetchMock.deleteOnce("/api/v2/auth/access_token", { + status: 200, + body: { logoutRedirect: "http://example.com/cas/logout" } + }); + + fetchMock.getOnce("/api/v2/me", { + status: 401 + }); + + fetchMock.getOnce("/api/v2/", { + _links: { + login: { + login: "/login" + } + } + }); + + window.location.assign = jest.fn(); + + const expectedActions = [ + { type: LOGOUT_PENDING }, + { type: LOGOUT_SUCCESS }, + { type: FETCH_INDEXRESOURCES_PENDING } + ]; + + const store = mockStore({}); + + return store.dispatch(logout("/auth/access_token")).then(() => { + expect(window.location.assign.mock.calls[0][0]).toBe( + "http://example.com/cas/logout" + ); + expect(store.getActions()).toEqual(expectedActions); + + // expect(window.location.href).toEqual("http://example.com/cas/logout"); + }); + }); + it("should dispatch logout failure", () => { fetchMock.deleteOnce("/api/v2/auth/access_token", { status: 500 diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java index 3493283086..b9612fedb2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java @@ -23,10 +23,18 @@ import sonia.scm.security.DefaultAccessTokenCookieIssuer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.MediaType; +import java.io.UnsupportedEncodingException; +import java.net.URI; import java.net.URISyntaxException; import java.util.Date; +import java.util.Optional; +import static java.net.URI.create; +import static java.util.Optional.empty; +import static java.util.Optional.of; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -49,6 +57,8 @@ public class AuthenticationResourceTest { private AccessTokenCookieIssuer cookieIssuer = new DefaultAccessTokenCookieIssuer(mock(ScmConfiguration.class)); + private MockHttpResponse response = new MockHttpResponse(); + private static final String AUTH_JSON_TRILLIAN = "{\n" + "\t\"cookie\": true,\n" + "\t\"grant_type\": \"password\",\n" + @@ -123,7 +133,6 @@ public class AuthenticationResourceTest { public void shouldAuthCorrectly() throws URISyntaxException { MockHttpRequest request = getMockHttpRequest(AUTH_JSON_TRILLIAN); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -134,7 +143,6 @@ public class AuthenticationResourceTest { public void shouldAuthCorrectlyWithFormencodedData() throws URISyntaxException { MockHttpRequest request = getMockHttpRequestUrlEncoded(AUTH_FORMENCODED_TRILLIAN); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -146,7 +154,6 @@ public class AuthenticationResourceTest { public void shouldNotAuthUserWithWrongPassword() throws URISyntaxException { MockHttpRequest request = getMockHttpRequest(AUTH_JSON_TRILLIAN_WRONG_PW); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -156,7 +163,6 @@ public class AuthenticationResourceTest { @Test public void shouldNotAuthNonexistingUser() throws URISyntaxException { MockHttpRequest request = getMockHttpRequest(AUTH_JSON_NOT_EXISTING_USER); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -187,16 +193,43 @@ public class AuthenticationResourceTest { @SubjectAware(username = "trillian", password = "secret") public void shouldSuccessfullyLogoutUser() throws URISyntaxException { MockHttpRequest request = MockHttpRequest.delete("/" + AuthenticationResource.PATH + "/access_token"); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); } + @Test + public void shouldHandleLogoutRedirection() throws URISyntaxException, UnsupportedEncodingException { + mockResourceWithLogoutRedirection(of(create("http://example.com/cas/logout"))); + + MockHttpRequest request = MockHttpRequest.delete("/" + AuthenticationResource.PATH + "/access_token"); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertThat(response.getContentAsString(), containsString("http://example.com/cas/logout")); + } + + @Test + public void shouldHandleDisabledLogoutRedirection() throws URISyntaxException { + mockResourceWithLogoutRedirection(empty()); + + MockHttpRequest request = MockHttpRequest.delete("/" + AuthenticationResource.PATH + "/access_token"); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); + } + + private void mockResourceWithLogoutRedirection(Optional target) { + dispatcher.getRegistry().removeRegistrations(AuthenticationResource.class); + AuthenticationResource authenticationResource = + new AuthenticationResource(accessTokenBuilderFactory, cookieIssuer, () -> target); + dispatcher.getRegistry().addSingletonResource(authenticationResource); + } private void shouldReturnBadRequest(String requestBody) throws URISyntaxException { MockHttpRequest request = getMockHttpRequest(requestBody); - MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke(request, response); @@ -218,5 +251,4 @@ public class AuthenticationResourceTest { request.contentType(MediaType.APPLICATION_FORM_URLENCODED_TYPE); return request; } - }