package com.alibaba.cobar.client; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.springframework.jdbc.core.RowMapper; import org.testng.annotations.Test; import com.alibaba.cobar.client.entities.Follower; import com.alibaba.cobar.client.support.utils.CollectionUtils; @Test(sequential=true) public class CobarSqlMapClientTemplateWithSqlActionOnlyRouterTest extends AbstractTestNGCobarClientTest { public CobarSqlMapClientTemplateWithSqlActionOnlyRouterTest() { super(new String[] { "META-INF/spring/cobar-client-appctx.xml", "META-INF/spring/datasources-appctx.xml", "META-INF/spring/sqlaction-router-appctx.xml" }); } public void testInsertOnCobarSqlMapClientWithSqlActionOnlyRules() { String name = "Darren"; Follower follower = new Follower(name); getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Follower.create", follower); // since no rule for this insert, it will be inserted into default data source, that's, partition1 String confirmSQL = "select name from followers where name='" + name + "'"; verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); // this sql action is routed to partition2, so can't find any matched record. Follower followerToFind = (Follower) getSqlMapClientTemplate().queryForObject( "com.alibaba.cobar.client.entities.Follower.finaByName", name); assertNull(followerToFind); // sql action below will be against all of the partitions , so we will get back what we want here @SuppressWarnings("unchecked") List<Follower> followers = (List<Follower>) getSqlMapClientTemplate().queryForList( "com.alibaba.cobar.client.entities.Follower.findAll"); assertTrue(CollectionUtils.isNotEmpty(followers)); assertEquals(1, followers.size()); assertEquals(name, followers.get(0).getName()); } public void testInsertWithBatchCommitOnCobarSqlMapClientTemplateWithSqlActionOnlyRules() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixture(names); // since no routing rule for insertion, all of the records will be inserted into default data source, that's, partition1 for (String name : names) { String confirmSQL = "select name from followers where name='" + name + "'"; verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m); verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); } // since sql action below is routed to partition2, so no record will be found with it. for (String name : names) { Follower followerToFind = (Follower) getSqlMapClientTemplate().queryForObject( "com.alibaba.cobar.client.entities.Follower.finaByName", name); assertNull(followerToFind); } // although records only reside on partition1, but we can get all of them with sql action below @SuppressWarnings("unchecked") List<Follower> followers = (List<Follower>) getSqlMapClientTemplate().queryForList( "com.alibaba.cobar.client.entities.Follower.findAll"); assertTrue(CollectionUtils.isNotEmpty(followers)); assertEquals(names.length, followers.size()); for (Follower f : followers) { assertTrue(ArrayUtils.contains(names, f.getName())); } } public void testDeleteOnCobarSqlMapClientTemplate() { String name = "Darren"; String sqlAction = "com.alibaba.cobar.client.entities.Follower.deleteByName"; // no record at beginning assertEquals(0, getSqlMapClientTemplate().delete(sqlAction, name)); // insert 1 record and delete will affect this record which resides on partition1 Follower follower = new Follower(name); getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Follower.create", follower); assertEquals(1, getSqlMapClientTemplate().delete(sqlAction, name)); // insert 1 record to partition2, delete will NOT affect it because no rule is defined for it. int updatedRow = jt2m.update("insert into followers(name) values('" + name + "')"); if (updatedRow == 1) // make sure it is do inserted into partition2 successfully. { assertEquals(0, getSqlMapClientTemplate().delete(sqlAction, name)); @SuppressWarnings("unchecked") List<Follower> followers = (List<Follower>) getSqlMapClientTemplate().queryForList( "com.alibaba.cobar.client.entities.Follower.findAll"); assertTrue(CollectionUtils.isNotEmpty(followers)); assertEquals(1, followers.size()); assertEquals(name, followers.get(0).getName()); } } /** * insert data onto default data source , and query will against all of the * partitions, so all of the records will be returned as expected. */ public void testQueryForListOnCobarSqlMapClientTemplateNormally() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixture(names); @SuppressWarnings("unchecked") List<Follower> followers = (List<Follower>) getSqlMapClientTemplate().queryForList( "com.alibaba.cobar.client.entities.Follower.findAll"); assertTrue(CollectionUtils.isNotEmpty(followers)); assertEquals(names.length, followers.size()); for (Follower f : followers) { assertTrue(ArrayUtils.contains(names, f.getName())); } } /** * although records are inserted onto patition2, but since the query is * against all of the data sources, so all of the records will be returned * as expected. */ public void testQueryForListOnCobarSqlMapClientTemplateWithoutDefaultPartitionData() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixtureWithJdbcTemplate(names, jt2m); @SuppressWarnings("unchecked") List<Follower> followers = (List<Follower>) getSqlMapClientTemplate().queryForList( "com.alibaba.cobar.client.entities.Follower.findAll"); assertTrue(CollectionUtils.isNotEmpty(followers)); assertEquals(names.length, followers.size()); for (Follower f : followers) { assertTrue(ArrayUtils.contains(names, f.getName())); } } /** * insert records onto partition1, but the * 'com.alibaba.cobar.client.entities.Follower.finaByName' will be performed * against partition2 as per the routing rule, so no record will be * returned. */ public void testQueryForObjectOnCobarSqlMapClientTemplateWithDefaultPartition() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixture(names); for (String name : names) { Follower f = (Follower) getSqlMapClientTemplate().queryForObject( "com.alibaba.cobar.client.entities.Follower.finaByName", name); assertNull(f); } } /** * we insert records onto partition2, and the * 'com.alibaba.cobar.client.entities.Follower.finaByName' action will be * performed against partition2 too, so each record will be returned as * expected. */ public void testQueryForObjectOnCobarSqlMapClientTemplateWithFillingDataOntoPartition2() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixtureWithJdbcTemplate(names, jt2m); for (String name : names) { Follower f = (Follower) getSqlMapClientTemplate().queryForObject( "com.alibaba.cobar.client.entities.Follower.finaByName", name); assertNotNull(f); assertTrue(ArrayUtils.contains(names, f.getName())); } } /** * WARNING: don't do stupid things such like below, we do this because we * can guarantee the shard id will NOT change. if you want to use cobar * client corretly, make sure you are partitioning you databases with shard * id that will not be changed once it's created!!! * <br> * with data fixtures setting up on default data source, and update with * CobarSqlMapClientTemplate. */ public void testUpdateOnCobarSqlMapClientTemplateNormally() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixture(names); for(String name:names) { Follower f = (Follower)jt1m.queryForObject("select * from followers where name=?",new Object[]{name}, new RowMapper(){ public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Follower fl = new Follower(); fl.setId(rs.getLong(1)); fl.setName(rs.getString(2)); return fl; }}); assertNotNull(f); int updatedCount = getSqlMapClientTemplate().update("com.alibaba.cobar.client.entities.Follower.update", f); assertEquals(1, updatedCount); } } /** * WARNING: don't do stupid things such like below, we do this because we * can guarantee the shard id will NOT change. if you want to use cobar * client corretly, make sure you are partitioning you databases with shard * id that will not be changed once it's created!!! * <br> * with data fixtures setting up on another data source, and update with * CobarSqlMapClientTemplate. */ public void testUpdateOnCobarSqlMapClientTemplateAbnormally() { String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" }; batchInsertMultipleFollowersAsFixtureWithJdbcTemplate(names, jt2m); for(String name:names) { Follower f = (Follower) getSqlMapClientTemplate().queryForObject( "com.alibaba.cobar.client.entities.Follower.finaByName", name); assertNotNull(f); // this sql action is performed against partition2 as per routing rule // sql action below will be performed against default data source(partition1), so will not affect any records on partition2 int updatedCount = getSqlMapClientTemplate().update("com.alibaba.cobar.client.entities.Follower.update", f); assertEquals(0, updatedCount); } } }