/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.regressionsuites;
import java.io.IOException;
import org.voltdb.BackendTarget;
import org.voltdb.ClientResponseImpl;
import org.voltdb.client.Client;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.ProcCallException;
import org.voltdb.compiler.VoltProjectBuilder;
import org.voltdb_testprocs.regressionsuites.basecase.eng7181;
public class TestMPBasecaseSuite extends RegressionSuite {
static final Class<?>[] PROCEDURES = {eng7181.class};
public TestMPBasecaseSuite(String name) {
super(name);
}
void loadData(Client client) throws IOException, ProcCallException
{
loadData("P1.insert", client);
}
void loadData(String procname, Client client) throws IOException, ProcCallException
{
// inserts
for (int i=0; i < 10; i++) {
ClientResponse resp = client.callProcedure(procname, i, i, i, Integer.toHexString(i));
assertTrue(resp.getStatus() == ClientResponse.SUCCESS);
assertTrue(resp.getResults()[0].asScalarLong() == 1);
}
}
public void testOneShotRead() throws Exception
{
final Client client = this.getClient();
loadData(client);
// testcase: single-stmt read.
ClientResponse resp = client.callProcedure("CountP1");
assertTrue("Successful oneshot read.", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Expect count=10", 10L, resp.getResults()[0].asScalarLong());
}
public void testOneShotWrite() throws Exception
{
final Client client = this.getClient();
loadData(client);
ClientResponse resp = client.callProcedure("UpdateP1");
assertTrue("Successful oneshot write.", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Touched 10 rows", 10L, resp.getResults()[0].asScalarLong());
// verify the update results.
resp = client.callProcedure("SumP1");
assertTrue("Verified updates", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Updated sum=20", 20L, resp.getResults()[0].asScalarLong());
}
public void testOneShotConstraintViolationAllSites() throws Exception
{
final Client client = this.getClient();
loadData(client);
boolean caught = false;
try {
client.callProcedure("ConstraintViolationUpdate");
assertFalse("Failed to produce constraint violation", true);
}
catch (ProcCallException e) {
assertEquals("Client response is rollback.",
ClientResponse.GRACEFUL_FAILURE, e.getClientResponse().getStatus());
caught = true;
}
assertTrue("Expected exception.", caught);
// verify initial result is unchanged (transactions!)
ClientResponse resp = client.callProcedure("SumB1");
assertTrue("Verified updates", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Updated sum=45", 45L, resp.getResults()[0].asScalarLong());
}
public void testOneshotPartitionViolationAllSites() throws Exception
{
// Restrict to clustered tests (configured with > 1 partition)
LocalCluster config = (LocalCluster)this.getServerConfig();
int sites = config.m_siteCount;
int nodes = config.m_hostCount;
int k = config.m_kfactor;
int parts = (nodes * sites) / (k + 1);
if (parts == 1) {
return;
}
final Client client = this.getClient();
loadData(client);
try {
client.callProcedure("PartitionViolationUpdate");
assertFalse("Failed to produce violation", true);
}
catch (ProcCallException e) {
assertEquals("Client response is not graceful failure.",
ClientResponse.GRACEFUL_FAILURE, e.getClientResponse().getStatus());
}
// verify initial result is unchanged (transactions!)
ClientResponse resp = client.callProcedure("SumKey");
assertTrue("Verified updates", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Updated sum=45", 45L, resp.getResults()[0].asScalarLong());
// see ENG-2941
assertTrue(resp.getStatusString() == null);
}
public void testOneshotReplicatedWriteAndRead() throws Exception
{
final Client client = this.getClient();
loadData("R1.insert", client);
ClientResponse resp = client.callProcedure("SumR1");
assertTrue("OK response", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Expected sum=45", 45L, resp.getResults()[0].asScalarLong());
}
public void testOneshotReplicatedConstraintViolation() throws Exception
{
final Client client = this.getClient();
boolean caught = false;
loadData("R1.insert", client);
try {
client.callProcedure("ConstraintViolationUpdate_R");
assertTrue("Failed to produce constraint violation", false);
}
catch (ProcCallException e) {
assertEquals("Client response is rollback.",
ClientResponse.GRACEFUL_FAILURE, e.getClientResponse().getStatus());
caught = true;
}
assertTrue("Caught expected", caught);
// verify initial result is unchanged (transactions!)
ClientResponse resp = client.callProcedure("SumB1_R");
assertTrue("Verified updates", resp.getStatus() == ClientResponse.SUCCESS);
assertEquals("Updated sum=45", 45L, resp.getResults()[0].asScalarLong());
}
// Validate that if the first thing done by a transaction is a read from a
// replicated table, that we don't mistakenly fail to create and use undo
// tokens on rollback.
public void testEng7181() throws Exception
{
System.out.println("-------------\n\n testEng7181 \n\n-------------");
final Client client = this.getClient();
ClientResponse resp = client.callProcedure("CountR1");
assertEquals(0, resp.getResults()[0].getRowCount());
// Add a row
resp = client.callProcedure("eng7181", 42, 0);
resp = client.callProcedure("CountR1");
assertEquals(1, resp.getResults()[0].getRowCount());
try {
// do borrow work, then insert, then rollback
resp = client.callProcedure("eng7181", 43, 1);
}
catch (ProcCallException pce) {
}
// Verify rollback happened
resp = client.callProcedure("CountR1");
assertEquals(1, resp.getResults()[0].getRowCount());
}
static public junit.framework.Test suite() {
VoltServerConfig config = null;
final MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(TestMPBasecaseSuite.class);
final VoltProjectBuilder project = new VoltProjectBuilder();
project.addStmtProcedure("CountP1", "select count(*) from p1;");
project.addStmtProcedure("CountR1", "select * from r1;");
// update non-unique, non-partitioning attribute
project.addStmtProcedure("UpdateP1", "update p1 set b2 = 2");
project.addStmtProcedure("SumP1", "select sum(b2) from p1;");
project.addStmtProcedure("UpdateR1", "update r1 set b2 = 2");
project.addStmtProcedure("SumR1", "select sum(b2) from r1;");
// update all pkeys to the same value.
project.addStmtProcedure("ConstraintViolationUpdate", "update p1 set b1 = 1");
project.addStmtProcedure("SumB1", "select sum(b1) from p1;");
project.addStmtProcedure("ConstraintViolationUpdate_R", "update r1 set b1 = 1");
project.addStmtProcedure("SumB1_R", "select sum(b1) from r1;");
// update all partitioning keys to the same value.
project.addStmtProcedure("PartitionViolationUpdate", "update p1 set key = 1");
project.addStmtProcedure("SumKey", "select sum(key) from p1;");
project.addProcedures(PROCEDURES);
try {
project.addLiteralSchema(
"CREATE TABLE p1(key INTEGER NOT NULL, b1 INTEGER NOT NULL assumeunique, " +
"b2 INTEGER NOT NULL, a2 VARCHAR(10) NOT NULL, PRIMARY KEY (b1, key)); " +
"PARTITION TABLE P1 ON COLUMN key;"
);
// a replicated table (should not generate procedures).
project.addLiteralSchema(
"CREATE TABLE r1(key INTEGER NOT NULL, b1 INTEGER NOT NULL, " +
"b2 INTEGER NOT NULL, a2 VARCHAR(10) NOT NULL, PRIMARY KEY (b1));"
);
} catch (IOException error) {
fail(error.getMessage());
}
// JNI
config = new LocalCluster("sqltypes-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_JNI);
boolean t1 = config.compile(project);
assertTrue(t1);
builder.addServerConfig(config);
config = new LocalCluster("sqltypes-onesite.jar", 3, 1, 0, BackendTarget.NATIVE_EE_JNI);
boolean t3 = config.compile(project);
assertTrue(t3);
builder.addServerConfig(config);
// CLUSTER
config = new LocalCluster("sqltypes-cluster.jar", 2, 3, 1, BackendTarget.NATIVE_EE_JNI);
boolean t2 = config.compile(project);
assertTrue(t2);
builder.addServerConfig(config);
return builder;
}
}