Unit test for SystemConfigProvider and CreateSchema

I keep breaking CreateSchema.  So lets ensure the underlying code
within SystemConfigProvider works by defining the important behavior
in a unit test.

Change-Id: I28da27ab1f1c64823d01459110d39e73848d2841
Signed-off-by: Shawn O. Pearce <sop@google.com>
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 f4045a0..ab5a293 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.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;
   }
 
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 0000000..c1fce7b
--- /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
index b83e04d..d628403 100644
--- a/src/test/java/com/google/gerrit/testutil/TestDatabase.java
+++ b/src/test/java/com/google/gerrit/testutil/TestDatabase.java
@@ -15,6 +15,7 @@
 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;
@@ -82,6 +83,12 @@
     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) {