/**
* Licensed to JumpMind Inc under one or more contributor
* license agreements. See the NOTICE file distributed
* with this work for additional information regarding
* copyright ownership. JumpMind Inc licenses this file
* to you under the GNU General Public License, version 3.0 (GPLv3)
* (the "License"); you may not use this file except in compliance
* with the License.
*
* You should have received a copy of the GNU General Public License,
* version 3.0 (GPLv3) along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jumpmind.symmetric.test;
import java.sql.Types;
import java.util.List;
import org.jumpmind.db.model.Column;
import org.jumpmind.db.model.Table;
import org.jumpmind.db.platform.DatabaseNamesConstants;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.model.Channel;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.web.rest.NotAllowedException;
import org.jumpmind.symmetric.web.rest.RestService;
import org.jumpmind.symmetric.web.rest.model.Batch;
import org.jumpmind.symmetric.web.rest.model.BatchResult;
import org.jumpmind.symmetric.web.rest.model.BatchResults;
import org.jumpmind.symmetric.web.rest.model.PullDataResults;
import org.jumpmind.symmetric.web.rest.model.RegistrationInfo;
import org.jumpmind.util.FormatUtils;
import static org.junit.Assert.*;
public class RestServiceTest extends AbstractTest {
@Override
protected Table[] getTables(String name) {
Table a = new Table("a");
a.addColumn(new Column("id", true, Types.INTEGER, -1, -1));
a.addColumn(new Column("notes", false, Types.VARCHAR, 255, -1));
a.addColumn(new Column("created", false, Types.TIMESTAMP, -1, -1));
return new Table[] { a };
}
@Override
protected String[] getGroupNames() {
return new String[] { "server", "client" };
}
@Override
protected void test(ISymmetricEngine rootServer, ISymmetricEngine clientServer)
throws Exception {
testRestPullApi();
}
protected void testRestPullApi() throws Exception {
loadConfigAtRegistrationServer();
RestService restService = getRegServer().getRestService();
ISymmetricEngine engine = getRegServer().getEngine();
IParameterService parameterService = engine.getParameterService();
INodeService nodeService = engine.getNodeService();
parameterService.saveParameter(ParameterConstants.REST_API_ENABLED, Boolean.TRUE,
"unit_test");
assertNotNull("Could not find the rest service in the application context",
restService);
List<Node> nodes = nodeService.findAllNodes();
assertEquals("Expected there to only be one node registered", 1, nodes.size());
assertEquals("The only node we expected to be registered is a server node",
"server", nodes.get(0).getNodeGroupId());
RegistrationInfo registrationInfo = restService.postRegisterNode("client", "client",
DatabaseNamesConstants.SQLITE, "3.0", "hostName");
assertNotNull("Registration should have returned a result object", registrationInfo);
assertFalse("Registration should not have been open",
registrationInfo.isRegistered());
assertEquals("Expected there to only be one node registered", 1, nodes.size());
engine.openRegistration("client", "client");
registrationInfo = restService.postRegisterNode("client", "client",
DatabaseNamesConstants.SQLITE, "3.0", "hostName");
assertNotNull("Registration should have returned a result object", registrationInfo);
assertTrue("Registration should have been open", registrationInfo.isRegistered());
assertEquals("client", registrationInfo.getNodeId());
try {
restService.getPullData(registrationInfo.getNodeId(), "wrong password", false, false, true, null);
fail("We should have received an exception");
} catch (NotAllowedException ex) {
}
PullDataResults results = null;
assertPullReturnsNoData(restService, registrationInfo);
engine.getSqlTemplate().update("insert into a values(?, ?, ?)", 1, "this is a test", FormatUtils.parseDate("2013-06-08 00:00:00.000", FormatUtils.TIMESTAMP_PATTERNS));
engine.route();
results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), false, false, true, null);
assertNotNull("Should have a non null results object", results);
assertEquals(1, results.getNbrBatches());
assertEquals(4, results.getBatches().get(0).getBatchId());
log.info(results.getBatches().get(0).getSqlStatements().get(0));
// pull a second time without acking. should get the same results
results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), false, false, false, null);
assertNotNull("Should have a non null results object", results);
assertEquals(1, results.getNbrBatches());
// test that when we don't request jdbc timestamp format sql statements come back in that format
assertFalse(results.getBatches().get(0).getSqlStatements().get(0).contains("{ts '"));
// make sure we have no delimited identifiers
assertFalse(results.getBatches().get(0).getSqlStatements().get(0).contains("\""));
engine.getSqlTemplate().update("update a set notes=? where id=?", "changed", 1);
engine.getSqlTemplate().update("update a set notes=? where id=?", "changed again", 1);
engine.route();
results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), true, false, true, null);
assertNotNull("Should have a non null results object", results);
assertEquals(2, results.getNbrBatches());
assertNotSame(results.getBatches().get(1).getBatchId(), results.getBatches().get(0).getBatchId());
assertEquals(2, results.getBatches().get(1).getSqlStatements().size());
// test that when we request jdbc timestamp format sql statements come back in that format
String testSql = results.getBatches().get(1).getSqlStatements().get(0);
assertTrue("The following sql was supposed to contain '{ts '" + testSql, testSql.contains("{ts '"));
// make sure we have delimited identifiers
assertTrue(results.getBatches().get(1).getSqlStatements().get(0).contains("\""));
log.info(results.getBatches().get(1).getSqlStatements().get(0));
log.info(results.getBatches().get(1).getSqlStatements().get(1));
ackBatches(restService, registrationInfo, results, buildBatchResults(registrationInfo, results));
engine.getSqlTemplate().update("insert into a values(?, ?, ?)", 2, "this is a test", FormatUtils.parseDate("2073-06-08 00:00:00.000", FormatUtils.TIMESTAMP_PATTERNS));
engine.getSqlTemplate().update("insert into a values(?, ?, ?)", 3, "this is a test", FormatUtils.parseDate("2073-06-08 00:00:00.000", FormatUtils.TIMESTAMP_PATTERNS));
engine.getSqlTemplate().update("update a set notes=? where id=?", "update to 2", 2);
engine.getSqlTemplate().update("update a set notes=? where id=?", "update to 3", 3);
engine.getSqlTemplate().update("update a set notes=? where id=?", "update 2 again", 2);
engine.route();
results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), false, true, true, null);
assertNotNull("Should have a non null results object", results);
assertEquals(1, results.getNbrBatches());
List<String> sqls = results.getBatches().get(0).getSqlStatements();
assertEquals(5, sqls.size());
for (String sql : sqls) {
log.info(sql);
assertTrue(sql, sql.toLowerCase().startsWith("insert or replace"));
}
ackBatches(restService, registrationInfo, results, buildBatchResults(registrationInfo, results));
Channel channel = engine.getConfigurationService().getChannel("default");
channel.setBatchAlgorithm("nontransactional");
channel.setMaxBatchSize(1);
engine.getConfigurationService().saveChannel(channel, true);
engine.getSqlTemplate().update("delete from a");
engine.route();
results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), false, false, true, null);
assertNotNull("Should have a non null results object", results);
assertEquals(3, results.getNbrBatches());
List<Batch> batches = results.getBatches();
for (Batch batch : batches) {
assertEquals(1, batch.getSqlStatements().size());
assertTrue(batch.getSqlStatements().get(0).toLowerCase().startsWith("delete from"));
}
ackBatches(restService, registrationInfo, results, buildBatchResults(registrationInfo, results));
}
protected BatchResults buildBatchResults(RegistrationInfo registrationInfo, PullDataResults results) {
BatchResults batchResults = new BatchResults();
batchResults.setNodeId(registrationInfo.getNodeId());
for (Batch batch : results.getBatches()) {
batchResults.getBatchResults().add(new BatchResult(batch.getBatchId(), true));
}
return batchResults;
}
protected void ackBatches(RestService restService, RegistrationInfo registrationInfo, PullDataResults results, BatchResults batchResults) {
restService.putAcknowledgeBatch("server", registrationInfo.getNodePassword(), batchResults);
assertPullReturnsNoData(restService, registrationInfo);
}
protected void assertPullReturnsNoData(RestService restService, RegistrationInfo registrationInfo) {
PullDataResults results = restService.getPullData("server", registrationInfo.getNodeId(),
registrationInfo.getNodePassword(), false, false, true, null);
assertNotNull("Should have a non null results object", results);
assertEquals(0, results.getNbrBatches());
}
}