| /******************************************************************************* |
| * Copyright (c) 2010-2014 SAP AG and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * SAP AG - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.skalli.gerrit.client.internal; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import java.io.File; |
| import java.lang.reflect.Method; |
| import java.text.MessageFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.eclipse.skalli.gerrit.client.GerritClient; |
| import org.eclipse.skalli.gerrit.client.GerritFeature; |
| import org.eclipse.skalli.gerrit.client.GerritVersion; |
| import org.eclipse.skalli.gerrit.client.InheritableBoolean; |
| import org.eclipse.skalli.gerrit.client.ProjectOptions; |
| import org.eclipse.skalli.gerrit.client.SubmitType; |
| import org.eclipse.skalli.gerrit.client.config.GerritServerConfig; |
| import org.eclipse.skalli.gerrit.client.exception.CommandException; |
| import org.eclipse.skalli.gerrit.client.exception.ConnectionException; |
| import org.eclipse.skalli.gerrit.client.exception.GerritClientException; |
| import org.eclipse.skalli.gerrit.client.internal.GSQL.ResultFormat; |
| import org.junit.After; |
| import org.junit.AfterClass; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @SuppressWarnings("nls") |
| public class GerritClientTest { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(GerritClientTest.class); |
| private static final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.ENGLISH); |
| |
| // DO NOT CONFIGURE A PRODUCTIVE GERRIT - the test case created a huge amount of projects and |
| // groups that cannot be removed easily. |
| private static String TEST_HOST = null; |
| private static String TEST_ACCOUNT = null; |
| private static String TEST_PORT = "8080"; |
| private static String TEST_PRIVATEKEY = null; |
| private static String TEST_PASSPHRASE = null; |
| private static String TEST_VERSION = null; |
| private static final String TEST_ONBEHALFOF = "userId"; |
| |
| // DO NOT MODIFY THIS DESCRIPTION - it is used in the clean up step to figure out which projects |
| // and groups have been created. |
| private static final String DESCRIPTION = "Generated by jUnit"; |
| |
| private GerritClientImpl client; |
| |
| @BeforeClass |
| public static void setUpOnce() throws Exception { |
| TEST_HOST = System.getProperty("testHost"); |
| String port = System.getProperty("testPort"); |
| TEST_PORT = port != null ? port : TEST_PORT; |
| TEST_VERSION = System.getProperty("testVersion"); |
| TEST_ACCOUNT = System.getProperty("testAccount"); |
| TEST_PRIVATEKEY = System.getProperty("testPrivateKey"); |
| String privateKeyFile = System.getProperty("testPrivateKeyFile"); |
| TEST_PRIVATEKEY = FileUtils.readFileToString(new File(privateKeyFile)); |
| TEST_PASSPHRASE = System.getProperty("testPassphrase"); |
| } |
| |
| @AfterClass |
| public static void tearDownOnce() throws Exception { |
| // clean up and delete all groups + projects that still exist |
| EvilGerritClient evilClient = new EvilGerritClient(getGerritConfig(), TEST_ONBEHALFOF); |
| evilClient.connect(); |
| |
| /* |
| * Deleting groups and clean up. Added WHERE clause that should avoid deleting system groups accidentally |
| */ |
| final StringBuffer deleteGroupsQueries = new StringBuffer(); |
| deleteGroupsQueries.append("DELETE FROM ").append(GSQL.Tables.ACCOUNT_GROUPS); |
| deleteGroupsQueries.append(" WHERE description = '").append(DESCRIPTION).append("'"); |
| deleteGroupsQueries.append(" AND group_id NOT IN (SELECT admin_group_id FROM ") |
| .append(GSQL.Tables.SYSTEM_CONFIG).append(")"); |
| deleteGroupsQueries.append(" AND group_id NOT IN (SELECT anonymous_group_id FROM ") |
| .append(GSQL.Tables.SYSTEM_CONFIG).append(")"); |
| deleteGroupsQueries.append(" AND group_id NOT IN (SELECT registered_group_id FROM ") |
| .append(GSQL.Tables.SYSTEM_CONFIG).append(")"); |
| deleteGroupsQueries.append(" AND group_id NOT IN (SELECT batch_users_group_id FROM ") |
| .append(GSQL.Tables.SYSTEM_CONFIG).append(");"); |
| // clean up |
| deleteGroupsQueries.append("DELETE FROM ").append(GSQL.Tables.ACCOUNT_GROUP_NAMES) |
| .append(" WHERE group_id NOT IN (SELECT group_id FROM ").append(GSQL.Tables.ACCOUNT_GROUPS) |
| .append(");"); |
| deleteGroupsQueries.append("DELETE FROM ").append(GSQL.Tables.ACCOUNT_GROUP_MEMBERS) |
| .append(" WHERE group_id NOT IN (SELECT group_id FROM ").append(GSQL.Tables.ACCOUNT_GROUPS) |
| .append(");"); |
| deleteGroupsQueries.append("DELETE FROM ").append(GSQL.Tables.ACCOUNT_GROUP_MEMBERS_AUDIT) |
| .append(" WHERE group_id NOT IN (SELECT group_id FROM ").append(GSQL.Tables.ACCOUNT_GROUPS) |
| .append(");"); |
| evilClient.gsql(deleteGroupsQueries.toString(), GSQL.ResultFormat.PRETTY); |
| |
| /* |
| * Deleting projects and clean up according to: |
| * http://groups.google.com/group/repo-discuss/browse_thread/thread/9fa2f8978d422709?fwc=1 |
| * |
| * Note: This does not clean up on file system. |
| * So creating a project w/ the same name again won't work. |
| * Hence the test cases always use project names with a timestamp. |
| */ |
| final StringBuffer deleteProjectsQueries = new StringBuffer(); |
| deleteProjectsQueries.append("DELETE FROM ") |
| .append(GSQL.Tables.PROJECTS).append(" WHERE description = '") |
| .append(DESCRIPTION).append("';"); |
| // clean up |
| deleteProjectsQueries.append("DELETE FROM ").append(GSQL.Tables.REF_RIGHTS) |
| .append(" WHERE project_name NOT IN (SELECT name FROM ").append(GSQL.Tables.PROJECTS).append(");"); |
| evilClient.gsql(deleteProjectsQueries.toString(), ResultFormat.PRETTY); |
| |
| evilClient.disconnect(); |
| } |
| |
| @Before |
| public void setup() throws Exception { |
| client = new GerritClientImpl(getGerritConfig(), TEST_ONBEHALFOF); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| if (client != null) { |
| client.disconnect(); |
| } |
| } |
| |
| private static GerritServerConfig getGerritConfig() { |
| GerritServerConfig gerritConfig = new GerritServerConfig(); |
| gerritConfig.setHost(TEST_HOST); |
| gerritConfig.setPort(TEST_PORT); |
| gerritConfig.setUser(TEST_ACCOUNT); |
| gerritConfig.setPrivateKey(TEST_PRIVATEKEY); |
| gerritConfig.setPassphrase(TEST_PASSPHRASE); |
| return gerritConfig; |
| } |
| |
| @Test |
| public void testGetVersion() throws Exception { |
| Assert.assertEquals(GerritVersion.asGerritVersion(TEST_VERSION), client.getVersion()); |
| } |
| |
| @Test |
| public void testGroupExists() throws Exception { |
| final String name = generateName("g"); |
| |
| Assert.assertFalse(client.groupExists(name)); |
| client.createGroup(name, null, DESCRIPTION, null); |
| Assert.assertTrue(client.groupExists(name)); |
| } |
| |
| @Test |
| public void testProjectExists() throws Exception { |
| final String name = generateName("p"); |
| Assert.assertFalse(client.projectExists(name)); |
| client.createProject(name, null, null, null, false, DESCRIPTION, null, false, false, true); |
| Assert.assertTrue(client.projectExists(name)); |
| } |
| |
| @Test |
| public void testCreateGroup() throws Exception { |
| final String name = generateName("g"); |
| |
| Assert.assertFalse(client.groupExists(name)); |
| client.createGroup(name, null, DESCRIPTION, null); |
| Assert.assertTrue(client.groupExists(name)); |
| } |
| |
| @Test(expected = CommandException.class) |
| public void testCreateGroupTwice() throws Exception { |
| final String name = generateName("g"); |
| |
| client.createGroup(name, null, DESCRIPTION, null); |
| client.createGroup(name, null, DESCRIPTION, null); |
| } |
| |
| @Test |
| public void testCreateProject() throws Exception { |
| final String name = generateName("p"); |
| |
| Assert.assertFalse(client.projectExists(name)); |
| client.createProject(name, null, null, null, false, DESCRIPTION, null, false, false, true); |
| Assert.assertTrue(client.projectExists(name)); |
| } |
| |
| @Test |
| public void testSshCreateProject() throws Exception { |
| final String name = generateName("p"); |
| ProjectOptions options = new ProjectOptions(); |
| options.setName(name); |
| options.setBranches(Arrays.asList("foo", "bar")); |
| options.setOwners(Arrays.asList("c", "a", "b")); |
| options.setParent("foo bar"); |
| options.setPermissionsOnly(true); |
| options.setDescription("test project"); |
| options.setSubmitType(SubmitType.REBASE_IF_NECESSARY); |
| options.setUseContributorAgreements(InheritableBoolean.TRUE); |
| options.setUseSignedOffBy(InheritableBoolean.TRUE); |
| options.setRequiredChangeId(InheritableBoolean.TRUE); |
| options.setUseContentMerge(InheritableBoolean.TRUE); |
| options.setCreateEmptyCommit(true); |
| options.setMaxObjectSizeLimit("1m"); |
| options.putPluginConfig("x", "c", "d"); |
| options.putPluginConfig("y", "a", "d"); |
| options.putPluginConfig("x", "a", "b"); |
| assertEquals(getExpectedSshCreateProject(name, GerritVersion.GERRIT_2_7_X), |
| client.sshCreateProject(options, GerritVersion.GERRIT_2_7_X)); |
| assertEquals(getExpectedSshCreateProject(name, GerritVersion.GERRIT_2_8_X), |
| client.sshCreateProject(options, GerritVersion.GERRIT_2_8_X)); |
| assertEquals(getExpectedSshCreateProject(name, GerritVersion.GERRIT_2_9_X), |
| client.sshCreateProject(options, GerritVersion.GERRIT_2_9_X)); |
| } |
| |
| private String getExpectedSshCreateProject(String name, GerritVersion version) { |
| StringBuilder sb = new StringBuilder( |
| "gerrit create-project" |
| + " --name \"" + name + "\"" |
| + " --branch \"bar\" --branch \"foo\"" //sorted! |
| + " --owner \"a\" --owner \"b\" --owner \"c\"" //sorted! |
| + " --parent \"foo bar\"" |
| + " --permissions-only" |
| + " --description \"test project\"" |
| + " --submit-type \"REBASE_IF_NECESSARY\"" |
| + " --use-contributor-agreements" |
| + " --use-signed-off-by" |
| + " --require-change-id" |
| + " --use-content-merge" |
| + " --empty-commit"); |
| if (version.compareTo(GerritVersion.GERRIT_2_8_X) >=0 ) { |
| sb.append(" --max-object-size-limit \"1m\""); |
| } |
| if (version.compareTo(GerritVersion.GERRIT_2_9_X) >= 0) { |
| sb.append( |
| " --plugin-config \"x.a=b\"" //sorted by plugin name and property names |
| + " --plugin-config \"x.c=d\"" |
| + " --plugin-config \"y.a=d\""); |
| } |
| return sb.toString(); |
| } |
| |
| @Test(expected = CommandException.class) |
| public void testCreateProjectTwice() throws Exception { |
| final String name = generateName("p"); |
| |
| client.createProject(name, null, null, null, false, DESCRIPTION, null, false, false, true); |
| client.createProject(name, null, null, null, false, DESCRIPTION, null, false, false, true); |
| } |
| |
| @Test |
| public void testGetProjects() throws Exception { |
| Assert.assertNotNull(client.getProjects()); |
| } |
| |
| @Test |
| public void testGetGroups() throws Exception { |
| Assert.assertNotNull(client.getGroups()); |
| } |
| |
| @Test |
| public void testGetGroupsForProject() throws Exception { |
| final String g1 = generateName("g1"); |
| final String g2 = generateName("g2"); |
| final String g3 = generateName("g3"); |
| |
| final String p1 = generateName("p1"); |
| final String p2 = generateName("p2"); |
| |
| client.createGroup(g1, null, DESCRIPTION, null); |
| client.createGroup(g2, null, DESCRIPTION, null); |
| client.createGroup(g3, null, DESCRIPTION, null); |
| |
| client.createProject(p1, null, new HashSet<String>(Arrays.asList(g1, g2)), null, false, |
| DESCRIPTION, null, false, false, true); |
| client.createProject(p2, null, new HashSet<String>(Arrays.asList(g2, g3)), null, false, |
| DESCRIPTION, null, false, false, true); |
| |
| List<String> groupsForP1 = client.getGroups(p1); |
| Assert.assertTrue(groupsForP1.contains(g1)); |
| Assert.assertTrue(groupsForP1.contains(g2)); |
| Assert.assertFalse(groupsForP1.contains(g3)); |
| |
| List<String> groupsForP2 = client.getGroups(p2); |
| Assert.assertFalse(groupsForP2.contains(g1)); |
| Assert.assertTrue(groupsForP2.contains(g2)); |
| Assert.assertTrue(groupsForP2.contains(g3)); |
| } |
| |
| @Test |
| public void testGetGroupsForProjects() throws Exception { |
| final String g1 = generateName("g1"); |
| final String g2 = generateName("g2"); |
| final String g3 = generateName("g3"); |
| |
| final String p1 = generateName("p1"); |
| final String p2 = generateName("p2"); |
| |
| client.createGroup(g1, null, DESCRIPTION, null); |
| client.createGroup(g2, null, DESCRIPTION, null); |
| client.createGroup(g3, null, DESCRIPTION, null); |
| |
| client.createProject(p1, null, new HashSet<String>(Arrays.asList(g1)), null, false, DESCRIPTION, |
| null, false, false, true); |
| client.createProject(p2, null, new HashSet<String>(Arrays.asList(g2)), null, false, DESCRIPTION, |
| null, false, false, true); |
| |
| List<String> groupsForP1 = client.getGroups(p1, p2); |
| Assert.assertTrue(groupsForP1.contains(g1)); |
| Assert.assertTrue(groupsForP1.contains(g2)); |
| Assert.assertFalse(groupsForP1.contains(g3)); |
| } |
| |
| @Test |
| public void testInvalidProjectNames() throws Exception { |
| String[] invalidProjectNames = new String[] { null, "", " ", "/", "/project", "project/", "my project", |
| " project", "project ", "pro\0ject", "my\tproject", "../project", "<project>", "my/../project", |
| "my/./project", "pro\\ject", "pro:ject", "pro~ject", "pro?ject", "pro*ject", "pro<ject", |
| "pro>ject", "pro|ject", "pro%ject", "pro\"ject" }; |
| for (String invalidProjectName : invalidProjectNames) { |
| Assert.assertNotNull(client.checkProjectName(invalidProjectName)); |
| try { |
| client.createProject(invalidProjectName, null, null, null, false, |
| DESCRIPTION, null, false, false, true); |
| Assert.fail(String.format("No error for project name '%s'.", invalidProjectName)); |
| } catch (GerritClientException e) { |
| LOG.debug(MessageFormat.format("'{0}' is identified as an invalid project name.", invalidProjectName)); |
| } catch (IllegalArgumentException e) { |
| LOG.debug(MessageFormat.format("'{0}' is identified as an invalid project name.", invalidProjectName)); |
| } |
| } |
| } |
| |
| @Test |
| public void testInvalidGroupNames() throws Exception { |
| String[] invalidGroupNames = new String[] { null, "", " ", " a", "b ", "\ta", "b\t", "a\tb", "<b>html</b>" }; |
| for (String invalidGroupName : invalidGroupNames) { |
| Assert.assertNotNull(client.checkGroupName(invalidGroupName)); |
| try { |
| client.createGroup(invalidGroupName, null, DESCRIPTION, null); |
| Assert.fail(String.format("No error for group name '%s'.", invalidGroupName)); |
| } catch (GerritClientException e) { |
| LOG.debug(MessageFormat.format("'{0}' is identified as an invalid group name.", invalidGroupName)); |
| } catch (IllegalArgumentException e) { |
| LOG.debug(MessageFormat.format("'{0}' is identified as an invalid group name.", invalidGroupName)); |
| } |
| } |
| } |
| |
| @Test |
| public void testGetKnownAccounts() throws Exception { |
| String unknownAccount = System.currentTimeMillis() + ""; |
| Set<String> variousAccounts = new HashSet<String>(Arrays.asList(TEST_ACCOUNT, "", null, unknownAccount)); |
| Set<String> knownAccounts = client.getKnownAccounts(variousAccounts); |
| |
| GerritVersion version = GerritVersion.asGerritVersion(TEST_VERSION); |
| if (version.supports(GerritFeature.ACCOUNT_CHECK_OBSOLETE)) { |
| Assert.assertEquals(2, knownAccounts.size()); |
| Assert.assertTrue(knownAccounts.contains(TEST_ACCOUNT)); |
| Assert.assertTrue(knownAccounts.contains(unknownAccount)); |
| } else { |
| Assert.assertEquals(1, knownAccounts.size()); |
| Assert.assertTrue(knownAccounts.contains(TEST_ACCOUNT)); |
| Assert.assertFalse(knownAccounts.contains(unknownAccount)); |
| } |
| } |
| |
| @Test |
| public void testGetKnownAccountsEmpty() throws Exception { |
| Set<String> knownAccounts = client.getKnownAccounts(Collections.<String> emptySet()); |
| Assert.assertEquals(0, knownAccounts.size()); |
| } |
| |
| @Test |
| public void testALotOfUnknownAccounts() throws Exception { |
| Set<String> variousAccounts = new HashSet<String>(); |
| // don't use an even number. challenge the system :) |
| for (int i = 0; i < 123; i++) { |
| String unknownAccount = System.currentTimeMillis() + "_" + i; |
| variousAccounts.add(unknownAccount); |
| } |
| variousAccounts.add(TEST_ACCOUNT); |
| |
| Set<String> knownAccounts = client.getKnownAccounts(variousAccounts); |
| GerritVersion version = GerritVersion.asGerritVersion(TEST_VERSION); |
| if (version.supports(GerritFeature.ACCOUNT_CHECK_OBSOLETE)) { |
| Assert.assertEquals(variousAccounts.size(), knownAccounts.size()); |
| } else { |
| Assert.assertEquals(1, knownAccounts.size()); |
| } |
| } |
| |
| @Test(expected = ConnectionException.class) |
| public void testInvalidSettingsHost() throws Exception { |
| GerritServerConfig gerritConfig = getGerritConfig(); |
| gerritConfig.setHost("some.host.corp"); |
| GerritClient invalidClient = new GerritClientImpl(gerritConfig, TEST_ONBEHALFOF); |
| invalidClient.connect(); |
| } |
| |
| @Test(expected = ConnectionException.class) |
| public void testInvalidSettingsPort() throws Exception { |
| GerritServerConfig gerritConfig = getGerritConfig(); |
| gerritConfig.setHost("50000"); |
| GerritClient invalidClient = new GerritClientImpl(gerritConfig, TEST_ONBEHALFOF); |
| invalidClient.connect(); |
| } |
| |
| @Test(expected = ConnectionException.class) |
| public void testInvalidSettingsUser() throws Exception { |
| GerritServerConfig gerritConfig = getGerritConfig(); |
| gerritConfig.setUser("LoremIpsum"); |
| GerritClient invalidClient = new GerritClientImpl(gerritConfig, TEST_ONBEHALFOF); |
| invalidClient.connect(); |
| } |
| |
| @Test(expected = ConnectionException.class) |
| public void testInvalidSettingsPrivateKey() throws Exception { |
| GerritServerConfig gerritConfig = getGerritConfig(); |
| gerritConfig.setPrivateKey("foobar"); |
| GerritClient invalidClient = new GerritClientImpl(gerritConfig, TEST_ONBEHALFOF); |
| invalidClient.connect(); |
| } |
| |
| @Test(expected = ConnectionException.class) |
| public void testInvalidSettingsPassphrase() throws Exception { |
| GerritServerConfig gerritConfig = getGerritConfig(); |
| gerritConfig.setPassphrase("foobar"); |
| GerritClient invalidClient = new GerritClientImpl(gerritConfig, TEST_ONBEHALFOF); |
| invalidClient.connect(); |
| } |
| |
| @Test |
| public void testUnsupportedGSQLCommands() throws Exception { |
| String[] invalidCommands = new String[] { "show", "insert", "update", "delete", "merge", "create", "alter", |
| "rename", "truncate", "drop" }; |
| for (String invalidCommand : invalidCommands) { |
| try { |
| client.gsql("SELECT * FROM unknown_table_xyz;" + invalidCommand + " bla bla", GSQL.ResultFormat.JSON); |
| } catch (UnsupportedOperationException e) { |
| continue; |
| } |
| Assert.fail("Command '" + invalidCommand + "' should not work on gsql(), but was not detected."); |
| } |
| } |
| |
| /** |
| * Due to the fact that project names can only be used once (won't be deleted from Git) we |
| * generate new names for each run. |
| * |
| * @param prefix a fixed prefix |
| * @return a random name (using the date & time) starting with the fixed prefix |
| */ |
| private static String generateName(String name) { |
| return "junit/" + df.format(new Date()) + "/" + name; |
| } |
| |
| /** |
| * YOU MUST NOT USE THIS ON PRODUCTIVE GERRIT INSTANCES! |
| * (utility to clean up a test Gerrit instance) |
| */ |
| private static class EvilGerritClient extends GerritClientImpl { |
| |
| private EvilGerritClient(GerritServerConfig gerritConfig, String onBehalfOf) { |
| super(gerritConfig, onBehalfOf); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| List<String> gsql(String query, ResultFormat format) throws ConnectionException, CommandException { |
| final StringBuffer sb = new StringBuffer("gerrit gsql"); |
| |
| sb.append(" --format ").append(format.name()); |
| sb.append(" -c \"").append(query).append("\""); |
| |
| // Here comes the evil part: Overriding gsql(), allowing modifying commands and using reflection to call a private method... |
| try { |
| Method sshCommand = this.getClass().getSuperclass().getDeclaredMethod("sshCommand", String.class); |
| sshCommand.setAccessible(true); |
| return (List<String>) sshCommand.invoke(this, sb.toString()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| } |