/* 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.
*/
/*
Copyright (c) 2008 Twilio, 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 OR COPYRIGHT
HOLDERS 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.
*/
/*
* What's up with the Twilio stuff? They have MIT licensed
* REST clients in lots of languages, even Java. It's not a
* direct copy/paste, but this code borrows heavily from what
* they did in a few ways.
* Thanks Twilio!
*/
package org.voltdb;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.json_voltpatches.JSONArray;
import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.voltcore.utils.CoreUtils;
import org.voltdb.VoltDB.Configuration;
import org.voltdb.client.Client;
import org.voltdb.client.ClientAuthScheme;
import org.voltdb.client.ClientConfig;
import org.voltdb.client.ClientFactory;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.ProcedureCallback;
import org.voltdb.compiler.VoltProjectBuilder;
import org.voltdb.compiler.VoltProjectBuilder.ProcedureInfo;
import org.voltdb.compiler.VoltProjectBuilder.RoleInfo;
import org.voltdb.compiler.VoltProjectBuilder.UserInfo;
import org.voltdb.compiler.deploymentfile.DeploymentType;
import org.voltdb.compiler.deploymentfile.HeartbeatType;
import org.voltdb.compiler.deploymentfile.ResourceMonitorType;
import org.voltdb.compiler.deploymentfile.ResourceMonitorType.Memorylimit;
import org.voltdb.compiler.deploymentfile.SnmpType;
import org.voltdb.compiler.deploymentfile.SystemSettingsType;
import org.voltdb.compiler.deploymentfile.SystemSettingsType.Query;
import org.voltdb.compiler.deploymentfile.UsersType;
import org.voltdb.compiler.procedures.CrazyBlahProc;
import org.voltdb.compiler.procedures.DelayProc;
import org.voltdb.compiler.procedures.SelectStarHelloWorld;
import org.voltdb.types.TimestampType;
import org.voltdb.utils.Base64;
import org.voltdb.utils.Encoder;
import org.voltdb.utils.MiscUtils;
import junit.framework.TestCase;
public class TestJSONInterface extends TestCase {
final static ContentType utf8ApplicationFormUrlEncoded =
ContentType.create("application/x-www-form-urlencoded","UTF-8");
private static final String VALID_JSONP = "good_$123";
private static final String INVALID_JSONP;
private static final Set<Integer> HANDLED_CLIENT_ERRORS = new HashSet<>();
static {
String pval = "jQuery111106314619798213243_1487039392105\"'></XSS/*-*/STYLE=xss:e/**/xpression(try{a=firstTime}catch(e){firstTime=1;alert(9096)})>";
try {
pval = URLEncoder.encode("jQuery111106314619798213243_1487039392105\"'></XSS/*-*/STYLE=xss:e/**/xpression(try{a=firstTime}catch(e){firstTime=1;alert(9096)})>", "UTF-8");
} catch (UnsupportedEncodingException e) {
}
INVALID_JSONP = pval;
HANDLED_CLIENT_ERRORS.add(400);
HANDLED_CLIENT_ERRORS.add(401);
HANDLED_CLIENT_ERRORS.add(404);
}
ServerThread server;
Client client;
public final static String protocolPrefix = ClientConfig.ENABLE_SSL_FOR_TEST ? "https://" : "http://";
static class Response {
public byte status = 0;
public String statusString = null;
public byte appStatus = Byte.MIN_VALUE;
public String appStatusString = null;
public VoltTable[] results = new VoltTable[0];
public String exception = null;
}
static String japaneseTestVarStrings = "Procedure=Insert&Parameters=%5B%22%5Cu3053%5Cu3093%5Cu306b%5Cu3061%5Cu306f%22%2C%22%5Cu4e16%5Cu754c%22%2C%22Japanese%22%5D";
static String getHTTPVarString(Map<String, String> params) throws UnsupportedEncodingException {
String s = "";
if (params == null) return s;
for (Entry<String, String> e : params.entrySet()) {
String encodedValue = URLEncoder.encode(e.getValue(), "UTF-8");
s += "&" + e.getKey() + "=" + encodedValue;
}
s = s.substring(1);
return s;
}
static String getHTTPURL(Integer port, String path) {
if (port == null) {
port = VoltDB.DEFAULT_HTTP_PORT;
}
return String.format(protocolPrefix + "localhost:%d/%s", port, path);
}
public static String callProcOverJSONRaw(Map<String, String> params, final int expectedCode) throws Exception {
return httpUrlOverJSON("POST", protocolPrefix + "localhost:8095/api/1.0/", null, null, null, expectedCode, null, params);
}
public static String callProcOverJSONRaw(Map<String, String> params, int httpPort, final int expectedCode) throws Exception {
return httpUrlOverJSON("POST", protocolPrefix + "localhost:" + httpPort + "/api/1.0/", null, null, null, expectedCode, null, params);
}
public static String callProcOverJSONRaw(String varString, final int expectedCode) throws Exception {
return httpUrlOverJSONExecute("POST", protocolPrefix + "localhost:8095/api/1.0/", null, null, null, expectedCode, null, varString);
}
public static String getUrlOverJSON(String url, String user, String password, String scheme, int expectedCode, String expectedCt) throws Exception {
return httpUrlOverJSON("GET", url, user, password, scheme, expectedCode, expectedCt, null);
}
public static String postUrlOverJSON(String url, String user, String password, String scheme, int expectedCode, String expectedCt, Map<String,String> params) throws Exception {
return httpUrlOverJSON("POST", url, user, password, scheme, expectedCode, expectedCt, params);
}
private static String putUrlOverJSON(String url, String user, String password, String scheme, int expectedCode, String expectedCt, Map<String,String> params) throws Exception {
return httpUrlOverJSON("PUT", url, user, password, scheme, expectedCode, expectedCt, params);
}
private static String deleteUrlOverJSON(String url, String user, String password, String scheme, int expectedCode, String expectedCt) throws Exception {
return httpUrlOverJSON("DELETE", url, user, password, scheme, expectedCode, expectedCt, null);
}
private static String httpUrlOverJSONExecute(String method, String url, String user, String password, String scheme, int expectedCode, String expectedCt, String varString) throws Exception {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (X509Certificate[] arg0, String arg1) -> true).build();
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(sslContext,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sf)
.build();
// allows multi-threaded use
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClientBuilder hb = HttpClientBuilder.create();
hb.setSslcontext(sslContext);
hb.setConnectionManager(connMgr);
try (CloseableHttpClient httpclient = hb.build()) {
HttpRequestBase request;
switch (method) {
case "POST":
HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity(varString, utf8ApplicationFormUrlEncoded));
request = post;
break;
case "PUT":
HttpPut put = new HttpPut(url);
put.setEntity(new StringEntity(varString, utf8ApplicationFormUrlEncoded));
request = put;
break;
case "DELETE":
HttpDelete delete = new HttpDelete(url);
request = delete;
break;
case "GET":
request = new HttpGet(url + ((varString != null && varString.trim().length() > 0) ? ("?" + varString.trim()) : ""));
break;
default:
request = new HttpGet(url + ((varString != null && varString.trim().length() > 0) ? ("?" + varString.trim()) : ""));
break;
}
// play nice by using HTTP 1.1 continue requests where the client sends the request headers first
// to the server to see if the server is willing to accept it. This allows us to test large requests
// without incurring server socket connection terminations
RequestConfig rc = RequestConfig.copy(RequestConfig.DEFAULT).setExpectContinueEnabled(true).build();
request.setProtocolVersion(HttpVersion.HTTP_1_1);
request.setConfig(rc);
if (user != null && password != null) {
if (scheme.equalsIgnoreCase("hashed")) {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte hashedPasswordBytes[] = md.digest(password.getBytes("UTF-8"));
String h = user + ":" + Encoder.hexEncode(hashedPasswordBytes);
request.setHeader("Authorization", "Hashed " + h);
} else if (scheme.equalsIgnoreCase("hashed256")) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte hashedPasswordBytes[] = md.digest(password.getBytes("UTF-8"));
String h = user + ":" + Encoder.hexEncode(hashedPasswordBytes);
request.setHeader("Authorization", "Hashed " + h);
} else if (scheme.equalsIgnoreCase("basic")) {
request.setHeader("Authorization", "Basic " + new String(Base64.encodeToString(new String(user + ":" + password).getBytes(), false)));
}
}
ResponseHandler<String> rh = new ResponseHandler<String>() {
@Override
public String handleResponse(final HttpResponse response) throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
String ct = response.getHeaders("Content-Type")[0].getValue();
if (expectedCt != null) {
assertTrue(ct.contains(expectedCt));
}
assertEquals(expectedCode, status);
if ((status >= 200 && status < 300) || HANDLED_CLIENT_ERRORS.contains(status)) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
}
return null;
}
};
return httpclient.execute(request,rh);
}
}
private static String httpUrlOverJSON(String method, String url, String user, String password, String scheme, int expectedCode, String expectedCt, Map<String,String> params) throws Exception {
return httpUrlOverJSONExecute(method, url, user, password, scheme, expectedCode, expectedCt, getHTTPVarString(params));
}
public static String getHashedPasswordForHTTPVar(String password, ClientAuthScheme scheme) {
assert (password != null);
MessageDigest md = null;
try {
md = MessageDigest.getInstance(ClientAuthScheme.getDigestScheme(scheme));
} catch (NoSuchAlgorithmException e) {
fail();
}
byte hashedPassword[] = null;
try {
hashedPassword = md.digest(password.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("JVM doesn't support UTF-8. Please use a supported JVM", e);
}
String retval = Encoder.hexEncode(hashedPassword);
assertEquals(ClientAuthScheme.getHexencodedDigestLength(scheme), retval.length());
return retval;
}
public static String callProcOverJSON(String procName, ParameterSet pset, String username, String password, boolean preHash) throws Exception {
return callProcOverJSON(procName, pset, username, password, preHash, false, 200 /* HTTP_OK */, ClientAuthScheme.HASH_SHA256);
}
public static String callProcOverJSON(String procName, ParameterSet pset, String username, String password, boolean preHash, boolean admin) throws Exception {
return callProcOverJSON(procName, pset, username, password, preHash, admin, 200 /* HTTP_OK */, ClientAuthScheme.HASH_SHA256);
}
public static String callProcOverJSON(String procName, ParameterSet pset, String username, String password, boolean preHash, boolean admin, int expectedCode, ClientAuthScheme scheme) throws Exception {
return callProcOverJSON(procName, pset, 8095, username, password, preHash, admin, expectedCode /* HTTP_OK */, scheme, -1);
}
public static String callProcOverJSON(String procName, ParameterSet pset, int httpPort, String username, String password, boolean preHash, boolean admin, int expectedCode, ClientAuthScheme scheme, int procCallTimeout) throws Exception {
// Call insert
String paramsInJSON = pset.toJSONString();
//System.out.println(paramsInJSON);
Map<String, String> params = new HashMap<>();
params.put("Procedure", procName);
params.put("Parameters", paramsInJSON);
if (procCallTimeout > 0) {
params.put(HTTPClientInterface.QUERY_TIMEOUT_PARAM, String.valueOf(procCallTimeout));
}
if (username != null) {
params.put("User", username);
}
if (password != null) {
if (preHash) {
params.put("Hashedpassword", getHashedPasswordForHTTPVar(password, scheme));
} else {
params.put("Password", password);
}
}
if (admin) {
params.put("admin", "true");
}
String ret = callProcOverJSONRaw(params, httpPort, expectedCode);
// Update application catalog sometimes changes the password.
// The second procedure call will fail in that case, so don't call it a second time.
if (preHash && !procName.equals("@UpdateApplicationCatalog")) {
//If prehash make same call with SHA1 to check expected code.
params.put("Hashedpassword", getHashedPasswordForHTTPVar(password, ClientAuthScheme.HASH_SHA1));
callProcOverJSONRaw(params, httpPort, expectedCode);
}
return ret;
}
public static Response responseFromJSON(String jsonStr) throws JSONException, IOException {
Response response = new Response();
JSONObject jsonObj = new JSONObject(jsonStr);
JSONArray resultsJson = jsonObj.getJSONArray("results");
response.results = new VoltTable[resultsJson.length()];
for (int i = 0; i < response.results.length; i++) {
JSONObject tableJson = resultsJson.getJSONObject(i);
response.results[i] = VoltTable.fromJSONObject(tableJson);
}
if (jsonObj.isNull("status") == false) {
response.status = (byte) jsonObj.getInt("status");
}
if (jsonObj.isNull("appstatus") == false) {
response.appStatus = (byte) jsonObj.getInt("appstatus");
}
if (jsonObj.isNull("statusstring") == false) {
response.statusString = jsonObj.getString("statusstring");
}
if (jsonObj.isNull("appstatusstring") == false) {
response.appStatusString = jsonObj.getString("appstatusstring");
}
if (jsonObj.isNull("exception") == false) {
response.exception = jsonObj.getString("exception");
}
return response;
}
public void testPausedMode() throws Exception {
try {
String testSchema
= "CREATE TABLE foo (\n"
+ " ival bigint default 23 not null, "
+ " sval varchar(200) default 'foo', "
+ " PRIMARY KEY (ival)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(testSchema);
builder.addPartitionInfo("foo", "ival");
builder.addStmtProcedure("fooinsert", "insert into foo values (?, ?);");
builder.addStmtProcedure("foocount", "select count(*) from foo;");
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
int pkStart = 0;
pkStart = runPauseTests(pkStart, false, false);
pkStart = runPauseTests(pkStart, false, true);
// pause server
ParameterSet pset = ParameterSet.emptyParameterSet();
Response response = responseFromJSON(callProcOverJSON("@Pause", pset, null, null, false, true));
assertTrue(response.status == ClientResponse.SUCCESS);
pkStart = runPauseTests(pkStart, true, false);
pkStart = runPauseTests(pkStart, true, true);
// resume server
pset = ParameterSet.emptyParameterSet();
response = responseFromJSON(callProcOverJSON("@Resume", pset, null, null, false, true));
assertTrue(response.status == ClientResponse.SUCCESS);
pkStart = runPauseTests(pkStart, false, false);
pkStart = runPauseTests(pkStart, false, true);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
private int runPauseTests(int pkStart, boolean paused, boolean useAdmin) throws Exception {
ParameterSet pset;
String responseJSON;
Response response;
pset = ParameterSet.fromArrayNoCopy(pkStart++, "hello");
responseJSON = callProcOverJSON("fooinsert", pset, null, null, false, useAdmin);
response = responseFromJSON(responseJSON);
if (paused && !useAdmin) {
assertEquals(ClientResponse.SERVER_UNAVAILABLE, response.status);
assertTrue(response.statusString.contains("is paused"));
pkStart--;
} else {
assertEquals(ClientResponse.SUCCESS, response.status);
assertEquals(1L, response.results[0].fetchRow(0).getLong(0));
}
pset = ParameterSet.emptyParameterSet();
responseJSON = callProcOverJSON("foocount", pset, null, null, false, useAdmin);
response = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, response.status);
assertEquals(pkStart, response.results[0].fetchRow(0).getLong(0));
// try AdHoc
pset = ParameterSet.fromArrayNoCopy("insert into foo values (" + (pkStart++) + ", 'adhochello')");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false, useAdmin);
response = responseFromJSON(responseJSON);
if (paused && !useAdmin) {
assertEquals(ClientResponse.SERVER_UNAVAILABLE, response.status);
assertTrue(response.statusString.contains("is paused"));
pkStart--;
} else {
assertEquals(ClientResponse.SUCCESS, response.status);
}
pset = ParameterSet.fromArrayNoCopy("select count(*) from foo");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false, useAdmin);
response = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, response.status);
assertEquals(pkStart, response.results[0].fetchRow(0).getLong(0));
return pkStart;
}
public void testaUpdateDeploymentSnmpConfig() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment
String jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
Map<String,String> params = new HashMap<>();
ObjectMapper mapper = new ObjectMapper();
DeploymentType deptype = mapper.readValue(jdep, DeploymentType.class);
SnmpType snmpConfig = new SnmpType();
snmpConfig.setTarget("localhost");
deptype.setSnmp(snmpConfig);
String ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
String pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
DeploymentType gotValue = mapper.readValue(jdep, DeploymentType.class);
assertEquals("public", gotValue.getSnmp().getCommunity());
snmpConfig.setCommunity("foobar");
deptype.setSnmp(snmpConfig);
ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
gotValue = mapper.readValue(jdep, DeploymentType.class);
assertEquals("foobar", gotValue.getSnmp().getCommunity());
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testAJAXAndClientTogether() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(simpleSchema);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
client = ClientFactory.createClient(new ClientConfig());
client.createConnection("localhost");
final AtomicLong fcnt = new AtomicLong(0);
final AtomicLong scnt = new AtomicLong(0);
final AtomicLong cfcnt = new AtomicLong(0);
final AtomicLong cscnt = new AtomicLong(0);
final int jsonRunnerCount = 50;
final int clientRunnerCount = 50;
final ParameterSet pset = ParameterSet.fromArrayNoCopy("select count(*) from foo");
String responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
Response r = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, r.status);
//Do replicated table read.
class JSONRunner implements Runnable {
@Override
public void run() {
try {
String rresponseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println("Response: " + rresponseJSON);
Response rr = responseFromJSON(rresponseJSON);
assertEquals(ClientResponse.SUCCESS, rr.status);
scnt.incrementAndGet();
} catch (Exception ex) {
fcnt.incrementAndGet();
ex.printStackTrace();
}
}
}
//Do replicated table read.
class ClientRunner implements Runnable {
class Callback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse clientResponse) throws Exception {
if (clientResponse.getStatus() == ClientResponse.SUCCESS) {
cscnt.incrementAndGet();
} else {
System.out.println("Client failed: " + clientResponse.getStatusString());
cfcnt.incrementAndGet();
}
}
}
@Override
public void run() {
try {
if (!client.callProcedure(new Callback(), "@AdHoc", "SELECT count(*) from foo")) {
cfcnt.decrementAndGet();
}
} catch (Exception ex) {
fcnt.incrementAndGet();
ex.printStackTrace();
}
}
}
//Start runners
ExecutorService es = CoreUtils.getBoundedSingleThreadExecutor("runners", jsonRunnerCount);
for (int i = 0; i < jsonRunnerCount; i++) {
es.submit(new JSONRunner());
}
ExecutorService ces = CoreUtils.getBoundedSingleThreadExecutor("crunners", clientRunnerCount);
for (int i = 0; i < clientRunnerCount; i++) {
ces.submit(new ClientRunner());
}
es.shutdown();
es.awaitTermination(1, TimeUnit.DAYS);
assertEquals(jsonRunnerCount, scnt.get());
ces.shutdown();
ces.awaitTermination(1, TimeUnit.DAYS);
client.drain();
assertEquals(clientRunnerCount, cscnt.get());
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
r = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, r.status);
//Make sure we are still good.
ClientResponse resp = client.callProcedure("@AdHoc", "SELECT count(*) from foo");
assertEquals(ClientResponse.SUCCESS, resp.getStatus());
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
if (client != null) {
client.close();
}
}
}
public void testAdminMode() throws Exception {
try {
String simpleSchema
= "create table blah ("
+ "ival bigint default 23 not null, "
+ "sval varchar(200) default 'foo', "
+ "dateval timestamp, "
+ "fval float, "
+ "decval decimal, "
+ "PRIMARY KEY(ival));";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltDB.Configuration config = new VoltDB.Configuration();
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("blah", "ival");
builder.addStmtProcedure("Insert", "insert into blah values (?,?,?,?,?);");
builder.addProcedures(CrazyBlahProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"), 1, 1, 0, 0) != null;
assertTrue(success);
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
config.m_adminPort = 21213;
config.m_isPaused = true;
server = new ServerThread(config);
server.start();
server.waitForInitialization();
ParameterSet pset;
String responseJSON;
Response response;
// Call insert on admin port
pset = ParameterSet.fromArrayNoCopy(1, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, true);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// Call insert on closed client port and expect failure
pset = ParameterSet.fromArrayNoCopy(2, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SERVER_UNAVAILABLE);
// open client port
pset = ParameterSet.emptyParameterSet();
responseJSON = callProcOverJSON("@Resume", pset, null, null, false, true);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// call insert on open client port
pset = ParameterSet.fromArrayNoCopy(2, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// call insert on admin port again (now that both ports are open)
pset = ParameterSet.fromArrayNoCopy(3, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, true);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// put the system in admin mode
pset = ParameterSet.emptyParameterSet();
responseJSON = callProcOverJSON("@Pause", pset, null, null, false, true);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// Call insert on admin port
pset = ParameterSet.fromArrayNoCopy(4, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, true);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// Call insert on closed client port and expect failure
pset = ParameterSet.fromArrayNoCopy(5, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SERVER_UNAVAILABLE);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testSimple() throws Exception {
try {
String simpleSchema
= "create table blah ("
+ "ival bigint default 23 not null, "
+ "sval varchar(200) default 'foo', "
+ "dateval timestamp, "
+ "fval float, "
+ "decval decimal, "
+ "PRIMARY KEY(ival));";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltDB.Configuration config = new VoltDB.Configuration();
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("blah", "ival");
builder.addStmtProcedure("Insert", "insert into blah values (?,?,?,?,?);");
builder.addProcedures(CrazyBlahProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"), 1, 1, 0, 0) != null;
assertTrue(success);
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
ParameterSet pset;
String responseJSON;
Response response;
// Call insert
pset = ParameterSet.fromArrayNoCopy(1, "hello", new TimestampType(System.currentTimeMillis()), 5.0, "5.0");
responseJSON = callProcOverJSON("Insert", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status == ClientResponse.SUCCESS);
// Call insert again (with failure expected)
responseJSON = callProcOverJSON("Insert", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertTrue(response.status != ClientResponse.SUCCESS);
// Call proc with complex params
pset = ParameterSet.fromArrayNoCopy(1,
5,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
new BigDecimal(5),
new BigDecimal[]{},
new TimestampType(System.currentTimeMillis()));
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, response.status);
// check the JSON itself makes sense
JSONObject jsonObj = new JSONObject(responseJSON);
JSONArray results = jsonObj.getJSONArray("results");
assertEquals(4, response.results.length);
JSONObject table = results.getJSONObject(0);
JSONArray data = table.getJSONArray("data");
assertEquals(1, data.length());
JSONArray row = data.getJSONArray(0);
assertEquals(1, row.length());
long value = row.getLong(0);
assertEquals(1, value);
// try to pass a string as a date
java.sql.Timestamp ts = new java.sql.Timestamp(System.currentTimeMillis());
ts.setNanos(123456000);
pset = ParameterSet.fromArrayNoCopy(1,
5,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
new BigDecimal(5),
new BigDecimal[]{},
ts.toString());
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, response.status);
response.results[3].advanceRow();
System.out.println(response.results[3].getTimestampAsTimestamp(0).getTime());
assertEquals(123456, response.results[3].getTimestampAsTimestamp(0).getTime() % 1000000);
// now try a null short value sent as a int (param expects short)
pset = ParameterSet.fromArrayNoCopy(1,
VoltType.NULL_SMALLINT,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
new BigDecimal(5),
new BigDecimal[]{},
new TimestampType(System.currentTimeMillis()));
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertFalse(response.status == ClientResponse.SUCCESS);
// now try an out of range long value (param expects short)
pset = ParameterSet.fromArrayNoCopy(1,
Long.MAX_VALUE - 100,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
new BigDecimal(5),
new BigDecimal[]{},
new TimestampType(System.currentTimeMillis()));
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
assertFalse(response.status == ClientResponse.SUCCESS);
// now try bigdecimal with small value
pset = ParameterSet.fromArrayNoCopy(1,
4,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
5,
new BigDecimal[]{},
new TimestampType(System.currentTimeMillis()));
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
// now try null
pset = ParameterSet.fromArrayNoCopy(1,
4,
new double[]{1.5, 6.0, 4},
new VoltTable(new VoltTable.ColumnInfo("foo", VoltType.BIGINT)),
5,
new BigDecimal[]{},
null);
responseJSON = callProcOverJSON("CrazyBlahProc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
// now try jsonp
responseJSON = callProcOverJSONRaw("Procedure=@Statistics&Parameters=[TABLE]&jsonp=fooBar", 200);
System.out.println(responseJSON);
assertTrue(responseJSON.startsWith("fooBar("));
// now try adhoc
pset = ParameterSet.fromArrayNoCopy("select * from blah");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
// now try adhoc insert with a huge bigint
pset = ParameterSet.fromArrayNoCopy("insert into blah values (974599638818488300, NULL, NULL, NULL, NULL);");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
pset = ParameterSet.fromArrayNoCopy("select * from blah where ival = 974599638818488300;");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println(responseJSON);
response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
assertEquals(1, response.results.length);
assertEquals(1, response.results[0].getRowCount());
// Call @AdHoc with zero parameters
pset = ParameterSet.emptyParameterSet();
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
assertTrue(responseJSON.contains("Adhoc system procedure requires at least the query parameter."));
// Call @AdHoc with many parameters (more than 2)
pset = ParameterSet.fromArrayNoCopy("select * from blah", "foo", "bar");
responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.err.println(responseJSON);
assertTrue(responseJSON.contains("Too many actual arguments were passed for the parameters in the sql "
+ "statement(s): (2 vs. 0)"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testJapaneseNastiness() throws Exception {
try {
String simpleSchema
= "CREATE TABLE HELLOWORLD (\n"
+ " HELLO VARCHAR(15),\n"
+ " WORLD VARCHAR(15),\n"
+ " DIALECT VARCHAR(15) NOT NULL,\n"
+ " PRIMARY KEY (DIALECT)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("HELLOWORLD", "DIALECT");
builder.addStmtProcedure("Insert", "insert into HELLOWORLD values (?,?,?);");
builder.addStmtProcedure("Select", "select * from HELLOWORLD;");
builder.addProcedures(SelectStarHelloWorld.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
String response = callProcOverJSONRaw(japaneseTestVarStrings, 200);
Response r = responseFromJSON(response);
assertEquals(1, r.status);
// If this line doesn't compile, right click the file in the package explorer.
// Select the properties menu. Set the text file encoding to UTF-8.
char[] test1 = {'こ', 'ん', 'に', 'ち', 'は'};
String test2 = new String(test1);
ParameterSet pset = ParameterSet.emptyParameterSet();
response = callProcOverJSON("Select", pset, null, null, false);
System.out.println(response);
System.out.println(test2);
r = responseFromJSON(response);
assertEquals(1, r.status);
response = callProcOverJSON("SelectStarHelloWorld", pset, null, null, false);
r = responseFromJSON(response);
assertEquals(1, r.status);
assertTrue(response.contains(test2));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testJSONAuth() throws Exception {
try {
String simpleSchema
= "CREATE TABLE HELLOWORLD (\n"
+ " HELLO VARCHAR(15),\n"
+ " WORLD VARCHAR(20),\n"
+ " DIALECT VARCHAR(15) NOT NULL,\n"
+ " PRIMARY KEY (DIALECT)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("HELLOWORLD", "DIALECT");
RoleInfo gi = new RoleInfo("foo", true, false, true, true, false, false);
builder.addRoles(new RoleInfo[]{gi});
// create 20 users, only the first one has an interesting user/pass
UserInfo[] ui = new UserInfo[15];
ui[0] = new UserInfo("ry@nlikesthe", "y@nkees", new String[]{"foo"});
for (int i = 1; i < ui.length; i++) {
ui[i] = new UserInfo("USER" + String.valueOf(i), "PASS" + String.valueOf(i), new String[]{"foo"});
}
builder.addUsers(ui);
builder.setSecurityEnabled(true, true);
ProcedureInfo[] pi = new ProcedureInfo[2];
pi[0] = new ProcedureInfo(new String[]{"foo"}, "Insert", "insert into HELLOWORLD values (?,?,?);", null);
pi[1] = new ProcedureInfo(new String[]{"foo"}, "Select", "select * from HELLOWORLD;", null);
builder.addProcedures(pi);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
ParameterSet pset;
// test good auths
for (UserInfo u : ui) {
pset = ParameterSet.fromArrayNoCopy(u.name, u.password, u.name);
String response = callProcOverJSON("Insert", pset, u.name, u.password, true);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
}
// test re-using auths
for (UserInfo u : ui) {
pset = ParameterSet.fromArrayNoCopy(u.name + "-X", u.password + "-X", u.name + "-X");
String response = callProcOverJSON("Insert", pset, u.name, u.password, false);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
}
// test bad auth
UserInfo u = ui[0];
pset = ParameterSet.fromArrayNoCopy(u.name + "-X1", u.password + "-X1", u.name + "-X1");
String response = callProcOverJSON("Insert", pset, u.name, "ick", true, false, 401, ClientAuthScheme.HASH_SHA256);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.UNEXPECTED_FAILURE, r.status);
response = callProcOverJSON("Insert", pset, u.name, "ick", false, false, 401, ClientAuthScheme.HASH_SHA256);
r = responseFromJSON(response);
assertEquals(ClientResponse.UNEXPECTED_FAILURE, r.status);
// test malformed auth (too short hash)
pset = ParameterSet.fromArrayNoCopy(u.name + "-X2", u.password + "-X2", u.name + "-X2");
String paramsInJSON = pset.toJSONString();
HashMap<String, String> params = new HashMap<>();
params.put("Procedure", "Insert");
params.put("Parameters", paramsInJSON);
params.put("User", u.name);
params.put("Password", Encoder.hexEncode(new byte[]{1, 2, 3}));
response = callProcOverJSONRaw(params, 401);
r = responseFromJSON(response);
assertEquals(ClientResponse.UNEXPECTED_FAILURE, r.status);
// test malformed auth (gibberish password, but good length)
pset = ParameterSet.fromArrayNoCopy(u.name + "-X3", u.password + "-X3", u.name + "-X3");
paramsInJSON = pset.toJSONString();
params = new HashMap<>();
params.put("Procedure", "Insert");
params.put("Parameters", paramsInJSON);
params.put("User", u.name);
params.put("Password", "abcdefghiabcdefghiabcdefghiabcdefghi");
response = callProcOverJSONRaw(params, 401);
r = responseFromJSON(response);
assertEquals(ClientResponse.UNEXPECTED_FAILURE, r.status);
// the update catalog test below is for enterprise only
if (VoltDB.instance().getConfig().m_isEnterprise == false) {
return;
}
// ENG-963 below here
// do enough to get a new deployment file
VoltProjectBuilder builder2 = new VoltProjectBuilder();
builder2.addSchema(schemaPath);
builder2.addPartitionInfo("HELLOWORLD", "DIALECT");
// Same groups
builder2.addRoles(new RoleInfo[]{gi});
// create same 15 users, hack the last 14 passwords
ui = new UserInfo[15];
ui[0] = new UserInfo("ry@nlikesthe", "y@nkees", new String[]{"foo"});
for (int i = 1; i < ui.length; i++) {
ui[i] = new UserInfo("USER" + String.valueOf(i),
"welcomehackers" + String.valueOf(i),
new String[]{"foo"});
}
builder2.addUsers(ui);
builder2.setSecurityEnabled(true, true);
builder2.addProcedures(pi);
builder2.setHTTPDPort(8095);
success = builder2.compile(Configuration.getPathToCatalogForTest("json-update.jar"));
assertTrue(success);
pset = ParameterSet.fromArrayNoCopy(Encoder.hexEncode(MiscUtils.fileToBytes(new File(config.m_pathToCatalog))),
new String(MiscUtils.fileToBytes(new File(builder2.getPathToDeployment())), "UTF-8"));
response = callProcOverJSON("@UpdateApplicationCatalog", pset,
ui[0].name, ui[0].password, true);
r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
// retest the good auths above
for (UserInfo user : ui) {
ParameterSet ps = ParameterSet.fromArrayNoCopy(user.name + "-X3", user.password + "-X3", user.name + "-X3");
String respstr = callProcOverJSON("Insert", ps, user.name, user.password, false);
Response resp = responseFromJSON(respstr);
assertEquals(ClientResponse.SUCCESS, resp.status);
}
VoltProjectBuilder builder3 = new VoltProjectBuilder();
builder3.addSchema(schemaPath);
builder3.addPartitionInfo("HELLOWORLD", "DIALECT");
// Same groups
builder3.addRoles(new RoleInfo[]{gi});
ui = new UserInfo[1];
ui[0] = new UserInfo("ry@nlikesthe",
"D033E22AE348AEB5660FC2140AEC35850C4DA9978C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918",
new String[]{"foo"}, false);
builder3.addUsers(ui);
builder3.setSecurityEnabled(true, true);
builder3.addProcedures(pi);
builder3.setHTTPDPort(8095);
success = builder3.compile(Configuration.getPathToCatalogForTest("json-update.jar"));
assertTrue(success);
pset = ParameterSet.fromArrayNoCopy(Encoder.hexEncode(MiscUtils.fileToBytes(new File(config.m_pathToCatalog))),
new String(MiscUtils.fileToBytes(new File(builder3.getPathToDeployment())), "UTF-8"));
response = callProcOverJSON("@UpdateApplicationCatalog", pset,
"ry@nlikesthe", "y@nkees", true);
r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
// retest the good auths above
ParameterSet ps = ParameterSet.fromArrayNoCopy(ui[0].name + "-X4", "admin-X4", ui[0].name + "-X4");
String respstr = callProcOverJSON("Insert", ps, ui[0].name, "admin", false);
Response resp = responseFromJSON(respstr);
assertEquals(ClientResponse.SUCCESS, resp.status);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testJSONDisabled() throws Exception {
try {
String simpleSchema
= "CREATE TABLE HELLOWORLD (\n"
+ " HELLO VARCHAR(15),\n"
+ " WORLD VARCHAR(15),\n"
+ " DIALECT VARCHAR(15) NOT NULL,\n"
+ " PRIMARY KEY (DIALECT)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("HELLOWORLD", "DIALECT");
builder.addStmtProcedure("Insert", "insert into HELLOWORLD values (?,?,?);");
builder.setHTTPDPort(8095);
builder.setJSONAPIEnabled(false);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
// test not enabled
ParameterSet pset = ParameterSet.fromArrayNoCopy("foo", "bar", "foobar");
try {
callProcOverJSON("Insert", pset, null, null, false, false, 403, ClientAuthScheme.HASH_SHA256); // HTTP_FORBIDDEN
} catch (Exception e) {
// make sure failed due to permissions on http
assertTrue(e.getMessage().contains("403"));
}
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testLongProc() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(simpleSchema);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
ParameterSet pset = ParameterSet.fromArrayNoCopy(14_000);
String response = callProcOverJSON("DelayProc", pset, null, null, false);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testProcTimeout() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(simpleSchema);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(InsertProc.class);
builder.addProcedures(LongReadProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
ParameterSet pset = null;
int batchSize = 10000;
for (int i=0; i<10; i++) {
pset = ParameterSet.fromArrayNoCopy(i*batchSize, batchSize);
String response = callProcOverJSON("TestJSONInterface$InsertProc", pset, null, null, false, false, 200, ClientAuthScheme.HASH_SHA256);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
}
pset = ParameterSet.fromArrayNoCopy(100000);
String response = callProcOverJSON("TestJSONInterface$LongReadProc", pset, 8095, null, null, false, false, 200, ClientAuthScheme.HASH_SHA256, 1);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.GRACEFUL_FAILURE, r.status);
assertTrue(r.statusString.contains("Transaction Interrupted"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public static class InsertProc extends VoltProcedure {
public final SQLStmt stmt = new SQLStmt("INSERT INTO foo values (?);");
public long run(int startValue, long numRows) {
for (int i=0; i<numRows; i++) {
voltQueueSQL(stmt, i+startValue);
}
voltExecuteSQL();
return 1;
}
}
public static class LongReadProc extends VoltProcedure {
public final SQLStmt stmt = new SQLStmt("SELECT * FROM foo");
public long run(long numLoops) {
voltQueueSQL(stmt);
voltExecuteSQL();
return 1;
}
}
public void testLongQuerySTring() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(simpleSchema);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//create a large query string
final StringBuilder s = new StringBuilder();
s.append("Procedure=@Statistics&Parameters=[TABLE]&jsonpxx=");
for (int i = 0; i < 450000; i++) {
s.append(i);
}
String query = s.toString();
//call multiple times.
for (int i = 0; i < 500; i++) {
String response = callProcOverJSONRaw(query, 200);
System.out.println(response);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.UNEXPECTED_FAILURE, r.status);
//make sure good queries can still work.
ParameterSet pset = ParameterSet.fromArrayNoCopy("select * from foo");
String responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println(responseJSON);
r = responseFromJSON(responseJSON);
assertEquals(ClientResponse.SUCCESS, r.status);
}
//make sure good queries can still work after.
ParameterSet pset = ParameterSet.fromArrayNoCopy("select * from foo");
String responseJSON = callProcOverJSON("@AdHoc", pset, null, null, false);
System.out.println(responseJSON);
Response response = responseFromJSON(responseJSON);
System.out.println(response.statusString);
assertEquals(ClientResponse.SUCCESS, response.status);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testBinaryProc() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " b VARBINARY(256) DEFAULT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addLiteralSchema(simpleSchema);
builder.addPartitionInfo("foo", "bar");
builder.addStmtProcedure("Insert", "insert into foo values (?, ?);");
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
// try a good insert
String varString = "Procedure=Insert&Parameters=[5,\"aa\"]";
String response = callProcOverJSONRaw(varString, 200);
System.out.println(response);
Response r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
// try two poorly hex-encoded inserts
varString = "Procedure=Insert&Parameters=[6,\"aaa\"]";
response = callProcOverJSONRaw(varString, 200);
System.out.println(response);
r = responseFromJSON(response);
assertEquals(ClientResponse.GRACEFUL_FAILURE, r.status);
varString = "Procedure=Insert&Parameters=[7,\"aaay\"]";
response = callProcOverJSONRaw(varString, 200);
System.out.println(response);
r = responseFromJSON(response);
assertEquals(ClientResponse.GRACEFUL_FAILURE, r.status);
// try null binary inserts
varString = "Procedure=Insert&Parameters=[8,NULL]";
response = callProcOverJSONRaw(varString, 200);
System.out.println(response);
r = responseFromJSON(response);
assertEquals(ClientResponse.SUCCESS, r.status);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testGarbageProcs() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
callProcOverJSONRaw(getHTTPURL(null, "api/1.0/Tim"), 400);
callProcOverJSONRaw(getHTTPURL(null, "api/1.0/Tim?Procedure=foo&Parameters=[x4{]"), 400);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testDeployment() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment
String jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
assertTrue(jdep.contains("cluster"));
//Download deployment
String xdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", null, null, null, 200, "text/xml");
assertTrue(xdep.contains("<deployment>"));
assertTrue(xdep.contains("</deployment>"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testUpdateDeployment() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment
String jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
assertTrue(jdep.contains("cluster"));
//POST deployment with no content
String pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 400, "application/json", null);
assertTrue(pdep.contains("Failed"));
Map<String,String> params = new HashMap<>();
params.put("deployment", jdep);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
//POST deployment in admin mode
params.put("admin", "true");
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
ObjectMapper mapper = new ObjectMapper();
DeploymentType deptype = mapper.readValue(jdep, DeploymentType.class);
//Test change heartbeat.
if (deptype.getHeartbeat() == null) {
HeartbeatType hb = new HeartbeatType();
hb.setTimeout(99);
deptype.setHeartbeat(hb);
} else {
deptype.getHeartbeat().setTimeout(99);
}
String ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
System.out.println("POST result is: " + pdep);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
assertTrue(jdep.contains("cluster"));
deptype = mapper.readValue(jdep, DeploymentType.class);
int nto = deptype.getHeartbeat().getTimeout();
assertEquals(99, nto);
//Test change Query timeout
SystemSettingsType ss = deptype.getSystemsettings();
if (ss == null) {
ss = new SystemSettingsType();
deptype.setSystemsettings(ss);
}
Query qv = ss.getQuery();
if (qv == null) {
qv = new Query();
qv.setTimeout(99);
} else {
qv.setTimeout(99);
}
ss.setQuery(qv);
deptype.setSystemsettings(ss);
ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
System.out.println("POST result is: " + pdep);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
assertTrue(jdep.contains("cluster"));
deptype = mapper.readValue(jdep, DeploymentType.class);
nto = deptype.getSystemsettings().getQuery().getTimeout();
assertEquals(99, nto);
qv.setTimeout(88);
ss.setQuery(qv);
deptype.setSystemsettings(ss);
ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
System.out.println("POST result is: " + pdep);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
assertTrue(jdep.contains("cluster"));
deptype = mapper.readValue(jdep, DeploymentType.class);
nto = deptype.getSystemsettings().getQuery().getTimeout();
assertEquals(88, nto);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testUpdateDeploymentMemoryLimit() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment
String jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
Map<String,String> params = new HashMap<>();
ObjectMapper mapper = new ObjectMapper();
DeploymentType deptype = mapper.readValue(jdep, DeploymentType.class);
SystemSettingsType ss = deptype.getSystemsettings();
if (ss == null) {
ss = new SystemSettingsType();
deptype.setSystemsettings(ss);
}
ResourceMonitorType resourceMonitor = new ResourceMonitorType();
Memorylimit memLimit = new Memorylimit();
memLimit.setSize("10");
memLimit.setAlert("5");
resourceMonitor.setMemorylimit(memLimit);
ss.setResourcemonitor(resourceMonitor);
String ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
String pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
DeploymentType gotValue = mapper.readValue(jdep, DeploymentType.class);
assertEquals("10", gotValue.getSystemsettings().getResourcemonitor().getMemorylimit().getSize());
memLimit.setSize("90%");
ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
assertTrue(pdep.contains("Deployment Updated"));
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
gotValue = mapper.readValue(jdep, DeploymentType.class);
assertEquals("90%", gotValue.getSystemsettings().getResourcemonitor().getMemorylimit().getSize());
// decimal values not allowed for percentages
memLimit.setSize("90.5%25");
ndeptype = mapper.writeValueAsString(deptype);
params.put("deployment", ndeptype);
pdep = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", null, null, null, 200, "application/json", params);
jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", null, null, null, 200, "application/json");
gotValue = mapper.readValue(jdep, DeploymentType.class);
// must be still the old value
assertEquals("90%", gotValue.getSystemsettings().getResourcemonitor().getMemorylimit().getSize());
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testDeploymentSecurity() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
UserInfo users[] = new UserInfo[] {
new UserInfo("user1", "admin", new String[] {"user"}),
new UserInfo("user2", "admin", new String[] {"administrator"}),
new UserInfo("user3", "admin", new String[] {"administrator"}), //user3 used for both hash testing.
};
builder.addUsers(users);
// suite defines its own ADMINISTRATOR user
builder.setSecurityEnabled(true, false);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment with diff hashed password
//20E3AAE7FC23385295505A6B703FD1FBA66760D5 FD19534FBF9B75DF7CD046DE3EAF93DB77367CA7C1CC017FFA6CED2F14D32E7D
//D033E22AE348AEB5660FC2140AEC35850C4DA997 8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918
//sha-256
String dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "user3&" + "Hashedpassword=8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918", null, null, null, 200, "application/json");
assertTrue(dep.contains("cluster"));
//sha-1
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "user3&" + "Hashedpassword=D033E22AE348AEB5660FC2140AEC35850C4DA997", null, null, null, 200, "application/json");
assertTrue(dep.contains("cluster"));
//Get deployment invalid user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "invaliduser&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997", null, null, null, 401, "application/json");
assertTrue(dep.contains("failed to authenticate"));
//Get deployment unauthorized user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "user1&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997", null, null, null, 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "user2&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997", null, null, null, 200, "application/json");
assertTrue(dep.contains("cluster"));
//Download deployment unauthorized user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download?User=" + "user1&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997", null, null, null, 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download?User=" + "user2&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997", null, null, null, 200, "text/xml");
assertTrue(dep.contains("<deployment>"));
assertTrue(dep.contains("</deployment>"));
//get with jsonp
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/?User=" + "user2&" + "Hashedpassword=d033e22ae348aeb5660fc2140aec35850c4da997&jsonp=jackson5", null, null, null, 200, "application/json");
assertTrue(dep.contains("cluster"));
assertTrue(dep.contains("jackson5"));
assertTrue(dep.matches("^jackson5(.*)"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testDeploymentSecurityAuthorizationHashed() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
UserInfo users[] = new UserInfo[] {
new UserInfo("user1", "admin", new String[] {"user"}),
new UserInfo("user2", "admin", new String[] {"administrator"}),
};
builder.addUsers(users);
// suite defines its own ADMINISTRATOR user
builder.setSecurityEnabled(true, false);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment bad user
String dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", "user1", "admin", "hashed", 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", "user2", "admin", "hashed", 200, "application/json");
assertTrue(dep.contains("cluster"));
//Download deployment bad user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user1", "admin", "hashed", 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user2", "admin", "hashed", 200, "text/xml");
assertTrue(dep.contains("<deployment>"));
assertTrue(dep.contains("</deployment>"));
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user2", "admin", "hashed256", 200, "text/xml");
assertTrue(dep.contains("<deployment>"));
assertTrue(dep.contains("</deployment>"));
//Test back with sha1
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user2", "admin", "hashed", 200, "text/xml");
assertTrue(dep.contains("<deployment>"));
assertTrue(dep.contains("</deployment>"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testDeploymentSecurityAuthorizationBasic() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
UserInfo users[] = new UserInfo[] {
new UserInfo("user1", "admin", new String[] {"user"}),
new UserInfo("user2", "admin", new String[] {"administrator"}),
};
builder.addUsers(users);
// suite defines its own ADMINISTRATOR user
builder.setSecurityEnabled(true, false);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get deployment bad user
String dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", "user1", "admin", "basic", 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", "user2", "admin", "basic", 200, "application/json");
assertTrue(dep.contains("cluster"));
//Download deployment bad user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user1", "admin", "basic", 401, "application/json");
assertTrue(dep.contains("Permission denied"));
//good user
dep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/download", "user2", "admin", "basic", 200, "text/xml");
assertTrue(dep.contains("<deployment>"));
assertTrue(dep.contains("</deployment>"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testUsers() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
builder.setUseDDLSchema(true);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get users
String json = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/", null, null, null, 200, "application/json");
assertEquals(json, "[]");
getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/foo", null, null, null, 404, "application/json");
//Put users
ObjectMapper mapper = new ObjectMapper();
UsersType.User user = new UsersType.User();
user.setName("foo");
user.setPassword("foo");
String map = mapper.writeValueAsString(user);
Map<String,String> params = new HashMap<>();
params.put("user", map);
putUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/foo/", null, null, null, 201, "application/json", params);
//Get users
json = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/", null, null, null, 200, "application/json");
JSONArray jarray = new JSONArray(json);
assertEquals(jarray.length(), 1);
JSONObject jobj = jarray.getJSONObject(0);
assertTrue(jobj.getString("id").contains("/deployment/users/foo"));
assertTrue(jobj.getString("roles").equalsIgnoreCase("null"));
//Post users
user.setRoles("foo");
map = mapper.writeValueAsString(user);
params.put("user", map);
postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/foo/", null, null, null, 200, "application/json", params);
//Get users
json = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/", null, null, null, 200, "application/json");
jarray = new JSONArray(json);
assertEquals(jarray.length(), 1);
jobj = jarray.getJSONObject(0);
assertTrue(jobj.getString("roles").equals("foo"));
//Delete users
deleteUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/foo/", null, null, null, 204, "application/json");
//Get users
json = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/users/", null, null, null, 200, "application/json");
assertEquals(json, "[]");
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testExportTypes() throws Exception {
try {
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get exportTypes
String json = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment/export/types", null, null, null, 200, "application/json");
JSONObject jobj = new JSONObject(json);
assertTrue(jobj.getString("types").contains("FILE"));
assertTrue(jobj.getString("types").contains("JDBC"));
assertTrue(jobj.getString("types").contains("KAFKA"));
assertTrue(jobj.getString("types").contains("HTTP"));
assertTrue(jobj.getString("types").contains("RABBITMQ"));
assertTrue(jobj.getString("types").contains("CUSTOM"));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testProfile() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
//Get profile
String dep = getUrlOverJSON(protocolPrefix + "localhost:8095/profile", null, null, null, 200, "application/json");
assertTrue(dep.contains("\"user\""));
assertTrue(dep.contains("\"permissions\""));
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testConnectionsWithUpdateCatalog() throws Exception {
runConnectionsWithUpdateCatalog(false);
}
public void testConnectionsWithUpdateCatalogWithSecurity() throws Exception {
runConnectionsWithUpdateCatalog(true);
}
public void runConnectionsWithUpdateCatalog(boolean securityOn) throws Exception {
try {
String simpleSchema
= "CREATE TABLE test1 (\n"
+ " fld1 BIGINT NOT NULL,\n"
+ " PRIMARY KEY (fld1)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("test1", "fld1");
builder.addProcedures(WorkerProc.class);
UserInfo[] ui = new UserInfo[5];
if (securityOn) {
RoleInfo ri = new RoleInfo("role1", true, false, true, true, false, false);
builder.addRoles(new RoleInfo[] { ri });
for (int i = 0; i < ui.length; i++) {
ui[i] = new UserInfo("user" + String.valueOf(i), "password" + String.valueOf(i), new String[] { "role1" } );
}
builder.addUsers(ui);
builder.setSecurityEnabled(true, true);
}
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
TestWorker.s_insertCount = new AtomicLong(0);
int poolSize = 25;
ExecutorService executor = Executors.newFixedThreadPool(poolSize);
int workCount = 200;
for (int i=0; i<workCount; i++) {
executor.execute(new TestWorker(i, workCount/10,
(securityOn ? ui[workCount%ui.length].name : null),
(securityOn ? ui[workCount%ui.length].password : null) ));
}
// wait for everything to be done and check status
executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
fail("Workers should have finished execution by now");
}
assertTrue(TestWorker.s_success);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testInvalidURI() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addProcedures(DelayProc.class);
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
String[] invalidURIs = {
"localhost:8095/invalid",
"localhost:8095/deployment/invalid",
"localhost:8095/deployment/download/invalid",
"localhost:8095/deployment/export",
"localhost:8095/deployment/export/invalid",
"localhost:8095/deployment/export/types/invalid",
"localhost:8095/profile/invalid",
"localhost:8095/api",
"localhost:8095/api/1.0/invalid",
};
for (int i=0; i<invalidURIs.length; i++) {
String result = getUrlOverJSON(protocolPrefix + invalidURIs[i], null, null, null, 404, null);
assertTrue(result.contains("not found"));
}
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
public void testJSONPSanitization() throws Exception {
try {
String simpleSchema
= "CREATE TABLE foo (\n"
+ " bar BIGINT NOT NULL,\n"
+ " PRIMARY KEY (bar)\n"
+ ");";
File schemaFile = VoltProjectBuilder.writeStringToTempFile(simpleSchema);
String schemaPath = schemaFile.getPath();
schemaPath = URLEncoder.encode(schemaPath, "UTF-8");
VoltProjectBuilder builder = new VoltProjectBuilder();
builder.addSchema(schemaPath);
builder.addPartitionInfo("foo", "bar");
builder.addStmtProcedure("Insert", "insert into foo values(?);");
builder.setHTTPDPort(8095);
boolean success = builder.compile(Configuration.getPathToCatalogForTest("json.jar"));
assertTrue(success);
VoltDB.Configuration config = new VoltDB.Configuration();
config.m_pathToCatalog = config.setPathToCatalogForTest("json.jar");
config.m_pathToDeployment = builder.getPathToDeployment();
server = new ServerThread(config);
server.start();
server.waitForInitialization();
// Get deployment
String dep = checkJSONPHandling("GET", protocolPrefix + "localhost:8095/deployment", "application/json", null);
// Download deployment
checkJSONPHandling("GET", protocolPrefix + "localhost:8095/deployment/download", "text/xml", null);
// Post deployment
Map<String,String> params = new HashMap<>();
params.put("deployment", takeOutWrappingJSONP(dep));
checkJSONPHandling("POST", protocolPrefix + "localhost:8095/deployment/", "application/json", params);
// Get users
checkJSONPHandling("GET", protocolPrefix + "localhost:8095/deployment/users", "application/json", null);
// Put user
ObjectMapper mapper = new ObjectMapper();
UsersType.User user = new UsersType.User();
user.setName("foo");
user.setPassword("foo");
String map = mapper.writeValueAsString(user);
params = new HashMap<>();
params.put("user", map);
checkJSONPHandling("PUT", protocolPrefix + "localhost:8095/deployment/users/foo", "application/json", params);
// Post user
user.setRoles("foo");
map = mapper.writeValueAsString(user);
params.put("user", map);
checkJSONPHandling("POST", protocolPrefix + "localhost:8095/deployment/users/foo", "application/json", params);
// Delete user
checkJSONPHandling("DELETE", protocolPrefix + "localhost:8095/deployment/users/foo", "application/json", null);
// Get exportTypes
checkJSONPHandling("GET", protocolPrefix + "localhost:8095/deployment/export/types", "application/json", null);
// Get profile
checkJSONPHandling("GET", protocolPrefix + "localhost:8095/profile", "application/json", null);
// Get /api/1.0
String response = checkJSONPHandling("GET", protocolPrefix + "localhost:8095/api/1.0?Procedure=Insert&Parameters=[1]", "application/json", null);
assertTrue(responseFromJSON(takeOutWrappingJSONP(response)).status == ClientResponse.SUCCESS);
// Post /api/1.0
params = new HashMap<>();
params.put("Procedure", "Insert");
params.put("Parameters", "[2]");
response = checkJSONPHandling("POST", protocolPrefix + "localhost:8095/api/1.0/", "application/json", params);
assertTrue(responseFromJSON(takeOutWrappingJSONP(response)).status == ClientResponse.SUCCESS);
} finally {
if (server != null) {
server.shutdown();
server.join();
}
server = null;
}
}
private static String takeOutWrappingJSONP(String s) {
return s.substring(s.indexOf('(') + 1, s.lastIndexOf(')')).trim();
}
private static String checkJSONPHandling(String method, String baseUrl,
String expectedCt, Map<String, String> params) throws Exception {
String jsonpKeyString = baseUrl.contains("?") ? "&jsonp=" : "?jsonp=";
String urlWithValidJSONP = baseUrl + jsonpKeyString + VALID_JSONP;
String urlWithInvalidJSONP= baseUrl + jsonpKeyString + INVALID_JSONP;
String validJSONPResponse = null;
String invalidJSONPResponse = null;
switch (method) {
case "GET":
validJSONPResponse = getUrlOverJSON(urlWithValidJSONP, null, null, null, 200, expectedCt);
invalidJSONPResponse = getUrlOverJSON(urlWithInvalidJSONP, null, null, null, 400, "application/json");
break;
case "POST":
validJSONPResponse = postUrlOverJSON(urlWithValidJSONP, null, null, null, 200, expectedCt, params);
invalidJSONPResponse = postUrlOverJSON(urlWithInvalidJSONP, null, null, null, 400, "application/json", params);
break;
case "PUT":
validJSONPResponse = putUrlOverJSON(urlWithValidJSONP, null, null, null, 201, expectedCt, params);
invalidJSONPResponse = putUrlOverJSON(urlWithInvalidJSONP, null, null, null, 400, "application/json", params);
break;
case "DELETE":
validJSONPResponse = deleteUrlOverJSON(urlWithValidJSONP, null, null, null, 204, expectedCt);
invalidJSONPResponse = deleteUrlOverJSON(urlWithInvalidJSONP, null, null, null, 400, "application/json");
break;
}
assertTrue(invalidJSONPResponse != null && invalidJSONPResponse.contains("Invalid jsonp callback function name"));
return validJSONPResponse;
}
private static class TestWorker implements Runnable {
public static boolean s_success = true; // this is set by worker threads on failure only
public static AtomicLong s_insertCount = new AtomicLong(0);
private final int m_id;
private final int m_catUpdateCount;
private final String m_username;
private final String m_password;
public TestWorker(int id, int catUpdateCount, String username, String password) {
m_id = id;
m_catUpdateCount = catUpdateCount;
m_username = username;
m_password = password;
}
@Override
public void run()
{
try {
if (m_id==0) { // do all deployment update from one thread to avoid version error on server side
for (int i=0; i<m_catUpdateCount; i++) {
// update deployment to force a catalog update and resetting connections
String jdep = getUrlOverJSON(protocolPrefix + "localhost:8095/deployment", m_username, m_password, "hashed", 200, "application/json");
ObjectMapper mapper = new ObjectMapper();
DeploymentType deptype = mapper.readValue(jdep, DeploymentType.class);
int timeout = 100 + m_id;
if (deptype.getHeartbeat() == null) {
HeartbeatType hb = new HeartbeatType();
hb.setTimeout(timeout);
deptype.setHeartbeat(hb);
} else {
deptype.getHeartbeat().setTimeout(timeout);
}
Map<String,String> params = new HashMap<>();
params.put("deployment", mapper.writeValueAsString(deptype));
params.put("admin", "true");
String responseJSON = postUrlOverJSON(protocolPrefix + "localhost:8095/deployment/", m_username, m_password, "hashed", 200, "application/json", params);
if (!responseJSON.contains("Deployment Updated.")) {
System.out.println("Failed to update deployment");
s_success = false;
}
}
} else {
// do a write and a read
ParameterSet pset = ParameterSet.fromArrayNoCopy("insert into test1 values (" + (m_id) + ")");
String responseJSON = callProcOverJSON("@AdHoc", pset, m_username, m_password, false, false);
//System.out.println("Insert response: " + responseJSON);
if (!responseJSON.contains("\"data\":[[1]]")) {
System.out.println("Insert should have returned 1. Got: " + responseJSON);
s_success = false;
return;
}
s_insertCount.incrementAndGet();
Thread.sleep(200);
pset = ParameterSet.fromArrayNoCopy("select count(*) from test1");
long expectedCount = s_insertCount.get();
responseJSON = callProcOverJSON("@AdHoc", pset, m_username, m_password, false, false);
int startIndex = responseJSON.indexOf(":[[");
int endIndex = responseJSON.indexOf("]]");
if (startIndex==-1 || endIndex==-1) {
System.out.println("Invalid response from select: " + responseJSON);
s_success = false;
return;
}
int count = Integer.parseInt(responseJSON.substring(startIndex+3, endIndex));
if (count < expectedCount) {
System.out.println("Select must have returned at least " + expectedCount + ". Got "+ count);
s_success = false;
return;
}
// do a proc cal that takes longer
pset = ParameterSet.fromArrayNoCopy(500);
responseJSON = callProcOverJSON("TestJSONInterface$WorkerProc", pset, m_username, m_password, false, false);
//System.out.println("WorkperProc response: " + responseJSON);
}
} catch(Exception e) {
e.printStackTrace();
s_success = false;
}
}
}
public static class WorkerProc extends VoltProcedure {
public long run(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
throw new VoltAbortException(e.getMessage());
}
return 0;
}
}
}