merge with branch 1.x

This commit is contained in:
Sebastian Sdorra
2017-01-12 19:50:39 +01:00
250 changed files with 16399 additions and 1573 deletions

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.filter;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import org.apache.shiro.SecurityUtils;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
/**
* Unit tests for {@link AdminSecurityFilter}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini")
public class AdminSecurityFilterTest {
private AdminSecurityFilter securityFilter;
@Rule
public ShiroRule shiro = new ShiroRule();
/**
* Prepare object under test and mocks.
*/
@Before
public void setUp(){
this.securityFilter = new AdminSecurityFilter(new ScmConfiguration());
}
/**
* Tests {@link AdminSecurityFilter#hasPermission(org.apache.shiro.subject.Subject)} as administrator.
*/
@Test
@SubjectAware(username = "dent", password = "secret")
public void testHasPermissionAsAdministrator() {
assertTrue(securityFilter.hasPermission(SecurityUtils.getSubject()));
}
/**
* Tests {@link AdminSecurityFilter#hasPermission(org.apache.shiro.subject.Subject)} as user.
*/
@Test
@SubjectAware(username = "trillian", password = "secret")
public void testHasPermissionAsUser() {
assertFalse(securityFilter.hasPermission(SecurityUtils.getSubject()));
}
}

View File

@@ -0,0 +1,130 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.filter;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import java.io.IOException;
import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.MDC;
import sonia.scm.AbstractTestBase;
/**
* Unit tests for {@link MDCFilter}.
*
* @author Sebastian Sdorra <sebastian.sdorra@gmail.com>
*/
@RunWith(MockitoJUnitRunner.class)
public class MDCFilterTest extends AbstractTestBase {
@Rule
public ShiroRule shiro = new ShiroRule();
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
private final MDCFilter filter = new MDCFilter();
/**
* Tests {@link MDCFilter#doFilter(HttpServletRequest, HttpServletResponse, FilterChain)}.
*
* @throws IOException
* @throws ServletException
*/
@Test
@SubjectAware(
username = "trillian",
password = "secret",
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testDoFilter() throws IOException, ServletException
{
when(request.getRequestURI()).thenReturn("api/v1/repositories");
when(request.getRemoteAddr()).thenReturn("127.0.0.1");
when(request.getRemoteHost()).thenReturn("localhost");
when(request.getMethod()).thenReturn("GET");
MDCCapturingFilterChain chain = new MDCCapturingFilterChain();
filter.doFilter(request, response, chain);
assertNotNull(chain.ctx);
assertEquals("trillian", chain.ctx.get(MDCFilter.MDC_USERNAME));
assertEquals("api/v1/repositories", chain.ctx.get(MDCFilter.MDC_REQUEST_URI));
assertEquals("127.0.0.1", chain.ctx.get(MDCFilter.MDC_CLIEN_IP));
assertEquals("localhost", chain.ctx.get(MDCFilter.MDC_CLIEN_HOST));
assertEquals("GET", chain.ctx.get(MDCFilter.MDC_REQUEST_METHOD));
}
/**
* Tests {@link MDCFilter#doFilter(HttpServletRequest, HttpServletResponse, FilterChain)} as anonymous user.
*
* @throws IOException
* @throws ServletException
*/
@Test
@SubjectAware
public void testDoFilterAsAnonymous() throws IOException, ServletException {
MDCCapturingFilterChain chain = new MDCCapturingFilterChain();
filter.doFilter(request, response, chain);
assertNotNull(chain.ctx);
assertEquals("anonymous", chain.ctx.get(MDCFilter.MDC_USERNAME));
}
private static class MDCCapturingFilterChain implements FilterChain {
private Map<String, String> ctx;
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
this.ctx = MDC.getCopyOfContextMap();
}
}
}

View File

@@ -0,0 +1,238 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.filter;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.user.User;
import sonia.scm.user.UserTestData;
/**
* Unit tests for {@link SecurityFilter}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini")
public class SecurityFilterTest {
@Mock
private HttpServletRequest request;
@Captor
private ArgumentCaptor<HttpServletRequest> requestCaptor;
@Mock
private HttpServletResponse response;
@Captor
private ArgumentCaptor<HttpServletResponse> responseCaptor;
@Mock
private FilterChain chain;
private ScmConfiguration configuration;
private SecurityFilter securityFilter;
@Rule
public ShiroRule shiro = new ShiroRule();
/**
* Prepare object under test and mocks.
*/
@Before
public void setUp(){
this.configuration = new ScmConfiguration();
this.securityFilter = new SecurityFilter(configuration);
when(request.getContextPath()).thenReturn("/scm");
}
/**
* Tests filter on authentication endpoint.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoOnAuthenticationUrl() throws IOException, ServletException {
when(request.getRequestURI()).thenReturn("/scm/api/rest/authentication");
securityFilter.doFilter(request, response, chain);
verify(request, never()).setAttribute(Mockito.anyString(), Mockito.any());
verify(chain).doFilter(request, response);
}
/**
* Tests filter without prior authentication.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testAnonymous() throws IOException, ServletException {
when(request.getRequestURI()).thenReturn("/scm/api");
securityFilter.doFilter(request, response, chain);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
/**
* Tests filter without prior authentication and enabled anonymous access.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testAnonymousWithAccessEnabled() throws IOException, ServletException {
when(request.getRequestURI()).thenReturn("/scm/api");
configuration.setAnonymousAccessEnabled(true);
// execute
securityFilter.doFilter(request, response, chain);
// verify and capture
verify(request).setAttribute(SecurityFilter.ATTRIBUTE_REMOTE_USER, SCMContext.USER_ANONYMOUS);
verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
// assert
HttpServletRequest captured = requestCaptor.getValue();
assertEquals(SCMContext.USER_ANONYMOUS, captured.getRemoteUser());
}
/**
* Tests filter with prior authentication.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testAuthenticated() throws IOException, ServletException {
authenticateUser(UserTestData.createTrillian());
when(request.getRequestURI()).thenReturn("/scm/api");
// execute
securityFilter.doFilter(request, response, chain);
// verify and capture
verify(request).setAttribute(SecurityFilter.ATTRIBUTE_REMOTE_USER, "trillian");
verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
// assert
HttpServletRequest captured = requestCaptor.getValue();
assertEquals("trillian", captured.getRemoteUser());
}
/**
* Tests filter without permissions.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testForbidden() throws IOException, ServletException {
authenticateUser(UserTestData.createTrillian());
when(request.getRequestURI()).thenReturn("/scm/api");
// execute
securityFilter = new AccessForbiddenSecurityFilter(configuration);
securityFilter.doFilter(request, response, chain);
// assert
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
}
/**
* Tests filter unauthenticated and without permissions.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testUnauthorized() throws IOException, ServletException {
when(request.getRequestURI()).thenReturn("/scm/api");
// execute
securityFilter = new AccessForbiddenSecurityFilter(configuration);
securityFilter.doFilter(request, response, chain);
// assert
verify(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
private void authenticateUser(User user) {
SimplePrincipalCollection spc = new SimplePrincipalCollection();
spc.add(user.getName(), "unit-test");
spc.add(user, "unit-test");
Subject subject = new Subject.Builder()
.authenticated(true)
.principals(spc)
.buildSubject();
shiro.setSubject(subject);
}
private static class AccessForbiddenSecurityFilter extends SecurityFilter {
private AccessForbiddenSecurityFilter(ScmConfiguration configuration) {
super(configuration);
}
@Override
protected boolean hasPermission(Subject subject) {
return false;
}
}
}

View File

@@ -286,7 +286,7 @@ public class AnonymousAccessITCase
File directory = temporaryFolder.newFolder();
RepositoryClient client = null;
String url = repository.createUrl(URL);
String url = repository.createUrl(BASE_URL);
if ((username != null) && (password != null))
{

View File

@@ -37,7 +37,6 @@ package sonia.scm.it;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -264,7 +263,7 @@ public class ChangesetViewerITCase extends AbstractAdminITCaseBase
throws RepositoryClientException
{
return RepositoryClientFactory.createClient(repositoryType, localDirectory,
repository.createUrl(URL), IntegrationTestUtil.ADMIN_USERNAME,
repository.createUrl(BASE_URL), IntegrationTestUtil.ADMIN_USERNAME,
IntegrationTestUtil.ADMIN_PASSWORD);
}

View File

@@ -77,11 +77,12 @@ public final class IntegrationTestUtil
/** Field description */
public static final String ADMIN_USERNAME = "scmadmin";
public static final String URL = "http://localhost:8081/scm";
/** Field description */
public static final String BASE_URL = "http://localhost:8081/scm/api/rest/";
/** scm-manager base url */
public static final String BASE_URL = "http://localhost:8081/scm/";
/** scm-manager base url for the rest api */
public static final String REST_BASE_URL = BASE_URL.concat("api/rest/");
/** Field description */
public static final String EXTENSION = ".xml";
@@ -256,7 +257,7 @@ public final class IntegrationTestUtil
*/
public static String createResourceUrl(String url)
{
return BASE_URL.concat(url).concat(EXTENSION);
return REST_BASE_URL.concat(url).concat(EXTENSION);
}
/**

View File

@@ -0,0 +1,211 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.it;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.sun.jersey.api.client.WebResource;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.junit.After;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import sonia.scm.debug.DebugHookData;
import static sonia.scm.it.IntegrationTestUtil.createResource;
import static sonia.scm.it.RepositoryITUtil.createRepository;
import static sonia.scm.it.RepositoryITUtil.deleteRepository;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.Person;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryTestData;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.repository.client.api.RepositoryClientFactory;
import sonia.scm.util.IOUtil;
/**
* Integration tests for repository hooks.
*
* @author Sebastian Sdorra
*/
@RunWith(Parameterized.class)
public class RepositoryHookITCase extends AbstractAdminITCaseBase
{
private static final long WAIT_TIME = 125;
private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory();
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
private final String repositoryType;
private Repository repository;
private File workingCopy;
private RepositoryClient repositoryClient;
/**
* Constructs a new instance with a repository type.
*
* @param repositoryType repository type
*/
public RepositoryHookITCase(String repositoryType)
{
this.repositoryType = repositoryType;
}
/**
* Creates a test repository.
*
* @throws IOException
*/
@Before
public void setUpTestRepository() throws IOException
{
repository = RepositoryTestData.createHeartOfGold(repositoryType);
repository = createRepository(client, repository);
workingCopy = tempFolder.newFolder();
repositoryClient = createRepositoryClient();
}
/**
* Removes the tests repository.
*/
@After
public void removeTestRepository()
{
deleteRepository(client, repository.getId());
}
/**
* Tests that the debug service has received the commit.
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testSimpleHook() throws IOException, InterruptedException
{
// push commit
Files.write("a", new File(workingCopy, "a.txt"), Charsets.UTF_8);
repositoryClient.getAddCommand().add("a.txt");
Changeset changeset = repositoryClient.getCommitCommand().commit(
new Person("scmadmin", "scmadmin@scm-manager.org"), "added a"
);
repositoryClient.getPushCommand().push();
// wait some time, because the debug hook is asnychron
Thread.sleep(WAIT_TIME);
// check debug servlet for pushed commit
WebResource wr = createResource(client, "debug/" + repository.getId() + "/post-receive/last");
DebugHookData data = wr.get(DebugHookData.class);
assertNotNull(data);
assertThat(data.getChangesets(), contains(changeset.getId()));
}
/**
* Tests that the debug service receives only new commits.
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testOnlyNewCommit() throws IOException, InterruptedException
{
// push commit
Files.write("a", new File(workingCopy, "a.txt"), Charsets.UTF_8);
repositoryClient.getAddCommand().add("a.txt");
Changeset a = repositoryClient.getCommitCommand().commit(
new Person("scmadmin", "scmadmin@scm-manager.org"), "added a"
);
repositoryClient.getPushCommand().push();
// create branch, commit and push again
repositoryClient.getBranchCommand().branch("feature/added-b");
Files.write("b", new File(workingCopy, "b.txt"), Charsets.UTF_8);
repositoryClient.getAddCommand().add("a.txt");
Changeset b = repositoryClient.getCommitCommand().commit(
new Person("scmadmin", "scmadmin@scm-manager.org"), "added b"
);
repositoryClient.getPushCommand().push();
// wait some time, because the debug hook is asnychron
Thread.sleep(WAIT_TIME);
// check debug servlet that only one commit is present
WebResource wr = createResource(client, "debug/" + repository.getId() + "/post-receive/last");
DebugHookData data = wr.get(DebugHookData.class);
assertNotNull(data);
assertThat(data.getChangesets(), allOf(
contains(b.getId()),
not(
contains(a.getId())
)
));
}
private RepositoryClient createRepositoryClient() throws IOException
{
return REPOSITORY_CLIENT_FACTORY.create(repositoryType,
IntegrationTestUtil.BASE_URL + repositoryType + "/" + repository.getName(),
IntegrationTestUtil.ADMIN_USERNAME, IntegrationTestUtil.ADMIN_PASSWORD, workingCopy
);
}
/**
* Returns repository types a test parameter.
*
* @return repository types test parameter
*/
@Parameters
public static Collection<String[]> createParameters()
{
Collection<String[]> params = Lists.newArrayList();
params.add(new String[] { "git" });
// params.add(new String[] { "svn" });
if (IOUtil.search("hg") != null)
{
params.add(new String[] { "hg" });
}
return params;
}
}

View File

@@ -35,7 +35,8 @@ package sonia.scm.it;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.After;
import com.google.common.collect.Lists;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -45,23 +46,23 @@ import sonia.scm.repository.Permission;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryTestData;
import sonia.scm.util.IOUtil;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import static sonia.scm.it.IntegrationTestUtil.*;
import static sonia.scm.it.RepositoryITUtil.*;
//~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import sonia.scm.util.IOUtil;
/**
*
@@ -90,34 +91,9 @@ public class RepositoryITCase extends AbstractAdminITCaseBase
*
* @return
*/
@Parameters
public static Collection<String[]> createParameters()
{
Collection<String[]> params = new ArrayList<String[]>();
params.add(new String[] { "git" });
params.add(new String[] { "svn" });
if (IOUtil.search("hg") != null)
{
params.add(new String[] { "hg" });
}
return params;
}
/**
* Method description
*
*/
@After
public void cleanup()
{
Client client = createClient();
authenticateAdmin(client);
Collection<Repository> repositories =
createResource(client,
"repositories").get(new GenericType<Collection<Repository>>() {}
@@ -137,6 +113,29 @@ public class RepositoryITCase extends AbstractAdminITCaseBase
/**
* Method description
*
*
* @return
*/
@Parameters
public static Collection<String[]> createParameters()
{
Collection<String[]> params = Lists.newArrayList();
params.add(new String[] { "git" });
params.add(new String[] { "svn" });
if (IOUtil.search("hg") != null)
{
params.add(new String[] { "hg" });
}
return params;
}
/**
* Method description
*
>>>>>>> merge rev
*/
@Test
public void create()
@@ -165,21 +164,18 @@ public class RepositoryITCase extends AbstractAdminITCaseBase
* Method description
*
*/
@Test
public void doubleCreate()
{
Repository repository = RepositoryTestData.create42Puzzle(repositoryType);
repository = createRepository(client, repository);
WebResource wr = createResource(client, "repositories");
ClientResponse response = wr.post(ClientResponse.class, repository);
assertNotNull(response);
// TODO should be 409?
assertEquals(500, response.getStatus());
assertThat(response.getStatus(), not(lessThanOrEqualTo(400)));
}
/**

View File

@@ -142,7 +142,7 @@ public class RepositoryITCaseBase
{
RepositoryClient rc =
RepositoryClientFactory.createClient(repository.getType(), directory,
repository.createUrl(URL), username, password);
repository.createUrl(BASE_URL), username, password);
rc.init();
addTestFiles(rc);
@@ -343,7 +343,7 @@ public class RepositoryITCaseBase
throws RepositoryClientException
{
return RepositoryClientFactory.createClient(repository.getType(),
directory, repository.createUrl(URL), user.getName(), password);
directory, repository.createUrl(BASE_URL), user.getName(), password);
}
//~--- fields ---------------------------------------------------------------

View File

@@ -0,0 +1,376 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.net.TrustAllHostnameVerifier;
import sonia.scm.util.HttpUtil;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.SocketAddress;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import sonia.scm.net.SSLContextProvider;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultAdvancedHttpClientTest
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyBaseSettings() throws IOException
{
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
verify(connection).setRequestMethod(HttpMethod.GET);
verify(connection).setReadTimeout(DefaultAdvancedHttpClient.TIMEOUT_RAED);
verify(connection).setConnectTimeout(
DefaultAdvancedHttpClient.TIMEOUT_CONNECTION);
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
@Test(expected = ContentTransformerNotFoundException.class)
public void testContentTransformerNotFound(){
client.createTransformer(String.class, "text/plain");
}
@Test
public void testContentTransformer(){
ContentTransformer transformer = mock(ContentTransformer.class);
when(transformer.isResponsible(String.class, "text/plain")).thenReturn(Boolean.TRUE);
transformers.add(transformer);
ContentTransformer t = client.createTransformer(String.class, "text/plain");
assertSame(transformer, t);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyContent() throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
when(connection.getOutputStream()).thenReturn(baos);
AdvancedHttpRequestWithBody request =
new AdvancedHttpRequestWithBody(client, HttpMethod.PUT,
"https://www.scm-manager.org");
request.stringContent("test").request();
verify(connection).setDoOutput(true);
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "4");
assertEquals("test", baos.toString("UTF-8"));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyHeaders() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.POST,
"http://www.scm-manager.org");
request.header("Header-One", "One").header("Header-Two", "Two").request();
verify(connection).setRequestMethod(HttpMethod.POST);
verify(connection).addRequestProperty("Header-One", "One");
verify(connection).addRequestProperty("Header-Two", "Two");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testApplyMultipleHeaders() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.POST,
"http://www.scm-manager.org");
request.header("Header-One", "One").header("Header-One", "Two").request();
verify(connection).setRequestMethod(HttpMethod.POST);
verify(connection).addRequestProperty("Header-One", "One");
verify(connection).addRequestProperty("Header-One", "Two");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testBodyRequestWithoutContent() throws IOException
{
AdvancedHttpRequestWithBody request =
new AdvancedHttpRequestWithBody(client, HttpMethod.PUT,
"https://www.scm-manager.org");
request.request();
verify(connection).addRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, "0");
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testDisableCertificateValidation() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.GET,
"https://www.scm-manager.org");
request.disableCertificateValidation(true).request();
verify(connection).setSSLSocketFactory(any(SSLSocketFactory.class));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testDisableHostnameValidation() throws IOException
{
AdvancedHttpRequest request = new AdvancedHttpRequest(client,
HttpMethod.GET,
"https://www.scm-manager.org");
request.disableHostnameValidation(true).request();
verify(connection).setHostnameVerifier(any(TrustAllHostnameVerifier.class));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testIgnoreProxy() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").ignoreProxySettings(true).request();
assertFalse(client.proxyConnection);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testProxyConnection() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
assertTrue(client.proxyConnection);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testProxyWithAuthentication() throws IOException
{
configuration.setProxyServer("proxy.scm-manager.org");
configuration.setProxyPort(8090);
configuration.setProxyUser("tricia");
configuration.setProxyPassword("tricias secret");
configuration.setEnableProxy(true);
new AdvancedHttpRequest(client, HttpMethod.GET,
"https://www.scm-manager.org").request();
assertTrue(client.proxyConnection);
verify(connection).addRequestProperty(
DefaultAdvancedHttpClient.HEADER_PROXY_AUTHORIZATION,
"Basic dHJpY2lhOnRyaWNpYXMgc2VjcmV0");
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*/
@Before
public void setUp()
{
configuration = new ScmConfiguration();
transformers = new HashSet<ContentTransformer>();
client = new TestingAdvacedHttpClient(configuration, transformers);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 15/05/01
* @author Enter your name here...
*/
public class TestingAdvacedHttpClient extends DefaultAdvancedHttpClient
{
/**
* Constructs ...
*
*
* @param configuration
* @param transformers
*/
public TestingAdvacedHttpClient(ScmConfiguration configuration,
Set<ContentTransformer> transformers)
{
super(configuration, transformers, new SSLContextProvider());
}
//~--- methods ------------------------------------------------------------
/**
* Method description
*
*
* @param url
*
* @return
*
* @throws IOException
*/
@Override
protected HttpURLConnection createConnection(URL url) throws IOException
{
return connection;
}
/**
* Method description
*
*
* @param url
* @param address
*
* @return
*
* @throws IOException
*/
@Override
protected HttpURLConnection createProxyConnecton(URL url,
SocketAddress address)
throws IOException
{
proxyConnection = true;
return connection;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private boolean proxyConnection = false;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private TestingAdvacedHttpClient client;
/** Field description */
private ScmConfiguration configuration;
/** Field description */
@Mock
private HttpsURLConnection connection;
/** Field description */
private Set<ContentTransformer> transformers;
}

View File

@@ -0,0 +1,152 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import sonia.scm.net.SSLContextProvider;
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultAdvancedHttpResponseTest
{
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testContentAsByteSource() throws IOException
{
ByteArrayInputStream bais =
new ByteArrayInputStream("test".getBytes(Charsets.UTF_8));
when(connection.getInputStream()).thenReturn(bais);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 200, "OK");
ByteSource content = response.contentAsByteSource();
assertEquals("test", content.asCharSource(Charsets.UTF_8).read());
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testContentAsByteSourceWithFailedRequest() throws IOException
{
ByteArrayInputStream bais =
new ByteArrayInputStream("test".getBytes(Charsets.UTF_8));
when(connection.getInputStream()).thenThrow(IOException.class);
when(connection.getErrorStream()).thenReturn(bais);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 404, "NOT FOUND");
ByteSource content = response.contentAsByteSource();
assertEquals("test", content.asCharSource(Charsets.UTF_8).read());
}
/**
* Method description
*
*/
@Test
public void testGetHeaders()
{
LinkedHashMap<String, List<String>> map = Maps.newLinkedHashMap();
List<String> test = Lists.newArrayList("One", "Two");
map.put("Test", test);
when(connection.getHeaderFields()).thenReturn(map);
AdvancedHttpResponse response = new DefaultAdvancedHttpResponse(client,
connection, 200, "OK");
Multimap<String, String> headers = response.getHeaders();
assertThat(headers.get("Test"), contains("One", "Two"));
assertTrue(headers.get("Test-2").isEmpty());
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final DefaultAdvancedHttpClient client =
new DefaultAdvancedHttpClient(new ScmConfiguration(),
new HashSet<ContentTransformer>(), new SSLContextProvider());
/** Field description */
@Mock
private HttpURLConnection connection;
}

View File

@@ -0,0 +1,167 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.io.ByteSource;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
public class JsonContentTransformerTest
{
/**
* Method description
*
*/
@Test
public void testDoNotFailOnUnknownProperties() {
ByteSource bs = ByteSource.wrap("{\"value\": \"test\", \"other\": \"test2\"}".getBytes(Charsets.UTF_8));
TestObject obj = transformer.unmarshall(TestObject.class, bs);
assertEquals("test", obj.value);
}
/**
* Method description
*
*/
@Test
public void testIsResponsible()
{
assertTrue(transformer.isResponsible(String.class, "application/json"));
assertTrue(transformer.isResponsible(String.class, "application/json;charset=UTF-8"));
assertFalse(transformer.isResponsible(String.class, "text/plain"));
}
/**
* Method description
*
*
* @throws IOException
*/
@Test
public void testMarshallAndUnmarshall() throws IOException
{
ByteSource bs = transformer.marshall(new TestObject("test"));
TestObject to = transformer.unmarshall(TestObject.class, bs);
assertEquals("test", to.value);
}
/**
* Method description
*
*
* @throws IOException
*/
@Test(expected = ContentTransformerException.class)
public void testUnmarshallIOException() throws IOException
{
ByteSource bs = mock(ByteSource.class);
when(bs.openBufferedStream()).thenThrow(IOException.class);
transformer.unmarshall(String.class, bs);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 15/10/21
* @author Enter your name here...
*/
@XmlRootElement(name = "test")
@XmlAccessorType(XmlAccessType.FIELD)
private static class TestObject
{
/**
* Constructs ...
*
*/
public TestObject() {}
/**
* Constructs ...
*
*
* @param value
*/
public TestObject(String value)
{
this.value = value;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private String value;
}
/**
* Class description
*
*
* @version Enter version here..., 15/10/21
* @author Enter your name here...
*/
private static class TestObject2 {}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final JsonContentTransformer transformer = new JsonContentTransformer();
}

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.io.ByteSource;
import java.io.IOException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
*
* @author Sebastian Sdorra
*/
public class XmlContentTransformerTest {
private final XmlContentTransformer transformer = new XmlContentTransformer();
@Test
public void testIsResponsible()
{
assertTrue(transformer.isResponsible(String.class, "application/xml"));
assertTrue(transformer.isResponsible(String.class, "application/xml;charset=UTF-8"));
assertFalse(transformer.isResponsible(String.class, "text/plain"));
}
@Test
public void testMarshallAndUnmarshall() throws IOException{
ByteSource bs = transformer.marshall(new TestObject("test"));
TestObject to = transformer.unmarshall(TestObject.class, bs);
assertEquals("test", to.value);
}
@Test(expected = ContentTransformerException.class)
public void testUnmarshallIOException() throws IOException{
ByteSource bs = mock(ByteSource.class);
when(bs.openBufferedStream()).thenThrow(IOException.class);
transformer.unmarshall(String.class, bs);
}
private static class TestObject2 {}
@XmlRootElement(name = "test")
@XmlAccessorType(XmlAccessType.FIELD)
private static class TestObject {
private String value;
public TestObject()
{
}
public TestObject(String value)
{
this.value = value;
}
}
}

View File

@@ -0,0 +1,95 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.resources;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.Matchers.*;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.plugin.PluginLoader;
/**
* Unit tests for {@link AbstractResourceManager}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class AbstractResourceManagerTest extends ResourceManagerTestBase
{
private DummyResourceManager resourceManager;
@Before
public void setUp()
{
Set<ResourceHandler> resourceHandlers = ImmutableSet.of(resourceHandler);
resourceManager = new DummyResourceManager(pluginLoader, resourceHandlers);
}
/**
* Test {@link AbstractResourceManager#getScriptResources()} in the correct order.
*
* @throws java.io.IOException
*
* @see <a href="https://goo.gl/ok03l4">Issue 809</a>
*/
@Test
public void testGetScriptResources() throws IOException
{
appendScriptResources("a/b.js", "z/a.js", "a/a.js");
List<String> scripts = resourceManager.getScriptResources();
assertThat(scripts, contains("a/a.js", "a/b.js", "z/a.js"));
}
private static class DummyResourceManager extends AbstractResourceManager
{
public DummyResourceManager(PluginLoader pluginLoader, Set<ResourceHandler> resourceHandlers)
{
super(pluginLoader, resourceHandlers);
}
@Override
protected void collectResources(Map<ResourceKey, Resource> resourceMap)
{
}
}
}

View File

@@ -0,0 +1,76 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.resources;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
/**
* Unit tests for {@link DefaultResourceManager}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultResourceManagerTest extends ResourceManagerTestBase {
private DefaultResourceManager resourceManager;
/**
* Set up {@link DefaultResourceManager} for tests.
*/
@Before
public void setUp()
{
Set<ResourceHandler> resourceHandlers = ImmutableSet.of(resourceHandler);
resourceManager = new DefaultResourceManager(pluginLoader, resourceHandlers);
}
/**
* Test {@link DefaultResourceManager#getResources(sonia.scm.resources.ResourceType)} method.
* @throws java.io.IOException
*/
@Test
public void testGetResources() throws IOException
{
appendScriptResources("a/b.js", "z/a.js", "a/a.js");
List<Resource> resources = resourceManager.getResources(ResourceType.SCRIPT);
assertEquals(1, resources.size());
}
}

View File

@@ -0,0 +1,112 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.resources;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContext;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
import sonia.scm.plugin.Plugin;
import sonia.scm.plugin.PluginCondition;
import sonia.scm.plugin.PluginInformation;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginResources;
import sonia.scm.plugin.PluginWrapper;
import sonia.scm.plugin.WebResourceLoader;
/**
* Base class for {@link ResourceManager} tests.
*
* @author Sebastian Sdorra
*/
public abstract class ResourceManagerTestBase
{
@Mock
protected ServletContext servletContext;
@Mock
protected PluginLoader pluginLoader;
@Mock
protected ResourceHandler resourceHandler;
@Mock
protected WebResourceLoader webResourceLoader;
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
/**
* Append scripts resources to plugin loader.
*
* @param resources resource names
*
* @throws IOException
*/
protected void appendScriptResources(String... resources) throws IOException
{
Set<String> scripts = Sets.newHashSet(resources);
Set<String> styles = Sets.newHashSet();
Set<String> dependencies = Sets.newHashSet();
Plugin plugin = new Plugin(
2,
new PluginInformation(),
new PluginResources(scripts, styles),
new PluginCondition(),
false,
dependencies
);
Path pluginPath = tempFolder.newFolder().toPath();
PluginWrapper wrapper = new PluginWrapper(
plugin,
Thread.currentThread().getContextClassLoader(),
webResourceLoader,
pluginPath
);
List<PluginWrapper> plugins = ImmutableList.of(wrapper);
when(pluginLoader.getInstalledPlugins()).thenReturn(plugins);
}
}

View File

@@ -0,0 +1,168 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.schedule;
import com.google.inject.Injector;
import com.google.inject.Provider;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import sonia.scm.web.security.AdministrationContext;
import sonia.scm.web.security.PrivilegedAction;
/**
* Unit tests for {@link InjectionEnabledJob}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class InjectionEnabledJobTest {
@Mock
private Injector injector;
@Mock
private JobDataMap dataMap;
@Mock
private JobDetail detail;
@Mock
private JobExecutionContext jec;
@Mock
private Provider<Runnable> runnable;
@Mock
private AdministrationContext context;
@Rule
public ExpectedException expected = ExpectedException.none();
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)} without context.
*
* @throws JobExecutionException
*/
@Test
public void testExecuteWithoutContext() throws JobExecutionException
{
expected.expect(NullPointerException.class);
expected.expectMessage("execution context");
new InjectionEnabledJob().execute(null);
}
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)} without job detail.
*
* @throws JobExecutionException
*/
@Test
public void testExecuteWithoutJobDetail() throws JobExecutionException
{
expected.expect(NullPointerException.class);
expected.expectMessage("detail");
new InjectionEnabledJob().execute(jec);
}
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)} without data map.
*
* @throws JobExecutionException
*/
@Test
public void testExecuteWithoutDataMap() throws JobExecutionException
{
when(jec.getJobDetail()).thenReturn(detail);
expected.expect(NullPointerException.class);
expected.expectMessage("data map");
new InjectionEnabledJob().execute(jec);
}
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)} without injector.
*
* @throws JobExecutionException
*/
@Test
public void testExecuteWithoutInjector() throws JobExecutionException
{
when(jec.getJobDetail()).thenReturn(detail);
when(detail.getJobDataMap()).thenReturn(dataMap);
expected.expect(NullPointerException.class);
expected.expectMessage("injector");
new InjectionEnabledJob().execute(jec);
}
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)} without runnable.
*
* @throws JobExecutionException
*/
@Test
public void testExecuteWithoutRunnable() throws JobExecutionException
{
when(jec.getJobDetail()).thenReturn(detail);
when(detail.getJobDataMap()).thenReturn(dataMap);
when(dataMap.get(Injector.class.getName())).thenReturn(injector);
expected.expect(JobExecutionException.class);
expected.expectMessage("runnable");
new InjectionEnabledJob().execute(jec);
}
/**
* Tests {@link InjectionEnabledJob#execute(org.quartz.JobExecutionContext)}.
*
* @throws JobExecutionException
*/
@Test
public void testExecute() throws JobExecutionException
{
when(jec.getJobDetail()).thenReturn(detail);
when(detail.getJobDataMap()).thenReturn(dataMap);
when(dataMap.get(Injector.class.getName())).thenReturn(injector);
when(dataMap.get(Runnable.class.getName())).thenReturn(runnable);
when(injector.getInstance(AdministrationContext.class)).thenReturn(context);
new InjectionEnabledJob().execute(jec);
verify(context).runAsAdmin(Mockito.any(PrivilegedAction.class));
}
}

View File

@@ -0,0 +1,220 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.schedule;
import com.google.inject.Injector;
import com.google.inject.Provider;
import java.io.IOException;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
/**
* Unit tests for {@link QuartzScheduler}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class QuartzSchedulerTest {
@Mock
private Injector injector;
@Mock
private org.quartz.Scheduler quartzScheduler;
private QuartzScheduler scheduler;
@Before
public void setUp()
{
scheduler = new QuartzScheduler(injector, quartzScheduler);
}
/**
* Tests {@link QuartzScheduler#schedule(java.lang.String, java.lang.Runnable)}.
*
* @throws SchedulerException
*/
@Test
public void testSchedule() throws SchedulerException
{
DummyRunnable dr = new DummyRunnable();
Task task = scheduler.schedule("42 2 * * * ?", dr);
assertNotNull(task);
ArgumentCaptor<JobDetail> detailCaptor = ArgumentCaptor.forClass(JobDetail.class);
ArgumentCaptor<Trigger> triggerCaptor = ArgumentCaptor.forClass(Trigger.class);
verify(quartzScheduler).scheduleJob(detailCaptor.capture(), triggerCaptor.capture());
Trigger trigger = triggerCaptor.getValue();
assertThat(trigger, is(instanceOf(CronTrigger.class)));
CronTrigger cron = (CronTrigger) trigger;
assertEquals("42 2 * * * ?", cron.getCronExpression());
JobDetail detail = detailCaptor.getValue();
assertEquals(InjectionEnabledJob.class, detail.getJobClass());
Provider<Runnable> runnable = (Provider<Runnable>) detail.getJobDataMap().get(Runnable.class.getName());
assertNotNull(runnable);
assertSame(dr, runnable.get());
assertEquals(injector, detail.getJobDataMap().get(Injector.class.getName()));
}
/**
* Tests {@link QuartzScheduler#schedule(java.lang.String, java.lang.Class)}.
*
* @throws SchedulerException
*/
@Test
public void testScheduleWithClass() throws SchedulerException
{
scheduler.schedule("42 * * * * ?", DummyRunnable.class);
verify(injector).getProvider(DummyRunnable.class);
ArgumentCaptor<JobDetail> detailCaptor = ArgumentCaptor.forClass(JobDetail.class);
ArgumentCaptor<Trigger> triggerCaptor = ArgumentCaptor.forClass(Trigger.class);
verify(quartzScheduler).scheduleJob(detailCaptor.capture(), triggerCaptor.capture());
Trigger trigger = triggerCaptor.getValue();
assertThat(trigger, is(instanceOf(CronTrigger.class)));
CronTrigger cron = (CronTrigger) trigger;
assertEquals("42 * * * * ?", cron.getCronExpression());
JobDetail detail = detailCaptor.getValue();
assertEquals(InjectionEnabledJob.class, detail.getJobClass());
assertEquals(injector, detail.getJobDataMap().get(Injector.class.getName()));
}
/**
* Tests {@link QuartzScheduler#init(sonia.scm.SCMContextProvider)}.
*
* @throws SchedulerException
*/
@Test
public void testInit() throws SchedulerException
{
when(quartzScheduler.isStarted()).thenReturn(Boolean.FALSE);
scheduler.init(null);
verify(quartzScheduler).start();
}
/**
* Tests {@link QuartzScheduler#init(sonia.scm.SCMContextProvider)} when the underlying scheduler is already started.
*
* @throws SchedulerException
*/
@Test
public void testInitAlreadyRunning() throws SchedulerException
{
when(quartzScheduler.isStarted()).thenReturn(Boolean.TRUE);
scheduler.init(null);
verify(quartzScheduler, never()).start();
}
/**
* Tests {@link QuartzScheduler#init(sonia.scm.SCMContextProvider)} when the underlying scheduler throws an exception.
*
* @throws SchedulerException
*/
@Test
public void testInitException() throws SchedulerException
{
when(quartzScheduler.isStarted()).thenThrow(SchedulerException.class);
scheduler.init(null);
verify(quartzScheduler, never()).start();
}
/**
* Tests {@link QuartzScheduler#close()}.
*
* @throws IOException
* @throws SchedulerException
*/
@Test
public void testClose() throws IOException, SchedulerException
{
when(quartzScheduler.isStarted()).thenReturn(Boolean.TRUE);
scheduler.close();
verify(quartzScheduler).shutdown();
}
/**
* Tests {@link QuartzScheduler#close()} when the underlying scheduler is not running.
*
* @throws IOException
* @throws SchedulerException
*/
@Test
public void testCloseNotRunning() throws IOException, SchedulerException
{
when(quartzScheduler.isStarted()).thenReturn(Boolean.FALSE);
scheduler.close();
verify(quartzScheduler, never()).shutdown();
}
/**
* Tests {@link QuartzScheduler#close()} when the underlying scheduler throws an exception.
*
* @throws IOException
* @throws SchedulerException
*/
@Test
public void testCloseException() throws IOException, SchedulerException
{
when(quartzScheduler.isStarted()).thenThrow(SchedulerException.class);
scheduler.close();
verify(quartzScheduler, never()).shutdown();
}
public static class DummyRunnable implements Runnable {
@Override
public void run()
{
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
}

View File

@@ -0,0 +1,89 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.schedule;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
/**
* Unit tests for {@link QuartzTask}.
*
* @author Sebastian Sdorra <sebastian.sdorra@triology.de>
*/
@RunWith(MockitoJUnitRunner.class)
public class QuartzTaskTest {
@Mock
private org.quartz.Scheduler scheduler;
private final JobKey jobKey = new JobKey("sample");
private QuartzTask task;
@Before
public void setUp(){
task = new QuartzTask(scheduler, jobKey);
}
/**
* Tests {@link QuartzTask#cancel()}.
*
* @throws SchedulerException
*/
@Test
public void testCancel() throws SchedulerException
{
task.cancel();
verify(scheduler).deleteJob(jobKey);
}
/**
* Tests {@link QuartzTask#cancel()} when the scheduler throws an exception.
* @throws org.quartz.SchedulerException
*/
@Test(expected = RuntimeException.class)
public void testCancelWithException() throws SchedulerException
{
when(scheduler.deleteJob(jobKey)).thenThrow(SchedulerException.class);
task.cancel();
}
}

View File

@@ -0,0 +1,401 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.HandlerEventType;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.group.Group;
import sonia.scm.group.GroupEvent;
import sonia.scm.group.GroupModificationEvent;
import sonia.scm.group.GroupNames;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryEvent;
import sonia.scm.repository.RepositoryModificationEvent;
import sonia.scm.repository.RepositoryTestData;
import sonia.scm.user.User;
import sonia.scm.user.UserEvent;
import sonia.scm.user.UserModificationEvent;
import sonia.scm.user.UserTestData;
/**
* Unit tests for {@link AuthorizationCollector}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultAuthorizationCollectorTest {
@Mock
private Cache cache;
@Mock
private CacheManager cacheManager;
@Mock
private RepositoryDAO repositoryDAO;
@Mock
private SecuritySystem securitySystem;
private DefaultAuthorizationCollector collector;
@Rule
public ShiroRule shiro = new ShiroRule();
/**
* Set up object to test.
*/
@Before
public void setUp(){
when(cacheManager.getCache(Mockito.any(String.class))).thenReturn(cache);
collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem);
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.user.UserEvent)}.
*/
@Test
public void testOnUserEvent()
{
User user = UserTestData.createDent();
collector.onEvent(new UserEvent(HandlerEventType.BEFORE_CREATE, user));
verify(cache, never()).clear();
collector.onEvent(new UserEvent(HandlerEventType.CREATE, user));
verify(cache).removeAll(Mockito.any(Predicate.class));
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.user.UserEvent)} with modified user.
*/
@Test
public void testOnUserModificationEvent()
{
User user = UserTestData.createDent();
User userModified = UserTestData.createDent();
userModified.setDisplayName("Super Dent");
collector.onEvent(new UserModificationEvent(HandlerEventType.BEFORE_CREATE, userModified, user));
verify(cache, never()).removeAll(Mockito.any(Predicate.class));
collector.onEvent(new UserModificationEvent(HandlerEventType.CREATE, userModified, user));
verify(cache, never()).removeAll(Mockito.any(Predicate.class));
userModified.setAdmin(true);
collector.onEvent(new UserModificationEvent(HandlerEventType.BEFORE_CREATE, userModified, user));
verify(cache, never()).removeAll(Mockito.any(Predicate.class));
collector.onEvent(new UserModificationEvent(HandlerEventType.CREATE, userModified, user));
verify(cache).removeAll(Mockito.any(Predicate.class));
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.group.GroupEvent)}.
*/
@Test
public void testOnGroupEvent()
{
Group group = new Group("xml", "base");
collector.onEvent(new GroupEvent(HandlerEventType.BEFORE_CREATE, group));
verify(cache, never()).clear();
collector.onEvent(new GroupEvent(HandlerEventType.CREATE, group));
verify(cache).clear();
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.group.GroupEvent)} with modified groups.
*/
@Test
public void testOnGroupModificationEvent()
{
Group group = new Group("xml", "base");
Group modifiedGroup = new Group("xml", "base");
collector.onEvent(new GroupModificationEvent(HandlerEventType.BEFORE_MODIFY, modifiedGroup, group));
verify(cache, never()).clear();
collector.onEvent(new GroupModificationEvent(HandlerEventType.MODIFY, modifiedGroup, group));
verify(cache, never()).clear();
modifiedGroup.add("test");
collector.onEvent(new GroupModificationEvent(HandlerEventType.MODIFY, modifiedGroup, group));
verify(cache).clear();
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)}.
*/
@Test
public void testOnRepositoryEvent()
{
Repository repository = RepositoryTestData.createHeartOfGold();
collector.onEvent(new RepositoryEvent(HandlerEventType.BEFORE_CREATE, repository));
verify(cache, never()).clear();
collector.onEvent(new RepositoryEvent(HandlerEventType.CREATE, repository));
verify(cache).clear();
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)} with modified repository.
*/
@Test
public void testOnRepositoryModificationEvent()
{
Repository repositoryModified = RepositoryTestData.createHeartOfGold();
repositoryModified.setName("test123");
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
Repository repository = RepositoryTestData.createHeartOfGold();
repository.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.BEFORE_CREATE, repositoryModified, repository));
verify(cache, never()).clear();
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
verify(cache, never()).clear();
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
verify(cache, never()).clear();
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test123")));
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
verify(cache).clear();
repositoryModified.setPermissions(
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.READ, true))
);
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
verify(cache, times(2)).clear();
repositoryModified.setPermissions(
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.WRITE))
);
collector.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
verify(cache, times(3)).clear();
}
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.security.StoredAssignedPermissionEvent)}.
*/
@Test
public void testOnStoredAssignedPermissionEvent()
{
StoredAssignedPermission groupPermission = new StoredAssignedPermission(
"123", new AssignedPermission("_authenticated", true, "repository:read:*")
);
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEventType.BEFORE_CREATE, groupPermission));
verify(cache, never()).clear();
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEventType.CREATE, groupPermission));
verify(cache).clear();
StoredAssignedPermission userPermission = new StoredAssignedPermission(
"123", new AssignedPermission("trillian", false, "repository:read:*")
);
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEventType.BEFORE_CREATE, userPermission));
verify(cache, never()).removeAll(Mockito.any(Predicate.class));
verify(cache).clear();
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEventType.CREATE, userPermission));
verify(cache).removeAll(Mockito.any(Predicate.class));
verify(cache).clear();
}
/**
* Tests {@link AuthorizationCollector#collect()} without user role.
*/
@Test
@SubjectAware
public void testCollectWithoutUserRole()
{
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), nullValue());
assertThat(authInfo.getStringPermissions(), nullValue());
assertThat(authInfo.getObjectPermissions(), nullValue());
}
/**
* Tests {@link AuthorizationCollector#collect()} from cache.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectFromCache()
{
AuthorizationInfo info = new SimpleAuthorizationInfo();
when(cache.get(anyObject())).thenReturn(info);
authenticate(UserTestData.createTrillian(), "main");
AuthorizationInfo authInfo = collector.collect();
assertSame(info, authInfo);
}
/**
* Tests {@link AuthorizationCollector#collect()} with cache.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectWithCache(){
authenticate(UserTestData.createTrillian(), "main");
AuthorizationInfo authInfo = collector.collect();
verify(cache).put(any(), any());
}
/**
* Tests {@link AuthorizationCollector#collect()} without permissions.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectWithoutPermissions()
{
authenticate(UserTestData.createTrillian(), "main");
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.contains(Role.USER));
assertThat(authInfo.getStringPermissions(), hasSize(0));
assertThat(authInfo.getObjectPermissions(), nullValue());
}
/**
* Tests {@link AuthorizationCollector#collect()} as admin.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectAsAdmin()
{
User trillian = UserTestData.createTrillian();
trillian.setAdmin(true);
authenticate(trillian, "main");
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER, Role.ADMIN));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), Matchers.contains("*"));
}
/**
* Tests {@link AuthorizationCollector#collect()} with repository permissions.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectWithRepositoryPermissions()
{
String group = "heart-of-gold-crew";
authenticate(UserTestData.createTrillian(), group);
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
heartOfGold.setId("one");
heartOfGold.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("trillian")));
Repository puzzle42 = RepositoryTestData.create42Puzzle();
puzzle42.setId("two");
sonia.scm.repository.Permission permission = new sonia.scm.repository.Permission(group, PermissionType.WRITE, true);
puzzle42.setPermissions(Lists.newArrayList(permission));
when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42));
// execute and assert
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("repository:read:one", "repository:read,write:two"));
}
/**
* Tests {@link AuthorizationCollector#collect()} with global permissions.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectWithGlobalPermissions(){
authenticate(UserTestData.createTrillian(), "main");
StoredAssignedPermission p1 = new StoredAssignedPermission("one", new AssignedPermission("one", "one:one"));
StoredAssignedPermission p2 = new StoredAssignedPermission("two", new AssignedPermission("two", "two:two"));
when(securitySystem.getPermissions(Mockito.any(Predicate.class))).thenReturn(Lists.newArrayList(p1, p2));
// execute and assert
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two"));
}
private void authenticate(User user, String group, String... groups)
{
SimplePrincipalCollection spc = new SimplePrincipalCollection();
spc.add(user.getName(), "unit");
spc.add(user, "unit");
spc.add(new GroupNames(group, groups), "unit");
Subject subject = new Subject.Builder().authenticated(true).principals(spc).buildSubject();
shiro.setSubject(subject);
}
}

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
/**
* Tests for the {@link XsrfCookies} util class.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class XsrfCookiesTest {
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
/**
* Prepare mocks for testing.
*/
@Before
public void prepareMocks(){
when(request.getContextPath()).thenReturn("/scm");
}
/**
* Tests create method.
*/
@Test
public void testCreate()
{
XsrfCookies.create(request, response, "mytoken");
// capture cookie
ArgumentCaptor<Cookie> captor = ArgumentCaptor.forClass(Cookie.class);
verify(response).addCookie(captor.capture());
// check for cookie
Cookie cookie = captor.getValue();
assertEquals(XsrfProtectionFilter.KEY, cookie.getName());
assertEquals("/scm", cookie.getPath());
assertEquals("mytoken", cookie.getValue());
}
/**
* Tests remove method.
*/
@Test
public void testRemove(){
Cookie cookie = new Cookie(XsrfProtectionFilter.KEY, "mytoken");
cookie.setMaxAge(15);
when(request.getCookies()).thenReturn(new Cookie[]{cookie});
XsrfCookies.remove(request, response);
// capture cookie
ArgumentCaptor<Cookie> captor = ArgumentCaptor.forClass(Cookie.class);
verify(response).addCookie(captor.capture());
// check the captured cookie
Cookie c = captor.getValue();
assertEquals("cookie max age should be set to 0", 0, c.getMaxAge());
assertEquals("cookie path should be equals", cookie.getPath(), c.getPath());
assertNull("cookie value shuld be null", c.getValue());
}
}

View File

@@ -0,0 +1,211 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.util.HttpUtil;
/**
* Unit tests for {@link XsrfProtectionFilter}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class XsrfProtectionFilterTest {
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private HttpSession session;
@Mock
private FilterChain chain;
private final ScmConfiguration configuration = new ScmConfiguration();
private final XsrfProtectionFilter filter = new XsrfProtectionFilter(configuration);
/**
* Prepare mocks for testing.
*/
@Before
public void setUp(){
when(request.getSession(true)).thenReturn(session);
when(request.getContextPath()).thenReturn("/scm");
configuration.setEnabledXsrfProtection(true);
}
/**
* Test filter method for non web interface clients.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterFromNonWuiClient() throws IOException, ServletException
{
filter.doFilter(request, response, chain);
verify(chain).doFilter(request, response);
}
/**
* Test filter method with disabled xsrf protection.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterWithDisabledXsrfProtection() throws IOException, ServletException
{
// disable xsrf protection
configuration.setEnabledXsrfProtection(false);
// set webui user-agent
when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI);
// call the filter
filter.doFilter(request, response, chain);
// verify that no xsrf other any other cookie was set
verify(response, never()).addCookie(Mockito.any(Cookie.class));
// ensure filter chain is called
verify(chain).doFilter(request, response);
}
/**
* Test filter method for first web interface request.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterIssuesTokenOnFirstWuiRequest() throws IOException, ServletException
{
when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI);
// call the filter
filter.doFilter(request, response, chain);
// capture cookie
ArgumentCaptor<Cookie> captor = ArgumentCaptor.forClass(Cookie.class);
verify(response).addCookie(captor.capture());
// check for cookie
Cookie cookie = captor.getValue();
assertEquals(XsrfProtectionFilter.KEY, cookie.getName());
assertEquals("/scm", cookie.getPath());
assertNotNull(cookie.getValue());
// ensure filter chain is called
verify(chain).doFilter(request, response);
}
/**
* Test filter method on protected session with an invalid xsrf token.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterWithInvalidToken() throws IOException, ServletException {
when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI);
when(request.getHeader(XsrfProtectionFilter.KEY)).thenReturn("invalidtoken");
when(session.getAttribute(XsrfProtectionFilter.KEY)).thenReturn("mytoken");
// call the filter
filter.doFilter(request, response, chain);
// ensure response send forbidden and the chain was never called
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
verify(chain, never()).doFilter(request, response);
}
/**
* Test filter method on protected session without xsrf token.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterOnProtectedSessionWithoutToken() throws IOException, ServletException {
when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI);
when(session.getAttribute(XsrfProtectionFilter.KEY)).thenReturn("mytoken");
// call the filter
filter.doFilter(request, response, chain);
// ensure response send forbidden and the chain was never called
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
verify(chain, never()).doFilter(request, response);
}
/**
* Test filter method on protected session with valid xsrf token.
*
* @throws IOException
* @throws ServletException
*/
@Test
public void testDoFilterOnProtectedSessionWithValidToken() throws IOException, ServletException {
when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI);
when(request.getHeader(XsrfProtectionFilter.KEY)).thenReturn("mytoken");
when(session.getAttribute(XsrfProtectionFilter.KEY)).thenReturn("mytoken");
// call the filter
filter.doFilter(request, response, chain);
// ensure chain was called
verify(chain).doFilter(request, response);
}
}

View File

@@ -34,25 +34,27 @@ package sonia.scm.selenium;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.selenium.page.Pages;
import sonia.scm.selenium.page.MainPage;
import sonia.scm.selenium.page.LoginPage;
import static org.junit.Assert.*;
import org.junit.Test;
/**
*
* Authentication related selenium integration tests.
*
* @author Sebastian Sdorra
*/
public class AuthenticationITCase extends SeleniumTestBase
{
public class AuthenticationITCase extends SeleniumITCaseBase {
/**
* Method description
*
*
* @throws Exception
* Authenticates an user and call logout function.
*/
@Test
public void testAuthentication() throws Exception
{
login("scmadmin", "scmadmin");
logout();
public void testAuthentication() {
MainPage main = Pages.get(driver, LoginPage.class).login("scmadmin", "scmadmin");
assertEquals("scmadmin", main.getUserInfo());
main.logout();
}
}

View File

@@ -34,61 +34,55 @@ package sonia.scm.selenium;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.selenium.page.Pages;
import sonia.scm.selenium.page.MainPage;
import sonia.scm.selenium.page.LoginPage;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import sonia.scm.repository.Repository;
/**
*
* Repository related selenium integration tests.
*
* @author Sebastian Sdorra
*/
public class RepositoryCRUDITCase extends SeleniumTestBase
{
public class RepositoriesITCase extends SeleniumITCaseBase {
private MainPage main;
/**
* Method description
*
*/
@After
public void after()
{
logout();
}
/**
* Method description
*
*/
@Test
public void createRepository() throws InterruptedException
{
waitAndClick("#repositoryAddButton");
waitForPresence("input[name=name]").sendKeys("scm");
select("#x-form-el-repositoryType img").click();
waitAndClick("div.x-combo-list-item:nth-of-type(2)");
type("input[name=contact]", "scmadmin@scm-manager.org");
type("textarea[name=description]", "SCM-Manager");
waitAndClick("div.x-panel-btns button:nth-of-type(1)");
String name =
waitForPresence(
"div.x-grid3-row-selected div.x-grid3-col-name").getText();
assertEquals("scm", name);
waitAndClick("#repoRmButton button");
waitAndClick("div.x-window button:nth-of-type(1)");
}
/**
* Method description
*
* Authenticates admin user, before each test.
*/
@Before
public void login()
{
login("scmadmin", "scmadmin");
public void login() {
main = Pages.get(driver, LoginPage.class)
.login("scmadmin", "scmadmin");
}
/**
* Creates, select and removes a repository.
*/
@Test
public void createRepository() {
Repository repository = new Repository();
repository.setName("scm");
repository.setType("git");
repository.setContact("scmadmin@scm-manager.org");
repository.setDescription("SCM-Manager");
main.repositories()
.add(repository)
.select(repository.getName())
.remove();
}
/**
* Logs the user out, after each test.
*/
@After
public void logout() {
main.logout();
}
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
/**
* Base class for selenium integration tests.
*
* @author Sebastian Sdorra
*/
public class SeleniumITCaseBase {
/**
* Selenium test driver.
*/
protected static WebDriver driver;
/**
* Setup selenium test driver.
*/
@BeforeClass
public static void setUpDriver() {
// DesiredCapabilities capa = DesiredCapabilities.chrome();
// capa.setBrowserName("firefox");
// capa.setPlatform(Platform.ANY);
// RemoteWebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capa);
driver = new FirefoxDriver();
driver.get("http://localhost:8082/scm/index.html");
}
/**
* Closes the selenium test driver.
*/
@AfterClass
public static void tearDownDriver() {
driver.close();
}
}

View File

@@ -1,271 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.Files;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
*
* @author Sebastian Sdorra
*/
public class SeleniumTestBase
{
/**
* the logger for SeleniumTestBase
*/
private static final Logger logger =
LoggerFactory.getLogger(SeleniumTestBase.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @throws Exception
*/
@After
public void tearDown() throws Exception
{
driver.quit();
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @throws Exception
*/
@Before
public void setUp() throws Exception
{
driver = new FirefoxDriver();
baseUrl = "http://localhost:8082/scm/";
open("index.html");
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param username
* @param password
*/
protected void login(String username, String password)
{
type("input[name=username]", username);
type("input[name=password]", password);
waitAndClick("#loginButton button");
String ue = waitForPresence("#scm-userinfo-tip").getText();
assertEquals(username, ue);
}
/**
* Method description
*
*/
protected void logout()
{
waitAndClick("#navLogout a");
}
/**
* Method description
*
*
* @param url
*/
protected void open(String url)
{
driver.get(baseUrl + url);
pause(500, TimeUnit.MILLISECONDS);
}
/**
* Method description
*
*
* @param value
* @param unit
*/
protected void pause(int value, TimeUnit unit)
{
driver.manage().timeouts().implicitlyWait(value, unit);
}
/**
* Method description
*
*
* @param target
*/
protected void screenshot(String target)
{
screenshot(new File(target));
}
/**
* Method description
*
*
* @param target
*/
protected void screenshot(File target)
{
try
{
File scrFile =
((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(scrFile, target);
}
catch (IOException ex)
{
logger.error("could not create screenshot", ex);
}
}
/**
* Method description
*
*
* @param cssSelector
*
* @return
*/
protected WebElement select(String cssSelector)
{
WebElement element = driver.findElement(By.cssSelector(cssSelector));
assertNotNull(element);
return element;
}
/**
* Method description
*
*
* @param cssLocator
* @param value
*/
protected void type(String cssLocator, String value)
{
select(cssLocator).clear();
select(cssLocator).sendKeys(value);
}
/**
* Method description
*
*
* @param query
*/
protected void waitAndClick(String query)
{
waitToBeClickable(query).click();
}
/**
* Method description
*
*
* @param query
*
* @return
*/
protected WebElement waitForPresence(String query)
{
WebDriverWait wait = new WebDriverWait(driver, 5);
return wait.until(
ExpectedConditions.presenceOfElementLocated(By.cssSelector(query)));
}
/**
* Method description
*
*
* @param query
*
* @return
*/
protected WebElement waitToBeClickable(String query)
{
WebDriverWait wait = new WebDriverWait(driver, 5);
return wait.until(
ExpectedConditions.elementToBeClickable(By.cssSelector(query)));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
protected WebDriver driver;
/** Field description */
private String baseUrl;
}

View File

@@ -0,0 +1,168 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import com.google.common.base.Throwables;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* Abstract selenium base page.
*
* @author Sebastian Sdorra
*
* @param <P> concrete page implementation
*/
public abstract class BasePage<P extends BasePage> {
/**
* Selenium test driver.
*/
protected final WebDriver driver;
/**
* Constructs a new base page.
*
* @param driver selenium test driver
*/
protected BasePage(WebDriver driver) {
this.driver = driver;
}
/**
* Performs a {@link Thread#sleep(long)} for the given timeout.
*
* @param time timeout
* @param unit time unit of timeout
*/
protected void sleep(long time, TimeUnit unit) {
try {
unit.sleep(time);
} catch (InterruptedException ex) {
throw Throwables.propagate(ex);
}
}
/**
* Wait for the element until it is clickable.
*
* @param by element selector
*
* @return web element
*/
protected WebElement waitToBeClickable(By by){
return waitToBeClickable(driver.findElement(by));
}
/**
* Waits for the element until it is clickable.
*
* @param element web element
*
* @return web element
*/
protected WebElement waitToBeClickable(WebElement element) {
WebDriverWait wait = new WebDriverWait(driver, 5);
return wait.until(ExpectedConditions.elementToBeClickable(element));
}
/**
* Waits until the element is present.
*
* @param by element locator
*
* @return web element
*/
protected WebElement waitFor(By by){
WebDriverWait wait = new WebDriverWait(driver, 1);
return wait.until(ExpectedConditions.presenceOfElementLocated(by));
}
/**
* Waits until the elements are present.
*
* @param by element selector
*
* @return list of web elements
*/
protected List<WebElement> waitForAll(By by){
WebDriverWait wait = new WebDriverWait(driver, 1);
return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by));
}
/**
* Creates a screenshot of the current browser content and stores it at the given path.
*
* @param target target file path
*
* @return {@code this}
*/
public P screenshot(String target) {
return screenshot(new File(target));
}
/**
* Creates a screenshot of the current browser content and stores it at the file.
*
* @param target target file
*
* @return {@code this}
*/
public P screenshot(File target) {
try {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(scrFile, target);
} catch (IOException ex) {
throw Throwables.propagate(ex);
}
return self();
}
/**
* Returns {@code this}.
*
* @return {@code this}
*/
protected abstract P self();
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* Page object for the scm-manager login page.
*
* @author Sebastian Sdorra
*/
public class LoginPage extends BasePage<LoginPage> {
@FindBy(css = "input[name=username]")
private WebElement usernameInput;
@FindBy(css = "input[name=password]")
private WebElement passwordInput;
@FindBy(css = "#loginButton button")
private WebElement loginButton;
/**
* Constructs a new page. This constructor should only be called from {@link Pages}.
*
* @param driver selenium test driver
*/
LoginPage(WebDriver driver) {
super(driver);
}
@Override
protected LoginPage self() {
return this;
}
/**
* Authenticates the user and returns the {@link MainPage}.
*
* @param username username
* @param password password
*
* @return {@link MainPage} after successful authentication
*/
public MainPage login(String username, String password) {
usernameInput.clear();
usernameInput.sendKeys(username);
passwordInput.clear();
passwordInput.sendKeys(password);
sleep(250, TimeUnit.MILLISECONDS);
waitToBeClickable(loginButton).click();
return Pages.get(driver, MainPage.class);
}
}

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* Page object for scm-manager's main page.
*
* @author Sebastian Sdorra
*/
public class MainPage extends BasePage<MainPage> {
@FindBy(css = "#navLogout a")
private WebElement logoutLink;
@FindBy(linkText = "Repositories")
private WebElement repositoriesLink;
@FindBy(css = "#scm-userinfo-tip")
private WebElement userInfoTip;
/**
* Constructs a new page. This constructor should only be called from {@link Pages}.
*
* @param driver selenium test driver
*/
MainPage(WebDriver driver) {
super(driver);
}
@Override
protected MainPage self() {
return this;
}
/**
* Returns the name of the current authenticated user from the user info tip.
*
* @return name of the current authenticated user
*/
public String getUserInfo(){
return userInfoTip.getText();
}
/**
* Navigates to the repositories page and returns the page object for this page.
*
* @return page object for repositories page
*/
public RepositoriesPage repositories(){
repositoriesLink.click();
return Pages.get(driver, RepositoriesPage.class);
}
/**
* Logs the current user out.
*
* @return page object for the login
*/
public LoginPage logout(){
waitToBeClickable(logoutLink).click();
return Pages.get(driver, LoginPage.class);
}
}

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* Helper class for selenium page objects.
*
* @author Sebastian Sdorra
*/
public final class Pages {
private Pages() {
}
/**
* Creates an instance of the given page object.
*
* @param <T> page object type
* @param driver selenium driver
* @param clazz page object type
* @param otherArguments other constructor arguments
*
* @return instance of page object
*/
public static <T extends BasePage> T get(WebDriver driver, Class<T> clazz, Object... otherArguments)
{
T page = null;
try {
List<Class<?>> argumentTypes = Lists.newArrayList();
argumentTypes.add(WebDriver.class);
for (Object argument : otherArguments) {
argumentTypes.add(argument.getClass());
}
List<Object> arguments = Lists.newArrayList();
arguments.add(driver);
arguments.addAll(Arrays.asList(otherArguments));
Constructor<T> constructor = clazz.getDeclaredConstructor(
argumentTypes.toArray(new Class<?>[argumentTypes.size()])
);
page = constructor.newInstance(arguments.toArray(new Object[arguments.size()]));
PageFactory.initElements(new DefaultElementLocatorFactory(new WaitingSearchContext(driver)), page);
} catch (Exception ex) {
throw Throwables.propagate(ex);
}
return page;
}
private static class WaitingSearchContext implements SearchContext {
private final WebDriver driver;
private final WebDriverWait wait;
private WaitingSearchContext(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, 1);
}
@Override
public List<WebElement> findElements(By by) {
return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by));
}
@Override
public WebElement findElement(By by) {
return wait.until(ExpectedConditions.presenceOfElementLocated(by));
}
}
}

View File

@@ -0,0 +1,136 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import com.google.common.base.Objects;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.WebDriverWait;
import sonia.scm.repository.Repository;
/**
* Page object for scm-manager's repository creation page.
*
* @author Sebastian Sdorra
*/
public class RepositoriesAddPage extends BasePage<RepositoriesAddPage> {
@FindBy(css = "input[name=name]")
private WebElement nameInput;
@FindBy(css = "input[name=contact]")
private WebElement contactInput;
@FindBy(css = "#x-form-el-repositoryType img")
private WebElement typeInput;
@FindBy(css = "textarea[name=description]")
private WebElement descriptionInput;
@FindBy(css = "div.x-panel-btns button:nth-of-type(1)")
private WebElement okButton;
private final RepositoriesPage repositoriesPage;
/**
* Constructs a new page. This constructor should only be called from {@link Pages}.
*
* @param driver selenium test driver
* @param repositoriesPage repositories page object
*/
RepositoriesAddPage(WebDriver driver, RepositoriesPage repositoriesPage) {
super(driver);
this.repositoriesPage = repositoriesPage;
}
@Override
protected RepositoriesAddPage self() {
return this;
}
/**
* Creates a new {@link Repository}.
*
* @param repository repository for creation
*
* @return repositories overview page
*/
public RepositoriesPage add(Repository repository) {
nameInput.sendKeys(repository.getName());
selectType(repository.getType());
contactInput.sendKeys(repository.getContact());
descriptionInput.sendKeys(repository.getDescription());
waitToBeClickable(okButton).click();
return repositoriesPage;
}
private void selectType(String type) {
typeInput.click();
String displayName = findDisplayName(type);
WebDriverWait wait = new WebDriverWait(driver, 1);
List<WebElement> elements = waitForAll(By.className("x-combo-list-item"));
WebElement typeElement = null;
for (WebElement te : elements){
if (te.getText().trim().equalsIgnoreCase(displayName)){
typeElement = te;
break;
}
}
if (typeElement == null){
throw new NotFoundException("could not find type element with type " + displayName);
}
typeElement.click();
}
private String findDisplayName(String type) {
String displayName = null;
if (driver instanceof JavascriptExecutor) {
// TODO seams not to work
String script = "Sonia.repository.getTypeByName('" + type + "').displayName;";
displayName = (String) ((JavascriptExecutor)driver).executeScript(script);
}
return Objects.firstNonNull(displayName, type);
}
}

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import java.util.List;
import java.util.Locale;
import org.openqa.selenium.By;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import sonia.scm.repository.Repository;
/**
* Page object for scm-manager's repositories overview page.
*
* @author Sebastian Sdorra
*/
public class RepositoriesPage extends BasePage<RepositoriesPage> {
@FindBy(id = "repositoryAddButton")
private WebElement addButton;
/**
* Constructs a new page. This constructor should only be called from {@link Pages}.
*
* @param driver selenium test driver
*/
RepositoriesPage(WebDriver driver) {
super(driver);
}
@Override
protected RepositoriesPage self() {
return this;
}
/**
* Creates a new {@link Repository}.
*
* @param repository repository for creation
*
* @return {@link this}
*/
public RepositoriesPage add(Repository repository){
addButton.click();
RepositoriesAddPage addPage = Pages.get(driver, RepositoriesAddPage.class, this);
return addPage.add(repository);
}
/**
* Selects the repository with the given name and returns the detail page object for the selected repository.
*
* @param repositoryName name of the repository
*
* @return page object for selected repository
*/
public RepositoryPage select(String repositoryName){
WebElement repositoryNameColumn = null;
List<WebElement> elements = waitForAll(By.className("x-grid3-col-name"));
for (WebElement element : elements){
if (element.getText().trim().toLowerCase(Locale.ENGLISH).equals(repositoryName)){
repositoryNameColumn = element;
break;
}
}
if ( repositoryNameColumn == null ) {
throw new NotFoundException("could not find repository " + repositoryName);
}
return Pages.get(driver, RepositoryPage.class, this);
}
}

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.selenium.page;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* Page object for scm-manager's repository detail page.
*
* @author Sebastian Sdorra
*/
public class RepositoryPage extends BasePage<RepositoryPage> {
@FindBy(css = "#repoRmButton button")
private WebElement removeButton;
private final RepositoriesPage repositoriesPage;
/**
* Constructs a new page. This constructor should only be called from {@link Pages}.
*
* @param driver selenium test driver
* @param repositoriesPage repositories page object
*/
RepositoryPage(WebDriver driver, RepositoriesPage repositoriesPage) {
super(driver);
this.repositoriesPage = repositoriesPage;
}
@Override
protected RepositoryPage self() {
return this;
}
/**
* Removes the selected repository.
*
* @return repositories overview page object
*/
public RepositoriesPage remove(){
removeButton.click();
waitToBeClickable(By.cssSelector("div.x-window button:nth-of-type(1)")).click();
return repositoriesPage;
}
}

View File

@@ -55,13 +55,25 @@ import static org.mockito.Mockito.*;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
/**
*
* TODO add test with {@link UserAgentParser}.
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class BasicWebTokenGeneratorTest
{
/**
* Set up object under test.
* Use {@code null} as {@link UserAgentParser}.
*/
@Before
public void setUpObjectUnderTest() {
generator = new BasicWebTokenGenerator(null);
}
/**
* Method description
@@ -132,10 +144,9 @@ public class BasicWebTokenGeneratorTest
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final BasicWebTokenGenerator generator = new BasicWebTokenGenerator();
private BasicWebTokenGenerator generator;
/** Field description */
@Mock
private HttpServletRequest request;

View File

@@ -0,0 +1,114 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import org.junit.Test;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.Locale;
/**
*
* @author Sebastian Sdorra <sebastian.sdorra@triology.de>
*/
public class BrowserUserAgentProviderTest
{
/** Field description */
private static final String CHROME =
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36";
/** Field description */
private static final String FIREFOX =
"Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.8.1.18) Gecko/20081029 Firefox/2.0.0.18";
/** Field description */
private static final String MSIE =
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; )";
/** Field description */
private static final String OPERA =
"Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00";
/** Field description */
private static final String SAFARI =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/6.1.3 Safari/537.75.14";
/** Field description */
private static final String WGET = "Wget/1.5.3";
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Test
public void testParseUserAgent()
{
assertEquals(BrowserUserAgentProvider.MSIE, parse(MSIE));
assertEquals(BrowserUserAgentProvider.FIREFOX, parse(FIREFOX));
assertEquals(BrowserUserAgentProvider.OPERA, parse(OPERA));
assertEquals(BrowserUserAgentProvider.CHROME, parse(CHROME));
assertEquals(BrowserUserAgentProvider.SAFARI, parse(SAFARI));
assertNull(parse(WGET));
}
/**
* Method description
*
*
* @param v
*
* @return
*/
private UserAgent parse(String v)
{
return provider.parseUserAgent(
Strings.nullToEmpty(v).toLowerCase(Locale.ENGLISH));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final BrowserUserAgentProvider provider =
new BrowserUserAgentProvider();
}