package com.tesora.dve.sql;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.server.bootstrap.BootstrapHost;
import com.tesora.dve.sql.util.ConnectionResource;
import com.tesora.dve.sql.util.DBHelperConnectionResource;
import com.tesora.dve.sql.util.ListOfPairs;
import com.tesora.dve.sql.util.MirrorTest;
import com.tesora.dve.sql.util.Pair;
import com.tesora.dve.sql.util.PortalDBHelperConnectionResource;
import com.tesora.dve.sql.util.ProjectDDL;
import com.tesora.dve.sql.util.ResourceResponse;
import com.tesora.dve.sql.util.TestResource;
import com.tesora.dve.standalone.PETest;
public abstract class SchemaMirrorTest extends SchemaTest {
protected TestResource sysResource;
protected TestResource checkResource;
protected TestResource nativeResource;
protected boolean useUTF8 = true;
public void setUseUTF8(boolean useUTF8) {
this.useUTF8 = useUTF8;
}
protected ProjectDDL getMultiDDL() {
return null;
}
protected ProjectDDL getSingleDDL() {
return null;
}
protected ProjectDDL getNativeDDL() {
return null;
}
protected static void setup(ProjectDDL multiDDL, ProjectDDL singleDDL, ProjectDDL nativeDDL, List<MirrorTest> populate) throws Throwable {
ArrayList<ProjectDDL> exists = new ArrayList<ProjectDDL>();
if (multiDDL != null) exists.add(multiDDL);
if (singleDDL != null) exists.add(singleDDL);
if (nativeDDL != null) exists.add(nativeDDL);
PETest.projectSetup(exists.toArray(new ProjectDDL[0]));
PETest.bootHost = BootstrapHost.startServices(PETest.class);
// putting the load into the per class portion
// then we can have real test cases (almost)
PortalDBHelperConnectionResource sysconn = (multiDDL == null ? null : new PortalDBHelperConnectionResource());
PortalDBHelperConnectionResource checkconn = (singleDDL == null ? null : new PortalDBHelperConnectionResource());
DBHelperConnectionResource nativeConn = (nativeDDL == null ? null : new DBHelperConnectionResource());
try {
TestResource smr = (multiDDL == null ? null : new TestResource(sysconn, multiDDL));
TestResource cmr = (singleDDL == null ? null : new TestResource(checkconn, singleDDL));
TestResource nmr = (nativeDDL == null ? null : new TestResource(nativeConn, nativeDDL));
ArrayList<TestResource> trs = new ArrayList<TestResource>();
if (smr != null)
trs.add(smr);
if (cmr != null)
trs.add(cmr);
if (nmr != null)
trs.add(nmr);
for (TestResource tr : trs)
tr.getDDL().create(tr);
for (TestResource tr : trs) {
for (MirrorTest mt : populate)
mt.execute(tr, null);
}
} finally {
if (sysconn != null)
sysconn.disconnect();
if (checkconn != null)
checkconn.disconnect();
if (nativeConn != null)
nativeConn.disconnect();
}
}
@Before
public void connect() throws Throwable {
if (getMultiDDL() != null)
sysResource = new TestResource(createConnection(getMultiDDL()), getMultiDDL());
if (getSingleDDL() != null)
checkResource = new TestResource(createConnection(getSingleDDL()), getSingleDDL());
if (getNativeDDL() != null)
nativeResource = new TestResource(createConnection(getNativeDDL()), getNativeDDL());
TestResource[] trs = new TestResource[] { sysResource, checkResource, nativeResource };
for(TestResource tr : trs)
if (tr != null)
onConnect(tr);
}
public ConnectionResource getMultiConnection() {
if (sysResource == null) return null;
return sysResource.getConnection();
}
public ConnectionResource getSingleConnection() {
if (checkResource == null) return null;
return checkResource.getConnection();
}
public ConnectionResource getNativeConnection() {
if (nativeResource == null) return null;
return nativeResource.getConnection();
}
protected ConnectionResource createConnection(ProjectDDL p) throws Throwable {
if (p == getNativeDDL())
return new DBHelperConnectionResource(useUTF8);
else if (p == getMultiDDL() || p == getSingleDDL())
return new PortalDBHelperConnectionResource(useUTF8);
throw new PEException("ProjectDDL of unknown type " + p.getClass());
}
protected void onConnect(TestResource tr) throws Throwable {
tr.getConnection().execute("use " + tr.getDDL().getDatabaseName());
}
@After
public void disconnect() throws Throwable {
if (sysResource != null)
sysResource.getConnection().disconnect();
if (checkResource != null)
checkResource.getConnection().disconnect();
if (nativeResource != null)
nativeResource.getConnection().disconnect();
sysResource = null;
checkResource = null;
nativeResource = null;
}
protected void runTest(MirrorTest single) throws Throwable {
runTest(Collections.singletonList(single));
}
protected void runTest(List<MirrorTest> tests) throws Throwable {
ListOfPairs<TestResource, TestResource> c = new ListOfPairs<TestResource,TestResource>();
c.add(nativeResource, checkResource);
c.add(nativeResource, sysResource);
runTest(tests, c, true);
}
protected ListOfPairs<TestResource,TestResource> getTestConfig() {
ListOfPairs<TestResource, TestResource> c = new ListOfPairs<TestResource,TestResource>();
c.add(nativeResource, checkResource);
c.add(nativeResource, sysResource);
return c;
}
protected void runTest(List<MirrorTest> tests, ListOfPairs<TestResource,TestResource> configs, boolean omitMissingRHS) throws Throwable {
for(Pair<TestResource, TestResource> p : configs) {
if (p.getSecond() == null && omitMissingRHS) continue;
for(MirrorTest mt : tests) {
mt.execute(p.getFirst(), p.getSecond());
}
}
}
protected void runSerialNoMirror(List<MirrorTest> tests) throws Throwable {
ListOfPairs<TestResource, TestResource> c = new ListOfPairs<TestResource, TestResource>();
if (nativeResource != null) c.add(nativeResource,null);
if (checkResource != null) c.add(checkResource,null);
if (sysResource != null) c.add(sysResource,null);
runTest(tests, c, false);
}
/**
* Facilitates extended packet mirror testing by handling necessary variable
* and setting updates.
*/
protected class ExtendedPacketTester {
private static final long VARIABLE_REFRESH_WAIT_TIME_SEC = 10;
private static final long DEFAULT_MAX_ALLOWED_PACKET_SIZE = 16777216;
private final long maxAllowedPacketSize;
private boolean useFormatedOutput = false;
private final ArrayList<MirrorTest> tests = new ArrayList<MirrorTest>();
/**
* @param maxAllowedPacketSize
* Value of 'max_allowed_packet' global variable used in the
* test.
*/
public ExtendedPacketTester(final long maxAllowedPacketSize) {
this.maxAllowedPacketSize = maxAllowedPacketSize;
}
/**
* Execute the mirror tests.
*/
public void runTests() throws Throwable {
try {
resetMaxAllowedPacketVariable(this.maxAllowedPacketSize);
ResourceResponse.BLOB_COLUMN.useFormatedOutput(this.useFormatedOutput);
// Refresh the 'max_allowed_packet' variable.
disconnect();
TimeUnit.SECONDS.sleep(VARIABLE_REFRESH_WAIT_TIME_SEC); //TODO: hack to deal with race condition where fast disconnect/reconnect after a response still picks up old value. -sgossard
connect();
test();
} finally {
ResourceResponse.BLOB_COLUMN.useFormatedOutput(true);
resetMaxAllowedPacketVariable(DEFAULT_MAX_ALLOWED_PACKET_SIZE);
}
}
/**
* Run mirror tests.
*/
protected void test() throws Throwable {
SchemaMirrorTest.this.runTest(this.tests);
}
/**
* Add MirrorTest to the suite.
*/
public void add(final MirrorTest test) {
this.tests.add(test);
}
/**
* Add MirrorTests to the suite.
*/
public void addAll(final Collection<MirrorTest> tests) {
this.tests.addAll(tests);
}
/**
* Remove all MirrorTest currently in the suite.
*/
public void clear() {
this.tests.clear();
}
/**
* Formatted output on large packets may lead to heap exhaustion in
* StringBuilder.
*/
public void enableFormatedOutput() {
this.useFormatedOutput = true;
}
private void resetMaxAllowedPacketVariable(final long value) throws Throwable {
SchemaMirrorTest.this.runTest(new StatementMirrorProc("SET GLOBAL max_allowed_packet = " + String.valueOf(value)));
}
}
}