summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pom.xml9
-rw-r--r--src/main/java/com/google/gerrit/client/reviewdb/AccountGroup.java32
-rw-r--r--src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java15
-rw-r--r--src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java362
-rw-r--r--src/test/java/com/google/gerrit/testutil/TestDatabase.java105
5 files changed, 516 insertions, 7 deletions
diff --git a/pom.xml b/pom.xml
index 910db5a928..606826d389 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@ limitations under the License.
<groupId>gerrit</groupId>
<artifactId>gerrit</artifactId>
<packaging>war</packaging>
- <version>2.0.24.1</version>
+ <version>2.0.24.2</version>
<name>gerrit</name>
<description>Gerrit - Web Based Code Review</description>
<url>http://android.git.kernel.org/?p=tools/gerrit.git</url>
@@ -632,6 +632,13 @@ limitations under the License.
</dependency>
<dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <version>1.2.122</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.5.1</version>
diff --git a/src/main/java/com/google/gerrit/client/reviewdb/AccountGroup.java b/src/main/java/com/google/gerrit/client/reviewdb/AccountGroup.java
index 79a35a5dfa..eb38ef212f 100644
--- a/src/main/java/com/google/gerrit/client/reviewdb/AccountGroup.java
+++ b/src/main/java/com/google/gerrit/client/reviewdb/AccountGroup.java
@@ -105,13 +105,38 @@ public final class AccountGroup {
}
public static enum Type {
- /** System defined and managed group, e.g. anonymous users. */
+ /**
+ * System defined and managed group, e.g. anonymous users.
+ * <p>
+ * These groups must be explicitly named by {@link SystemConfig} and are
+ * specially handled throughout the code. In UI contexts their membership is
+ * not displayed. When computing effective group membership for any given
+ * user account, these groups are automatically handled using specialized
+ * branch conditions.
+ */
SYSTEM,
- /** Group defined within our database. */
+ /**
+ * Group defined within our database.
+ * <p>
+ * An internal group has its membership fully enumerated in the database.
+ * The membership can be viewed and edited through the web UI by any user
+ * who is a member of the owner group. These groups are not treated special
+ * in the code.
+ */
INTERNAL,
- /** Group defined by external LDAP database. */
+ /**
+ * Group defined by external LDAP database.
+ * <p>
+ * A group whose membership is determined by the LDAP directory that we
+ * connect to for user and group information. In UI contexts the membership
+ * of the group is not displayed, as it may be exceedingly large, or might
+ * contain users who have never logged into this server before (and thus
+ * have no matching account record). Adding or removing users from an LDAP
+ * group requires making edits through the LDAP directory, and cannot be
+ * done through our UI.
+ */
LDAP;
}
@@ -151,6 +176,7 @@ public final class AccountGroup {
name = newName;
groupId = newId;
ownerGroupId = groupId;
+ setType(Type.INTERNAL);
}
public AccountGroup.Id getId() {
diff --git a/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java b/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java
index 15c9ecb56b..ab5a2933f0 100644
--- a/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java
+++ b/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java
@@ -38,13 +38,13 @@ import java.util.Collections;
import java.util.List;
/** Loads the {@link SystemConfig} from the database. */
-class SystemConfigProvider implements Provider<SystemConfig> {
+public class SystemConfigProvider implements Provider<SystemConfig> {
private static final Project.NameKey DEFAULT_WILD_NAME =
new Project.NameKey("-- All Projects --");
private final SchemaFactory<ReviewDb> schema;
@Inject
- SystemConfigProvider(final SchemaFactory<ReviewDb> sf) {
+ public SystemConfigProvider(final SchemaFactory<ReviewDb> sf) {
schema = sf;
}
@@ -133,6 +133,7 @@ class SystemConfigProvider implements Provider<SystemConfig> {
new AccountGroup(new AccountGroup.NameKey("Administrators"),
new AccountGroup.Id(c.nextAccountGroupId()));
admin.setDescription("Gerrit Site Administrators");
+ admin.setType(AccountGroup.Type.INTERNAL);
c.accountGroups().insert(Collections.singleton(admin));
final AccountGroup anonymous =
@@ -148,7 +149,7 @@ class SystemConfigProvider implements Provider<SystemConfig> {
new AccountGroup.Id(c.nextAccountGroupId()));
registered.setDescription("Any signed-in user");
registered.setOwnerGroupId(admin.getId());
- anonymous.setType(AccountGroup.Type.SYSTEM);
+ registered.setType(AccountGroup.Type.SYSTEM);
c.accountGroups().insert(Collections.singleton(registered));
File sitePath = new File(".").getAbsoluteFile();
@@ -255,6 +256,14 @@ class SystemConfigProvider implements Provider<SystemConfig> {
final ProjectRight read =
new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(),
sConfig.anonymousGroupId));
+ read.setMaxValue((short) 1);
+ read.setMinValue((short) 1);
+ c.projectRights().insert(Collections.singleton(read));
+ }
+ {
+ final ProjectRight read =
+ new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(),
+ sConfig.registeredGroupId));
read.setMaxValue((short) 2);
read.setMinValue((short) 1);
c.projectRights().insert(Collections.singleton(read));
diff --git a/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java b/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java
new file mode 100644
index 0000000000..c1fce7b042
--- /dev/null
+++ b/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java
@@ -0,0 +1,362 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.config;
+
+import com.google.gerrit.client.reviewdb.AccountGroup;
+import com.google.gerrit.client.reviewdb.ApprovalCategory;
+import com.google.gerrit.client.reviewdb.ApprovalCategoryValue;
+import com.google.gerrit.client.reviewdb.Project;
+import com.google.gerrit.client.reviewdb.ProjectRight;
+import com.google.gerrit.client.reviewdb.ReviewDb;
+import com.google.gerrit.client.reviewdb.SchemaVersion;
+import com.google.gerrit.client.reviewdb.SystemConfig;
+import com.google.gerrit.server.workflow.NoOpFunction;
+import com.google.gerrit.server.workflow.SubmitFunction;
+import com.google.gerrit.testutil.TestDatabase;
+import com.google.gwtorm.client.OrmException;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.sql.SQLException;
+import java.util.HashSet;
+
+public class SystemConfigProviderTest extends TestCase {
+ private ApprovalCategory.Id codeReview = new ApprovalCategory.Id("CRVW");
+ private TestDatabase db;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ db = new TestDatabase();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestDatabase.drop(db);
+ super.tearDown();
+ }
+
+ public void testGetCauses_CreateSchema() throws OrmException {
+ // Initially the schema should be empty.
+ //
+ try {
+ getSchemaVersion();
+ fail("Brand new test database has schema_version table");
+ } catch (OrmException e) {
+ final Throwable cause = e.getCause();
+ assertTrue(cause instanceof SQLException);
+
+ final String msg = cause.getMessage();
+ assertEquals("Table SCHEMA_VERSION not found", msg.split(";")[0]);
+ }
+
+ // Create the schema using the current schema version.
+ //
+ final SystemConfig config = getSystemConfig();
+ final SchemaVersion version = getSchemaVersion();
+ assertNotNull(version);
+ assertEquals(ReviewDb.VERSION, version.versionNbr);
+
+ assertNotNull(config);
+ assertNotNull(config.adminGroupId);
+ assertNotNull(config.anonymousGroupId);
+ assertNotNull(config.registeredGroupId);
+
+ // By default sitePath is set to the current working directory.
+ //
+ File sitePath = new File(".").getAbsoluteFile();
+ if (sitePath.getName().equals(".")) {
+ sitePath = sitePath.getParentFile();
+ }
+ assertEquals(sitePath.getAbsolutePath(), config.sitePath);
+
+ // This is randomly generated and should be at least 20 bytes long.
+ //
+ assertNotNull(config.registerEmailPrivateKey);
+ assertTrue(20 < config.registerEmailPrivateKey.length());
+ }
+
+ public void testSubsequentGetReads() {
+ final SystemConfig exp = getSystemConfig();
+ final SystemConfig act = getSystemConfig();
+
+ assertNotSame(exp, act);
+ assertEquals(exp.adminGroupId, act.adminGroupId);
+ assertEquals(exp.anonymousGroupId, act.anonymousGroupId);
+ assertEquals(exp.registeredGroupId, act.registeredGroupId);
+ assertEquals(exp.sitePath, act.sitePath);
+ assertEquals(exp.registerEmailPrivateKey, act.registerEmailPrivateKey);
+ }
+
+ public void testCreateSchema_Group_Administrators() throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ final ReviewDb c = db.open();
+ try {
+ final AccountGroup admin = c.accountGroups().get(config.adminGroupId);
+ assertNotNull(admin);
+ assertEquals(config.adminGroupId, admin.getId());
+ assertEquals("Administrators", admin.getName());
+ assertSame(AccountGroup.Type.INTERNAL, admin.getType());
+ } finally {
+ c.close();
+ }
+ }
+
+ public void testCreateSchema_Group_AnonymousUsers() throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ final ReviewDb c = db.open();
+ try {
+ final AccountGroup anon = c.accountGroups().get(config.anonymousGroupId);
+ assertNotNull(anon);
+ assertEquals(config.anonymousGroupId, anon.getId());
+ assertEquals("Anonymous Users", anon.getName());
+ assertSame(AccountGroup.Type.SYSTEM, anon.getType());
+ } finally {
+ c.close();
+ }
+ }
+
+ public void testCreateSchema_Group_RegisteredUsers() throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ final ReviewDb c = db.open();
+ try {
+ final AccountGroup reg = c.accountGroups().get(config.registeredGroupId);
+ assertNotNull(reg);
+ assertEquals(config.registeredGroupId, reg.getId());
+ assertEquals("Registered Users", reg.getName());
+ assertSame(AccountGroup.Type.SYSTEM, reg.getType());
+ } finally {
+ c.close();
+ }
+ }
+
+ public void testCreateSchema_WildCardProject() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final Project all;
+
+ all = c.projects().get(WildProjectNameProvider.WILD_PROJECT_ID);
+ assertNotNull(all);
+ assertEquals("-- All Projects --", all.getName());
+ assertEquals(new Project.Id(0), all.getId());
+ assertFalse(all.isUseContributorAgreements());
+ assertFalse(all.isUseSignedOffBy());
+ } finally {
+ c.close();
+ }
+ }
+
+ public void testCreateSchema_ApprovalCategory_CodeReview()
+ throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(codeReview);
+ assertNotNull(cat);
+ assertEquals(codeReview, cat.getId());
+ assertEquals("Code Review", cat.getName());
+ assertEquals("R", cat.getAbbreviatedName());
+ assertEquals("MaxWithBlock", cat.getFunctionName());
+ assertTrue(cat.isCopyMinScore());
+ assertFalse(cat.isAction());
+ assertTrue(0 <= cat.getPosition());
+ } finally {
+ c.close();
+ }
+ assertValueRange(codeReview, -2, -1, 0, 1, 2);
+ }
+
+ public void testCreateSchema_ApprovalCategory_Read() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(ApprovalCategory.READ);
+ assertNotNull(cat);
+ assertEquals(ApprovalCategory.READ, cat.getId());
+ assertEquals("Read Access", cat.getName());
+ assertNull(cat.getAbbreviatedName());
+ assertEquals(NoOpFunction.NAME, cat.getFunctionName());
+ assertTrue(cat.isAction());
+ } finally {
+ c.close();
+ }
+ assertValueRange(ApprovalCategory.READ, -1, 1, 2);
+ }
+
+ public void testCreateSchema_ApprovalCategory_Submit() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(ApprovalCategory.SUBMIT);
+ assertNotNull(cat);
+ assertEquals(ApprovalCategory.SUBMIT, cat.getId());
+ assertEquals("Submit", cat.getName());
+ assertNull(cat.getAbbreviatedName());
+ assertEquals(SubmitFunction.NAME, cat.getFunctionName());
+ assertTrue(cat.isAction());
+ } finally {
+ c.close();
+ }
+ assertValueRange(ApprovalCategory.SUBMIT, 1);
+ }
+
+ public void testCreateSchema_ApprovalCategory_PushTag() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(ApprovalCategory.PUSH_TAG);
+ assertNotNull(cat);
+ assertEquals(ApprovalCategory.PUSH_TAG, cat.getId());
+ assertEquals("Push Annotated Tag", cat.getName());
+ assertNull(cat.getAbbreviatedName());
+ assertEquals(NoOpFunction.NAME, cat.getFunctionName());
+ assertTrue(cat.isAction());
+ } finally {
+ c.close();
+ }
+ assertValueRange(ApprovalCategory.PUSH_TAG, //
+ ApprovalCategory.PUSH_TAG_SIGNED, //
+ ApprovalCategory.PUSH_TAG_ANNOTATED, //
+ ApprovalCategory.PUSH_TAG_ANY);
+ }
+
+ public void testCreateSchema_ApprovalCategory_PushHead() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(ApprovalCategory.PUSH_HEAD);
+ assertNotNull(cat);
+ assertEquals(ApprovalCategory.PUSH_HEAD, cat.getId());
+ assertEquals("Push Branch", cat.getName());
+ assertNull(cat.getAbbreviatedName());
+ assertEquals(NoOpFunction.NAME, cat.getFunctionName());
+ assertTrue(cat.isAction());
+ } finally {
+ c.close();
+ }
+ assertValueRange(ApprovalCategory.PUSH_HEAD, //
+ ApprovalCategory.PUSH_HEAD_UPDATE, //
+ ApprovalCategory.PUSH_HEAD_CREATE, //
+ ApprovalCategory.PUSH_HEAD_REPLACE);
+ }
+
+ public void testCreateSchema_ApprovalCategory_Owner() throws OrmException {
+ final ReviewDb c = db.create().open();
+ try {
+ final ApprovalCategory cat;
+
+ cat = c.approvalCategories().get(ApprovalCategory.OWN);
+ assertNotNull(cat);
+ assertEquals(ApprovalCategory.OWN, cat.getId());
+ assertEquals("Owner", cat.getName());
+ assertNull(cat.getAbbreviatedName());
+ assertEquals(NoOpFunction.NAME, cat.getFunctionName());
+ assertTrue(cat.isAction());
+ } finally {
+ c.close();
+ }
+ assertValueRange(ApprovalCategory.OWN, 1);
+ }
+
+ private void assertValueRange(ApprovalCategory.Id cat, int... range)
+ throws OrmException {
+ final HashSet<ApprovalCategoryValue.Id> act =
+ new HashSet<ApprovalCategoryValue.Id>();
+ final ReviewDb c = db.open();
+ try {
+ for (ApprovalCategoryValue v : c.approvalCategoryValues().byCategory(cat)) {
+ assertNotNull(v.getId());
+ assertNotNull(v.getName());
+ assertEquals(cat, v.getCategoryId());
+ assertFalse(v.getName().isEmpty());
+
+ act.add(v.getId());
+ }
+ } finally {
+ c.close();
+ }
+
+ for (int value : range) {
+ final ApprovalCategoryValue.Id exp =
+ new ApprovalCategoryValue.Id(cat, (short) value);
+ if (!act.remove(exp)) {
+ fail("Category " + cat + " lacks value " + value);
+ }
+ }
+ if (!act.isEmpty()) {
+ fail("Category " + cat + " has additional values: " + act);
+ }
+ }
+
+ public void testCreateSchema_DefaultAccess_AnonymousUsers()
+ throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ assertDefaultRight(config.anonymousGroupId, ApprovalCategory.READ, 1, 1);
+ }
+
+ public void testCreateSchema_DefaultAccess_RegisteredUsers()
+ throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ assertDefaultRight(config.registeredGroupId, ApprovalCategory.READ, 1, 2);
+ assertDefaultRight(config.registeredGroupId, codeReview, -1, 1);
+ }
+
+ public void testCreateSchema_DefaultAccess_Administrators()
+ throws OrmException {
+ final SystemConfig config = getSystemConfig();
+ assertDefaultRight(config.adminGroupId, ApprovalCategory.READ, 1, 1);
+ }
+
+ private void assertDefaultRight(final AccountGroup.Id group,
+ final ApprovalCategory.Id category, int min, int max) throws OrmException {
+ final ReviewDb c = db.open();
+ try {
+ final Project all;
+ final ProjectRight right;
+
+ all = c.projects().get(WildProjectNameProvider.WILD_PROJECT_ID);
+ right = c.projectRights().get( //
+ new ProjectRight.Key(all.getNameKey(), category, group));
+
+ assertNotNull(right);
+ assertEquals(all.getNameKey(), right.getProjectNameKey());
+ assertEquals(group, right.getAccountGroupId());
+ assertEquals(category, right.getApprovalCategoryId());
+ assertEquals(min, right.getMinValue());
+ assertEquals(max, right.getMaxValue());
+ } finally {
+ c.close();
+ }
+ }
+
+ private SystemConfig getSystemConfig() {
+ return new SystemConfigProvider(db).get();
+ }
+
+ private SchemaVersion getSchemaVersion() throws OrmException {
+ final ReviewDb c = db.open();
+ try {
+ return c.schemaVersion().get(new SchemaVersion.Key());
+ } finally {
+ c.close();
+ }
+ }
+}
diff --git a/src/test/java/com/google/gerrit/testutil/TestDatabase.java b/src/test/java/com/google/gerrit/testutil/TestDatabase.java
new file mode 100644
index 0000000000..d628403c4f
--- /dev/null
+++ b/src/test/java/com/google/gerrit/testutil/TestDatabase.java
@@ -0,0 +1,105 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.testutil;
+
+import com.google.gerrit.client.reviewdb.ReviewDb;
+import com.google.gerrit.server.config.SystemConfigProvider;
+import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.jdbc.Database;
+import com.google.gwtorm.jdbc.SimpleDataSource;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+/**
+ * An in-memory test instance of {@link ReviewDb} database.
+ * <p>
+ * Test classes should create one instance of this class for each unique test
+ * database they want to use. When the tests needing this instance are complete,
+ * ensure that {@link #drop(TestDatabase)} is called to free the resources so
+ * the JVM running the unit tests doesn't run out of heap space.
+ */
+public class TestDatabase implements SchemaFactory<ReviewDb> {
+ private static int dbCnt;
+
+ private static synchronized DataSource newDataSource() throws SQLException {
+ final Properties p = new Properties();
+ p.setProperty("driver", org.h2.Driver.class.getName());
+ p.setProperty("url", "jdbc:h2:mem:" + "Test_" + (++dbCnt));
+ final DataSource dataSource = new SimpleDataSource(p);
+ return dataSource;
+ }
+
+ /** Drop the database from memory; does nothing if the instance was null. */
+ public static void drop(final TestDatabase db) {
+ if (db != null) {
+ db.drop();
+ }
+ }
+
+ private Connection openHandle;
+ private Database<ReviewDb> database;
+
+ public TestDatabase() throws OrmException {
+ try {
+ final DataSource dataSource = newDataSource();
+
+ // Open one connection. This will peg the database into memory
+ // until someone calls drop on us, allowing subsequent connections
+ // opened against the same URL to go to the same set of tables.
+ //
+ openHandle = dataSource.getConnection();
+
+ // Build the access layer around the connection factory.
+ //
+ database = new Database<ReviewDb>(dataSource, ReviewDb.class);
+ } catch (SQLException e) {
+ throw new OrmException(e);
+ }
+ }
+
+ public Database<ReviewDb> getDatabase() {
+ return database;
+ }
+
+ @Override
+ public ReviewDb open() throws OrmException {
+ return getDatabase().open();
+ }
+
+ /** Ensure the database schema has been created and initialized. */
+ public TestDatabase create() {
+ new SystemConfigProvider(this).get();
+ return this;
+ }
+
+ /** Drop this database from memory so it no longer exists. */
+ public void drop() {
+ if (openHandle != null) {
+ try {
+ openHandle.close();
+ } catch (SQLException e) {
+ System.err.println("WARNING: Cannot close database connection");
+ e.printStackTrace(System.err);
+ }
+ openHandle = null;
+ database = null;
+ }
+ }
+}