/*
* Copyright 2010-2013 Ning, Inc.
* Copyright 2014 Groupon, Inc
* Copyright 2014 The Billing Project, LLC
*
* The Billing Project licenses this file to you 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 org.killbill.billing;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicBoolean;
import org.killbill.billing.platform.test.PlatformDBTestingHelper;
import org.killbill.billing.util.dao.AuditLogModelDaoMapper;
import org.killbill.billing.util.dao.RecordIdIdMappingsMapper;
import org.killbill.billing.util.io.IOUtils;
import org.killbill.billing.util.security.shiro.dao.SessionModelDao;
import org.killbill.commons.embeddeddb.EmbeddedDB;
import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.IDBI;
import com.google.common.base.MoreObjects;
public class DBTestingHelper extends PlatformDBTestingHelper {
private static DBTestingHelper dbTestingHelper = null;
private AtomicBoolean initialized;
public static synchronized DBTestingHelper get() {
if (dbTestingHelper == null) {
dbTestingHelper = new DBTestingHelper();
}
return dbTestingHelper;
}
private DBTestingHelper() {
super();
initialized = new AtomicBoolean(false);
}
@Override
public IDBI getDBI() {
final DBI dbi = (DBI) super.getDBI();
// Register KB specific mappers
if (initialized.compareAndSet(false, true)) {
dbi.registerMapper(new AuditLogModelDaoMapper());
dbi.registerMapper(new RecordIdIdMappingsMapper());
dbi.registerMapper(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
}
return dbi;
}
protected synchronized void executePostStartupScripts() throws IOException {
final EmbeddedDB instance = getInstance();
final String databaseSpecificDDL = "org/killbill/billing/util/" + "ddl-" + instance.getDBEngine().name().toLowerCase() + ".sql";
installDDLSilently(databaseSpecificDDL);
// We always want the accounts and tenants table
instance.executeScript("drop table if exists accounts;" +
"CREATE TABLE accounts (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" external_key varchar(128) NULL,\n" +
" email varchar(128) NOT NULL,\n" +
" name varchar(100) NOT NULL,\n" +
" first_name_length int NOT NULL,\n" +
" currency varchar(3) DEFAULT NULL,\n" +
" billing_cycle_day_local int DEFAULT NULL,\n" +
" payment_method_id varchar(36) DEFAULT NULL,\n" +
" time_zone varchar(50) DEFAULT NULL,\n" +
" locale varchar(5) DEFAULT NULL,\n" +
" address1 varchar(100) DEFAULT NULL,\n" +
" address2 varchar(100) DEFAULT NULL,\n" +
" company_name varchar(50) DEFAULT NULL,\n" +
" city varchar(50) DEFAULT NULL,\n" +
" state_or_province varchar(50) DEFAULT NULL,\n" +
" country varchar(50) DEFAULT NULL,\n" +
" postal_code varchar(16) DEFAULT NULL,\n" +
" phone varchar(25) DEFAULT NULL,\n" +
" migrated boolean default false,\n" +
" is_notified_for_invoices boolean NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" created_by varchar(50) NOT NULL,\n" +
" updated_date datetime DEFAULT NULL,\n" +
" updated_by varchar(50) DEFAULT NULL,\n" +
" tenant_record_id bigint /*! unsigned */ not null default 0,\n" +
" PRIMARY KEY(record_id)\n" +
");");
instance.executeScript("DROP TABLE IF EXISTS tenants;\n" +
"CREATE TABLE tenants (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" external_key varchar(128) NULL,\n" +
" api_key varchar(128) NULL,\n" +
" api_secret varchar(128) NULL,\n" +
" api_salt varchar(128) NULL,\n" +
" created_date datetime NOT NULL,\n" +
" created_by varchar(50) NOT NULL,\n" +
" updated_date datetime DEFAULT NULL,\n" +
" updated_by varchar(50) DEFAULT NULL,\n" +
" PRIMARY KEY(record_id)\n" +
");");
// We always want the basic tables when we do account_record_id lookups (e.g. for custom fields, tags or junction)
instance.executeScript("DROP TABLE IF EXISTS bundles;\n" +
"CREATE TABLE bundles (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" external_key varchar(64) NOT NULL,\n" +
" account_id varchar(36) NOT NULL,\n" +
" last_sys_update_date datetime,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
" updated_date datetime NOT NULL,\n" +
" account_record_id bigint /*! unsigned */ not null,\n" +
" tenant_record_id bigint /*! unsigned */ not null default 0,\n" +
" PRIMARY KEY(record_id)\n" +
");");
instance.executeScript("DROP TABLE IF EXISTS subscriptions;\n" +
"CREATE TABLE subscriptions (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" bundle_id varchar(36) NOT NULL,\n" +
" category varchar(32) NOT NULL,\n" +
" start_date datetime NOT NULL,\n" +
" bundle_start_date datetime NOT NULL,\n" +
" active_version int DEFAULT 1,\n" +
" charged_through_date datetime DEFAULT NULL,\n" +
" paid_through_date datetime DEFAULT NULL,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
" updated_date datetime NOT NULL,\n" +
" account_record_id bigint /*! unsigned */ not null,\n" +
" tenant_record_id bigint /*! unsigned */ not null default 0,\n" +
" PRIMARY KEY(record_id)\n" +
");");
// HACK (PIERRE): required by invoice tests which perform payments lookups to find the account record id for the internal callcontext
instance.executeScript("DROP TABLE IF EXISTS payments;\n" +
"CREATE TABLE payments (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" account_id varchar(36) NOT NULL,\n" +
" invoice_id varchar(36) NOT NULL,\n" +
" payment_method_id varchar(36) NOT NULL,\n" +
" amount numeric(15,9),\n" +
" currency varchar(3),\n" +
" effective_date datetime,\n" +
" payment_status varchar(50),\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
" updated_date datetime NOT NULL,\n" +
" account_record_id bigint /*! unsigned */ not null,\n" +
" tenant_record_id bigint /*! unsigned */ not null default 0,\n" +
" PRIMARY KEY (record_id)\n" +
");");
for (final String pack : new String[]{"catalog", "account", "analytics", "beatrix", "subscription", "util", "payment", "invoice", "entitlement", "usage", "meter", "tenant"}) {
for (final String ddlFile : new String[]{"ddl.sql", "ddl_test.sql"}) {
final String resourceName = "org/killbill/billing/" + pack + "/" + ddlFile;
installDDLSilently(resourceName);
}
}
}
private void installDDLSilently(final String resourceName) throws IOException {
final ClassLoader classLoader = MoreObjects.firstNonNull(Thread.currentThread().getContextClassLoader(), DBTestingHelper.class.getClassLoader());
final Enumeration<URL> resources = classLoader.getResources(resourceName);
while (resources.hasMoreElements()) {
final URL inputStream = resources.nextElement();
final String ddl;
try {
ddl = IOUtils.toString(inputStream.openStream());
getInstance().executeScript(ddl);
} catch (final Exception ignored) {
// The test doesn't have this module ddl in the classpath - that's fine
}
}
}
}