blob: c58e39780f618cdb8af1391e591ac9080b6c0cb4 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}
}
}