Implement automatic schema upgrading

SchemaVersion subclasses form a DAG, managed by Guice, chaining the
current schema version to its immediate predecessor.  When a version
is selected, we try to upgrade to it by first asking is predecessor
to validate (and upgrade).

Drops of schema elements are not performed automatically, but instead
are printed to the console so the administrator can verify the drops
aren't their own private schema elements, and execute the commands
they know won't damage their own private data.

Change-Id: I2a53749ca23432da2a9b1866203aafb151b48aab
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce 2009-12-23 10:43:01 -08:00
parent 23e0987350
commit 5a15b6d46f
19 changed files with 486 additions and 69 deletions

View File

@ -34,8 +34,10 @@ import com.google.gerrit.server.git.GitProjectImporter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.schema.SchemaUpdater;
import com.google.gerrit.server.schema.UpdateUI;
import com.google.gerrit.server.util.HostPlatform;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.StatementExecutor;
import com.google.inject.AbstractModule;
import com.google.inject.CreationException;
import com.google.inject.Guice;
@ -76,7 +78,7 @@ public class Init extends SiteProgram {
init.flags.deleteOnFailure = false;
run = createSiteRun(init);
run.schemaUpdater.update();
run.upgradeSchema();
run.importGit();
} catch (Exception failure) {
if (init.flags.deleteOnFailure) {
@ -176,6 +178,39 @@ public class Init extends SiteProgram {
this.browser = browser;
}
void upgradeSchema() throws OrmException {
schemaUpdater.update(new UpdateUI() {
@Override
public void message(String msg) {
System.err.println(msg);
System.err.flush();
}
@Override
public void pruneSchema(StatementExecutor e, List<String> pruneList)
throws OrmException {
StringBuilder msg = new StringBuilder();
msg.append("Execute the following SQL to drop unused objects:\n");
msg.append("\n");
for (String sql : pruneList) {
msg.append(" ");
msg.append(sql);
msg.append(";\n");
}
if (ui.isBatch()) {
System.err.print(msg);
System.err.flush();
} else if (ui.yesno(true, "%s\nExecute now", msg)) {
for (String sql : pruneList) {
e.execute(sql);
}
}
}
});
}
void importGit() throws OrmException, IOException {
if (flags.importProjects) {
gitProjectImporter.run(new GitProjectImporter.Messages() {

View File

@ -18,10 +18,10 @@ import static com.google.inject.Scopes.SINGLETON;
import static com.google.inject.Stage.PRODUCTION;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.DatabaseModule;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.DatabaseModule;
import com.google.gwtorm.client.OrmException;
import com.google.inject.AbstractModule;
import com.google.inject.CreationException;

View File

@ -18,7 +18,7 @@ import com.google.gwtorm.client.Column;
import com.google.gwtorm.client.StringKey;
/** Current version of the database schema, to facilitate live upgrades. */
public final class SchemaVersion {
public final class CurrentSchemaVersion {
public static final class Key extends
StringKey<com.google.gwtorm.client.Key<?>> {
private static final long serialVersionUID = 1L;
@ -43,9 +43,9 @@ public final class SchemaVersion {
}
/** Construct a new, unconfigured instance. */
public static SchemaVersion create() {
final SchemaVersion r = new SchemaVersion();
r.singleton = new SchemaVersion.Key();
public static CurrentSchemaVersion create() {
final CurrentSchemaVersion r = new CurrentSchemaVersion();
r.singleton = new CurrentSchemaVersion.Key();
return r;
}
@ -56,6 +56,6 @@ public final class SchemaVersion {
@Column
public transient int versionNbr;
protected SchemaVersion() {
protected CurrentSchemaVersion() {
}
}

View File

@ -31,7 +31,7 @@ import com.google.gwtorm.client.Sequence;
* </ul>
*/
public interface ReviewDb extends Schema {
public static final int VERSION = 19;
/* If you change anything, update SchemaVersion.C to use a new version. */
@Relation
SchemaVersionAccess schemaVersion();

View File

@ -18,9 +18,9 @@ import com.google.gwtorm.client.Access;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.PrimaryKey;
/** Access interface for {@link SchemaVersion}. */
/** Access interface for {@link CurrentSchemaVersion}. */
public interface SchemaVersionAccess extends
Access<SchemaVersion, SchemaVersion.Key> {
Access<CurrentSchemaVersion, CurrentSchemaVersion.Key> {
@PrimaryKey("singleton")
SchemaVersion get(SchemaVersion.Key key) throws OrmException;
CurrentSchemaVersion get(CurrentSchemaVersion.Key key) throws OrmException;
}

View File

@ -14,9 +14,11 @@
package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SchemaVersion;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.schema.Current;
import com.google.gerrit.server.schema.SchemaVersion;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
@ -29,9 +31,14 @@ import java.util.List;
public class SystemConfigProvider implements Provider<SystemConfig> {
private final SchemaFactory<ReviewDb> schema;
@Current
private final Provider<SchemaVersion> version;
@Inject
public SystemConfigProvider(final SchemaFactory<ReviewDb> sf) {
schema = sf;
public SystemConfigProvider(final SchemaFactory<ReviewDb> schemaFactory,
@Current final Provider<SchemaVersion> version) {
this.schema = schemaFactory;
this.version = version;
}
@Override
@ -39,15 +46,17 @@ public class SystemConfigProvider implements Provider<SystemConfig> {
try {
final ReviewDb db = schema.open();
try {
SchemaVersion sVer = getSchemaVersion(db);
final CurrentSchemaVersion sVer = getSchemaVersion(db);
final int eVer = version.get().getVersionNbr();
if (sVer == null) {
throw new OrmException("Schema not yet initialized."
+ " Run init to initialize the schema.");
}
if (sVer.versionNbr != ReviewDb.VERSION) {
throw new OrmException("Unsupported schema version " + sVer.versionNbr
+ "; expected schema version " + ReviewDb.VERSION + ". Run init to upgrade.");
if (sVer.versionNbr != eVer) {
throw new OrmException("Unsupported schema version "
+ sVer.versionNbr + "; expected schema version " + eVer
+ ". Run init to upgrade.");
}
final List<SystemConfig> all = db.systemConfig().all().toList();
@ -57,8 +66,8 @@ public class SystemConfigProvider implements Provider<SystemConfig> {
case 0:
throw new OrmException("system_config table is empty");
default:
throw new OrmException("system_config must have exactly 1 row;" + " found "
+ all.size() + " rows instead");
throw new OrmException("system_config must have exactly 1 row;"
+ " found " + all.size() + " rows instead");
}
} finally {
db.close();
@ -68,9 +77,9 @@ public class SystemConfigProvider implements Provider<SystemConfig> {
}
}
private SchemaVersion getSchemaVersion(final ReviewDb db) {
private CurrentSchemaVersion getSchemaVersion(final ReviewDb db) {
try {
return db.schemaVersion().get(new SchemaVersion.Key());
return db.schemaVersion().get(new CurrentSchemaVersion.Key());
} catch (OrmException e) {
return null;
}

View File

@ -0,0 +1,27 @@
// 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.schema;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
/** Indicates the {@link SchemaVersion} is the current one. */
@Retention(RUNTIME)
@BindingAnnotation
public @interface Current {
}

View File

@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.config;
package com.google.gerrit.server.schema;
import static com.google.inject.Scopes.SINGLETON;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gwtorm.client.SchemaFactory;
import com.google.gwtorm.jdbc.Database;
import com.google.inject.TypeLiteral;
@ -25,6 +26,8 @@ import com.google.inject.TypeLiteral;
public class DatabaseModule extends FactoryModule {
@Override
protected void configure() {
install(new SchemaVersion.Module());
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).to(
new TypeLiteral<Database<ReviewDb>>() {}).in(SINGLETON);
bind(new TypeLiteral<Database<ReviewDb>>() {}).toProvider(

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.config;
package com.google.gerrit.server.schema;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.OrmException;

View File

@ -17,10 +17,10 @@ package com.google.gerrit.server.schema;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.ProjectRight;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SchemaVersion;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePaths;
@ -30,6 +30,7 @@ import com.google.gerrit.server.workflow.SubmitFunction;
import com.google.gwtjsonrpc.server.SignedToken;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.Transaction;
import com.google.gwtorm.jdbc.JdbcExecutor;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.schema.sql.DialectH2;
import com.google.gwtorm.schema.sql.DialectMySQL;
@ -50,17 +51,21 @@ public class SchemaCreator {
private final @SitePath
File site_path;
private final int versionNbr;
private final ScriptRunner index_generic;
private final ScriptRunner index_postgres;
private final ScriptRunner mysql_nextval;
@Inject
public SchemaCreator(final SitePaths site) {
this(site.site_path);
public SchemaCreator(final SitePaths site,
@Current final SchemaVersion version) {
this(site.site_path, version);
}
public SchemaCreator(final @SitePath File site) {
public SchemaCreator(final @SitePath File site,
@Current final SchemaVersion version) {
site_path = site;
versionNbr = version.getVersionNbr();
index_generic = new ScriptRunner("index_generic.sql");
index_postgres = new ScriptRunner("index_postgres.sql");
mysql_nextval = new ScriptRunner("mysql_nextval.sql");
@ -68,11 +73,15 @@ public class SchemaCreator {
public void create(final ReviewDb db) throws OrmException {
final JdbcSchema jdbc = (JdbcSchema) db;
final JdbcExecutor e = new JdbcExecutor(jdbc);
try {
jdbc.updateSchema(e);
} finally {
e.close();
}
jdbc.createSchema();
final SchemaVersion sVer = SchemaVersion.create();
sVer.versionNbr = ReviewDb.VERSION;
final CurrentSchemaVersion sVer = CurrentSchemaVersion.create();
sVer.versionNbr = versionNbr;
db.schemaVersion().insert(Collections.singleton(sVer));
final SystemConfig sConfig = initSystemConfig(db);

View File

@ -14,15 +14,17 @@
package com.google.gerrit.server.schema;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SchemaVersion;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
/** Creates or updates the current database schema. */
@ -30,23 +32,32 @@ public class SchemaUpdater {
private final SchemaFactory<ReviewDb> schema;
private final SitePaths site;
private final SchemaCreator creator;
private final Provider<SchemaVersion> updater;
@Inject
SchemaUpdater(final SchemaFactory<ReviewDb> schema, final SitePaths site,
final SchemaCreator creator) {
final SchemaCreator creator, @Current final Provider<SchemaVersion> update) {
this.schema = schema;
this.site = site;
this.creator = creator;
this.updater = update;
}
public void update() throws OrmException {
public void update(final UpdateUI ui) throws OrmException {
final ReviewDb db = schema.open();
try {
final SchemaVersion version = getSchemaVersion(db);
final SchemaVersion u = updater.get();
final CurrentSchemaVersion version = getSchemaVersion(db);
if (version == null) {
creator.create(db);
} else {
try {
u.check(ui, version, db);
} catch (SQLException e) {
throw new OrmException("Cannot upgrade schema", e);
}
updateSystemConfig(db);
}
} finally {
@ -54,9 +65,9 @@ public class SchemaUpdater {
}
}
private SchemaVersion getSchemaVersion(final ReviewDb db) {
private CurrentSchemaVersion getSchemaVersion(final ReviewDb db) {
try {
return db.schemaVersion().get(new SchemaVersion.Key());
return db.schemaVersion().get(new CurrentSchemaVersion.Key());
} catch (OrmException e) {
return null;
}

View File

@ -0,0 +1,153 @@
// 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.schema;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.StatementExecutor;
import com.google.gwtorm.jdbc.JdbcExecutor;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.inject.AbstractModule;
import com.google.inject.Provider;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
private static final Class<? extends SchemaVersion> C = Schema_19.class;
public static class Module extends AbstractModule {
@Override
protected void configure() {
bind(SchemaVersion.class).annotatedWith(Current.class).to(C);
}
}
private final Provider<? extends SchemaVersion> prior;
private final int versionNbr;
protected SchemaVersion(final Provider<? extends SchemaVersion> prior) {
this.prior = prior;
this.versionNbr = guessVersion(getClass());
}
private static int guessVersion(Class<?> c) {
String n = c.getName();
n = n.substring(n.lastIndexOf('_') + 1);
while (n.startsWith("0"))
n = n.substring(1);
return Integer.parseInt(n);
}
protected SchemaVersion(final Provider<? extends SchemaVersion> prior,
final int versionNbr) {
this.prior = prior;
this.versionNbr = versionNbr;
}
/** @return the {@link CurrentSchemaVersion#versionNbr} this step targets. */
public final int getVersionNbr() {
return versionNbr;
}
public final void check(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db)
throws OrmException, SQLException {
if (curr.versionNbr == versionNbr) {
// Nothing to do, we are at the correct schema.
//
} else {
upgradeFrom(ui, curr, db);
}
}
/** Runs check on the prior schema version, and then upgrades. */
protected void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db)
throws OrmException, SQLException {
final JdbcSchema s = (JdbcSchema) db;
prior.get().check(ui, curr, db);
ui.message("Upgrading database schema from version " + curr.versionNbr
+ " to " + versionNbr + " ...");
preUpdateSchema(db);
final JdbcExecutor e = new JdbcExecutor(s);
try {
s.updateSchema(e);
migrateData(db);
final List<String> pruneList = new ArrayList<String>();
s.pruneSchema(new StatementExecutor() {
public void execute(String sql) {
pruneList.add(sql);
}
});
if (!pruneList.isEmpty()) {
ui.pruneSchema(e, pruneList);
}
} finally {
e.close();
}
finish(curr, db);
}
/** Invoke before updateSchema adds new columns/tables. */
protected void preUpdateSchema(ReviewDb db) throws OrmException, SQLException {
}
/**
* Invoked between updateSchema (adds new columns/tables) and pruneSchema
* (removes deleted columns/tables).
*/
@SuppressWarnings("unused")
protected void migrateData(ReviewDb db) throws OrmException, SQLException {
}
/** Mark the current schema version. */
protected void finish(CurrentSchemaVersion curr, ReviewDb db)
throws OrmException {
curr.versionNbr = versionNbr;
db.schemaVersion().update(Collections.singleton(curr));
}
/** Rename an existing column. */
protected void renameColumn(ReviewDb db, String table, String from, String to)
throws OrmException {
final JdbcSchema s = (JdbcSchema) db;
final JdbcExecutor e = new JdbcExecutor(s);
try {
s.renameField(e, table, from, to);
} finally {
e.close();
}
}
/** Execute a SQL statement. */
protected void execute(ReviewDb db, String sql) throws SQLException {
Statement s = ((JdbcSchema) db).getConnection().createStatement();
try {
s.execute(sql);
} finally {
s.close();
}
}
}

View File

@ -0,0 +1,42 @@
// 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.schema;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
class Schema_19 extends SchemaVersion {
@Inject
Schema_19() {
super(new Provider<SchemaVersion>() {
public SchemaVersion get() {
throw new ProvisionException("Cannot upgrade from 18");
}
});
}
@Override
protected void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr,
ReviewDb db) throws OrmException {
throw new OrmException("Cannot upgrade from " + curr.versionNbr
+ "; manually run scripts from"
+ " http://gerrit.googlecode.com/files/schema-upgrades003_019.zip"
+ " and restart.");
}
}

View File

@ -0,0 +1,27 @@
// 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.schema;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.StatementExecutor;
import java.util.List;
public interface UpdateUI {
void message(String msg);
void pruneSchema(StatementExecutor e, List<String> pruneList)
throws OrmException;
}

View File

@ -20,9 +20,7 @@ import com.google.gerrit.reviewdb.ApprovalCategoryValue;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.ProjectRight;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SchemaVersion;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.config.SystemConfigProvider;
import com.google.gerrit.server.config.WildProjectNameProvider;
import com.google.gerrit.server.workflow.NoOpFunction;
import com.google.gerrit.server.workflow.SubmitFunction;
@ -75,11 +73,8 @@ public class SchemaCreatorTest extends TestCase {
// Create the schema using the current schema version.
//
db.create();
final SystemConfig config = getSystemConfig();
final SchemaVersion version = getSchemaVersion();
assertNotNull(version);
assertEquals(ReviewDb.VERSION, version.versionNbr);
db.assertSchemaVersion();
final SystemConfig config = db.getSystemConfig();
assertNotNull(config);
assertNotNull(config.adminGroupId);
assertNotNull(config.anonymousGroupId);
@ -101,8 +96,8 @@ public class SchemaCreatorTest extends TestCase {
public void testSubsequentGetReads() throws OrmException {
db.create();
final SystemConfig exp = getSystemConfig();
final SystemConfig act = getSystemConfig();
final SystemConfig exp = db.getSystemConfig();
final SystemConfig act = db.getSystemConfig();
assertNotSame(exp, act);
assertEquals(exp.adminGroupId, act.adminGroupId);
@ -114,7 +109,7 @@ public class SchemaCreatorTest extends TestCase {
public void testCreateSchema_Group_Administrators() throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
final ReviewDb c = db.open();
try {
final AccountGroup admin = c.accountGroups().get(config.adminGroupId);
@ -129,7 +124,7 @@ public class SchemaCreatorTest extends TestCase {
public void testCreateSchema_Group_AnonymousUsers() throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
final ReviewDb c = db.open();
try {
final AccountGroup anon = c.accountGroups().get(config.anonymousGroupId);
@ -144,7 +139,7 @@ public class SchemaCreatorTest extends TestCase {
public void testCreateSchema_Group_RegisteredUsers() throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
final ReviewDb c = db.open();
try {
final AccountGroup reg = c.accountGroups().get(config.registeredGroupId);
@ -323,14 +318,14 @@ public class SchemaCreatorTest extends TestCase {
public void testCreateSchema_DefaultAccess_AnonymousUsers()
throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
assertDefaultRight(config.anonymousGroupId, ApprovalCategory.READ, 1, 1);
}
public void testCreateSchema_DefaultAccess_RegisteredUsers()
throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
assertDefaultRight(config.registeredGroupId, ApprovalCategory.READ, 1, 2);
assertDefaultRight(config.registeredGroupId, codeReview, -1, 1);
}
@ -338,7 +333,7 @@ public class SchemaCreatorTest extends TestCase {
public void testCreateSchema_DefaultAccess_Administrators()
throws OrmException {
db.create();
final SystemConfig config = getSystemConfig();
final SystemConfig config = db.getSystemConfig();
assertDefaultRight(config.adminGroupId, ApprovalCategory.READ, 1, 1);
}
@ -363,17 +358,4 @@ public class SchemaCreatorTest extends TestCase {
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();
}
}
}

View File

@ -0,0 +1,82 @@
// 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.schema;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.testutil.TestDatabase;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
import com.google.gwtorm.client.StatementExecutor;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.TypeLiteral;
import junit.framework.TestCase;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.UUID;
public class SchemaUpdaterTest extends TestCase {
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 testUpdate() throws OrmException, FileNotFoundException {
db.create();
final File site = new File(UUID.randomUUID().toString());
final SitePaths paths = new SitePaths(site);
SchemaUpdater u = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db);
bind(SitePaths.class).toInstance(paths);
install(new SchemaVersion.Module());
}
}).getInstance(SchemaUpdater.class);
u.update(new UpdateUI() {
@Override
public void message(String msg) {
}
@Override
public void pruneSchema(StatementExecutor e, List<String> pruneList)
throws OrmException {
for (String sql : pruneList) {
e.execute(sql);
}
}
});
db.assertSchemaVersion();
final SystemConfig sc = db.getSystemConfig();
assertEquals(paths.site_path.getAbsolutePath(), sc.sitePath);
}
}

View File

@ -14,12 +14,22 @@
package com.google.gerrit.testutil;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
import com.google.gerrit.server.config.SystemConfigProvider;
import com.google.gerrit.server.schema.Current;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.schema.SchemaVersion;
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 com.google.inject.Guice;
import com.google.inject.Key;
import com.google.inject.Provider;
import junit.framework.TestCase;
import java.io.File;
import java.sql.Connection;
@ -57,6 +67,7 @@ public class TestDatabase implements SchemaFactory<ReviewDb> {
private Connection openHandle;
private Database<ReviewDb> database;
private boolean created;
private SchemaVersion schemaVersion;
public TestDatabase() throws OrmException {
try {
@ -71,6 +82,10 @@ public class TestDatabase implements SchemaFactory<ReviewDb> {
// Build the access layer around the connection factory.
//
database = new Database<ReviewDb>(dataSource, ReviewDb.class);
schemaVersion =
Guice.createInjector(new SchemaVersion.Module()).getBinding(
Key.get(SchemaVersion.class, Current.class)).getProvider().get();
} catch (SQLException e) {
throw new OrmException(e);
}
@ -91,7 +106,7 @@ public class TestDatabase implements SchemaFactory<ReviewDb> {
created = true;
final ReviewDb c = open();
try {
new SchemaCreator(new File(".")).create(c);
new SchemaCreator(new File("."), schemaVersion).create(c);
} finally {
c.close();
}
@ -112,4 +127,26 @@ public class TestDatabase implements SchemaFactory<ReviewDb> {
database = null;
}
}
public SystemConfig getSystemConfig() {
return new SystemConfigProvider(this, new Provider<SchemaVersion>() {
public SchemaVersion get() {
return schemaVersion;
}
}).get();
}
public CurrentSchemaVersion getSchemaVersion() throws OrmException {
final ReviewDb c = open();
try {
return c.schemaVersion().get(new CurrentSchemaVersion.Key());
} finally {
c.close();
}
}
public void assertSchemaVersion() throws OrmException {
final CurrentSchemaVersion act = getSchemaVersion();
TestCase.assertEquals(schemaVersion.getVersionNbr(), act.versionNbr);
}
}

View File

@ -21,13 +21,13 @@ import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.AuthConfigModule;
import com.google.gerrit.server.config.CanonicalWebUrlModule;
import com.google.gerrit.server.config.DatabaseModule;
import com.google.gerrit.server.config.GerritGlobalModule;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.MasterNodeStartup;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePathFromSystemConfigProvider;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.DatabaseModule;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.inject.AbstractModule;

View File

@ -47,7 +47,7 @@ limitations under the License.
<properties>
<jgitVersion>0.5.1.51-g96b2e76</jgitVersion>
<gwtormVersion>1.1.2</gwtormVersion>
<gwtormVersion>1.1.3-SNAPSHOT</gwtormVersion>
<gwtjsonrpcVersion>1.2.1-SNAPSHOT</gwtjsonrpcVersion>
<gwtexpuiVersion>1.2.0-SNAPSHOT</gwtexpuiVersion>
<gwtVersion>2.0.0</gwtVersion>