/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.db;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.containers.TransientPicoContainer;
import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.event.EventDbTester;
import org.sonar.db.favorite.FavoriteDbTester;
import org.sonar.db.issue.IssueDbTester;
import org.sonar.db.notification.NotificationDbTester;
import org.sonar.db.organization.OrganizationDbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.permission.template.PermissionTemplateDbTester;
import org.sonar.db.property.PropertyDbTester;
import org.sonar.db.qualitygate.QualityGateDbTester;
import org.sonar.db.qualityprofile.QualityProfileDbTester;
import org.sonar.db.rule.RuleDbTester;
import org.sonar.db.user.RootFlagAssertions;
import org.sonar.db.user.UserDbTester;
import static com.google.common.base.Preconditions.checkState;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
/**
* This class should be called using @Rule.
* Data is truncated between each tests. The schema is created between each test.
*/
public class DbTester extends AbstractDbTester<TestDb> {
private final System2 system2;
private DbClient client;
private DbSession session = null;
private boolean disableDefaultOrganization = false;
private boolean started = false;
private String defaultOrganizationUuid = randomAlphanumeric(40);
private OrganizationDto defaultOrganization;
private final UserDbTester userTester;
private final ComponentDbTester componentTester;
private final FavoriteDbTester favoriteTester;
private final EventDbTester eventTester;
private final OrganizationDbTester organizationTester;
private final PermissionTemplateDbTester permissionTemplateTester;
private final PropertyDbTester propertyTester;
private final QualityGateDbTester qualityGateDbTester;
private final IssueDbTester issueDbTester;
private final RuleDbTester ruleDbTester;
private final NotificationDbTester notificationDbTester;
private final RootFlagAssertions rootFlagAssertions;
private final QualityProfileDbTester qualityProfileDbTester;
public DbTester(System2 system2, @Nullable String schemaPath) {
super(TestDb.create(schemaPath));
this.system2 = system2;
initDbClient();
this.userTester = new UserDbTester(this);
this.componentTester = new ComponentDbTester(this);
this.favoriteTester = new FavoriteDbTester(this);
this.eventTester = new EventDbTester(this);
this.organizationTester = new OrganizationDbTester(this);
this.permissionTemplateTester = new PermissionTemplateDbTester(this);
this.propertyTester = new PropertyDbTester(this);
this.qualityGateDbTester = new QualityGateDbTester(this);
this.issueDbTester = new IssueDbTester(this);
this.ruleDbTester = new RuleDbTester(this);
this.notificationDbTester = new NotificationDbTester(this);
this.rootFlagAssertions = new RootFlagAssertions(this);
this.qualityProfileDbTester = new QualityProfileDbTester(this);
}
public static DbTester create() {
return new DbTester(System2.INSTANCE, null);
}
public static DbTester create(System2 system2) {
return new DbTester(system2, null);
}
public static DbTester createForSchema(System2 system2, Class testClass, String filename) {
String path = StringUtils.replaceChars(testClass.getCanonicalName(), '.', '/');
String schemaPath = path + "/" + filename;
return new DbTester(system2, schemaPath).setDisableDefaultOrganization(true);
}
private void initDbClient() {
TransientPicoContainer ioc = new TransientPicoContainer();
ioc.addComponent(db.getMyBatis());
ioc.addComponent(system2);
ioc.addComponent(new SequenceUuidFactory());
for (Class daoClass : DaoModule.classes()) {
ioc.addComponent(daoClass);
}
List<Dao> daos = ioc.getComponents(Dao.class);
client = new DbClient(db.getDatabase(), db.getMyBatis(), daos.toArray(new Dao[daos.size()]));
}
public DbTester setDisableDefaultOrganization(boolean b) {
checkState(!started, "DbTester is already started");
this.disableDefaultOrganization = b;
return this;
}
public DbTester setDefaultOrganizationUuid(String uuid) {
checkState(!started, "DbTester is already started");
this.defaultOrganizationUuid = uuid;
return this;
}
public DbTester enableOrganizations() {
properties().insertInternal("organization.enabled", "true");
return this;
}
@Override
protected void before() throws Throwable {
db.start();
db.truncateTables();
initDbClient();
if (!disableDefaultOrganization) {
insertDefaultOrganization();
}
started = true;
}
private void insertDefaultOrganization() {
defaultOrganization = OrganizationTesting.newOrganizationDto().setUuid(defaultOrganizationUuid);
try (DbSession dbSession = db.getMyBatis().openSession(false)) {
client.organizationDao().insert(dbSession, defaultOrganization, false);
client.internalPropertiesDao().save(dbSession, "organization.default", defaultOrganization.getUuid());
dbSession.commit();
}
}
public boolean hasDefaultOrganization() {
return defaultOrganization != null;
}
public OrganizationDto getDefaultOrganization() {
checkState(defaultOrganization != null, "Default organization has not been created");
return defaultOrganization;
}
public UserDbTester users() {
return userTester;
}
public ComponentDbTester components() {
return componentTester;
}
public FavoriteDbTester favorites() {
return favoriteTester;
}
public EventDbTester events() {
return eventTester;
}
public OrganizationDbTester organizations() {
return organizationTester;
}
public PermissionTemplateDbTester permissionTemplates() {
return permissionTemplateTester;
}
public PropertyDbTester properties() {
return propertyTester;
}
public QualityGateDbTester qualityGates() {
return qualityGateDbTester;
}
public RootFlagAssertions rootFlag() {
return rootFlagAssertions;
}
public IssueDbTester issues() {
return issueDbTester;
}
public RuleDbTester rules() {
return ruleDbTester;
}
public NotificationDbTester notifications() {
return notificationDbTester;
}
public QualityProfileDbTester qualityProfiles() {
return qualityProfileDbTester;
}
@Override
protected void after() {
if (session != null) {
session.close();
}
db.stop();
started = false;
}
public DbSession getSession() {
if (session == null) {
session = db.getMyBatis().openSession(false);
}
return session;
}
public void commit() {
getSession().commit();
}
public DbClient getDbClient() {
return client;
}
public int countRowsOfTable(DbSession dbSession, String tableName) {
return super.countRowsOfTable(tableName, new DbSessionConnectionSupplier(dbSession));
}
public int countSql(DbSession dbSession, String sql) {
return super.countSql(sql, new DbSessionConnectionSupplier(dbSession));
}
public List<Map<String, Object>> select(DbSession dbSession, String selectSql) {
return super.select(selectSql, new DbSessionConnectionSupplier(dbSession));
}
public Map<String, Object> selectFirst(DbSession dbSession, String selectSql) {
return super.selectFirst(selectSql, new DbSessionConnectionSupplier(dbSession));
}
@Deprecated
public MyBatis myBatis() {
return db.getMyBatis();
}
@Deprecated
public Connection openConnection() throws SQLException {
return getConnection();
}
private Connection getConnection() throws SQLException {
return db.getDatabase().getDataSource().getConnection();
}
@Deprecated
public Database database() {
return db.getDatabase();
}
public DatabaseCommands getCommands() {
return db.getCommands();
}
private static class DbSessionConnectionSupplier implements ConnectionSupplier {
private final DbSession dbSession;
public DbSessionConnectionSupplier(DbSession dbSession) {
this.dbSession = dbSession;
}
@Override
public Connection get() throws SQLException {
return dbSession.getConnection();
}
@Override
public void close() {
// closing dbSession is not our responsability
}
}
}