content: 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 static org.testng.AssertJUnit.fail;
  
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.commons.lang.ArrayUtils;
  import org.springframework.dao.DataAccessException;
  import org.springframework.dao.EmptyResultDataAccessException;
  import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
  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;
  import com.alibaba.cobar.client.support.vo.BatchInsertTask;
  
  @Test(sequential=true)
  public class CobarSqlMapClientTemplateWithNamespaceShardingRouterTest extends
          AbstractTestNGCobarClientTest {
  
      private String                 insertSQLAction      = "com.alibaba.cobar.client.entities.Follower.create";
      private String                 batchInsertSQLAction = "com.alibaba.cobar.client.entities.Follower.batchInsert";
  
      public CobarSqlMapClientTemplateWithNamespaceShardingRouterTest() {
          super(new String[] { "META-INF/spring/cobar-client-appctx.xml",
                  "META-INF/spring/datasources-appctx.xml",
                  "META-INF/spring/namespace-sharding-router-appctx.xml" });
      }
  
      public void testInsertOnCobarSqlMapClientTemplateWithSingleEntityNormally() {
  
          String name = "Darren"; // shard standard
          Follower f = new Follower(name);
          getSqlMapClientTemplate().insert(insertSQLAction, f);
  
          String sql = "select name from followers where name='" + name + "'";
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt1s);
          verifyEntityExistenceOnSpecificDataSource(sql, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt2s);
  
          name = "Aaron";
          f = new Follower(name);
          getSqlMapClientTemplate().insert(insertSQLAction, f);
  
          sql = "select name from followers where name='" + name + "'";
          verifyEntityExistenceOnSpecificDataSource(sql, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(sql, jt2s);
      }
  
      public void testInsertOnCobarSqlMapClientTemplateWithMultipleEntities() {
          String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" };
  
          List<Follower> followers = new ArrayList<Follower>();
          for (String name : names) {
              followers.add(new Follower(name));
          }
          /**
           * NOTE: if the sqlmap is drafted with invalid format, data access
           * exception will be raised, usually, the information of exception
           * doesn't tell too much.
           */
          getSqlMapClientTemplate().insert(batchInsertSQLAction, new BatchInsertTask(followers));
  
          for (String name : names) {
              String sql = "select name from followers where name='" + name + "'";
              if (name.startsWith("A")) {
                  verifyEntityExistenceOnSpecificDataSource(sql, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt1s);
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt2s);
              } else {
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt1s);
                  verifyEntityExistenceOnSpecificDataSource(sql, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(sql, jt2s);
              }
  
          }
      }
  
      /**
       * if no rule is found for current data access request, the data access
       * request will be performed on default data source, that's, partition1.
       */
      public void testInsertWithoutFindingRuleOnCobarSqlMapClientTemplate() {
          String nameStartsWithS = "Sara";
          Follower follower = new Follower(nameStartsWithS);
          getSqlMapClientTemplate().insert(insertSQLAction, follower);
  
          String confirmSQL = "select name from followers where name='" + nameStartsWithS + "'";
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
      }
  
      public void testDeleteOnCobarSqlMapClientTemplate() {
          Follower f = new Follower("Darren");
          getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Follower.create", f);
  
          String confirmSQL = "select name from followers where name='Darren'";
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
  
          getSqlMapClientTemplate().delete("com.alibaba.cobar.client.entities.Follower.deleteByName", f);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
      }
  
      /**
       * MARK!!!
       */
      public void testDeleteWithExpectedResultSizeOnCobarSqlMapClientTemplate() {
          Follower f = new Follower("Darren");
          getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Follower.create", f);
  
          String confirmSQL = "select name from followers where name='Darren'";
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
  
          try {
              getSqlMapClientTemplate().delete("com.alibaba.cobar.client.entities.Follower.deleteByName",
                      f, 2);
              fail("only one row will be affected in fact.");
          } catch (DataAccessException e) {
              assertTrue(e instanceof JdbcUpdateAffectedIncorrectNumberOfRowsException);
              JdbcUpdateAffectedIncorrectNumberOfRowsException ex = (JdbcUpdateAffectedIncorrectNumberOfRowsException) e;
              assertEquals(1, ex.getActualRowsAffected());
          }
          // although JdbcUpdateAffectedIncorrectNumberOfRowsException is raised, but the delete does performed successfully.
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
  
          try {
              getSqlMapClientTemplate().delete("com.alibaba.cobar.client.entities.Follower.deleteByName",
                      f, 0);
          } catch (DataAccessException e) {
              fail();
          }
  
          f = new Follower("Amanda");
          try {
              getSqlMapClientTemplate().delete("com.alibaba.cobar.client.entities.Follower.deleteByName",
                      f, 0);
          } catch (DataAccessException e) {
              fail();
          }
      }
  
      public void testQueryForListOnCobarSqlMapClientTemplate() {
          // 1. initialize data
          String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" };
          batchInsertMultipleFollowersAsFixture(names);
  
          // 2. perform assertion
          @SuppressWarnings("unchecked")
          List<Follower> resultList = (List<Follower>) getSqlMapClientTemplate().queryForList(
                  "com.alibaba.cobar.client.entities.Follower.findAll");
          assertTrue(CollectionUtils.isNotEmpty(resultList));
          assertEquals(3, resultList.size()); // no rule match 'findAll', so query is performed against default data source - partition1
          for (Follower f : resultList) {
              assertTrue(ArrayUtils.contains(names, f.getName()));
          }
  
          // 3. perform assertion with another different query
          @SuppressWarnings("unchecked")
          List<Follower> followersWithNameStartsWithA = (List<Follower>) getSqlMapClientTemplate()
                  .queryForList("com.alibaba.cobar.client.entities.Follower.finaByNameAlike", "A");
          assertTrue(CollectionUtils.isNotEmpty(followersWithNameStartsWithA));
          assertEquals(3, followersWithNameStartsWithA.size());
          for (Follower f : followersWithNameStartsWithA) {
              assertTrue(ArrayUtils.contains(names, f.getName()));
          }
  
          @SuppressWarnings("unchecked")
          List<Follower> followersWithNameStartsWithD = (List<Follower>) getSqlMapClientTemplate()
                  .queryForList("com.alibaba.cobar.client.entities.Follower.finaByNameAlike", "D");
          assertTrue(CollectionUtils.isEmpty(followersWithNameStartsWithD));
      }
  
      /**
       * adapted from {@link CobarSqlMapClientTemplateWithNamespaceRouterTest}
       * with some adjustments.
       */
      public void testQueryForObjectOnCobarSqlMapClientTemplate() {
          // 1. initialize data
          String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" };
          batchInsertMultipleFollowersAsFixture(names);
  
          // 2. assertion.
          for (String name : names) {
              Follower follower = (Follower) getSqlMapClientTemplate().queryForObject(
                      "com.alibaba.cobar.client.entities.Follower.finaByName", name);
              if (name.startsWith("A")) {
                  assertNotNull(follower);
              } else {
                  assertNull(follower);
              }
          }
      }
      /**
       * 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!!!
       */
      public void testUpdateOnCobarSqlMapClientTemplate() {
          String[] names = { "Aaron", "Amily", "Aragon", "Darren", "Darwin" };
          batchInsertMultipleFollowersAsFixture(names);
  
          String nameSuffix = "Wang";
          for (String name : names) {
              if (name.startsWith("A")) {
                  Follower follower = (Follower) getSqlMapClientTemplate().queryForObject(
                          "com.alibaba.cobar.client.entities.Follower.finaByName", name);
                  assertNotNull(follower);
                  follower.setName(follower.getName() + nameSuffix);
                  getSqlMapClientTemplate().update(
                          "com.alibaba.cobar.client.entities.Follower.update", follower);
  
                  Long id = follower.getId();
  
                  follower = null;
                  follower = (Follower) getSqlMapClientTemplate().queryForObject(
                          "com.alibaba.cobar.client.entities.Follower.finaByName", name);
                  assertNull(follower);
  
                  follower = (Follower) getSqlMapClientTemplate().queryForObject(
                          "com.alibaba.cobar.client.entities.Follower.load", id);
                  assertNotNull(follower);
                  assertEquals(name + nameSuffix, follower.getName());
              } else {
                  String sql = "select * from followers where name=?";
                  RowMapper rowMapper = new RowMapper() {
                      public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                          Follower f = new Follower();
                          f.setId(rs.getLong(1));
                          f.setName(rs.getString(2));
                          return f;
                      }
                  };
                  Follower follower = (Follower) jt2m.queryForObject(sql, new Object[] { name },
                          rowMapper);
                  assertNotNull(follower);
                  follower.setName(follower.getName() + nameSuffix);
                  getSqlMapClientTemplate().update(
                          "com.alibaba.cobar.client.entities.Follower.update", follower);
  
                  Long id = follower.getId();
  
                  follower = null;
                  try {
                      follower = (Follower) jt2m
                              .queryForObject(sql, new Object[] { name }, rowMapper);
                      fail();
                  } catch (DataAccessException e) {
                      assertTrue(e instanceof EmptyResultDataAccessException);
                  }
  
                  follower = (Follower) jt2m.queryForObject("select * from followers where id=?",
                          new Object[] { id }, rowMapper);
                  assertNotNull(follower);
                  assertEquals(name + nameSuffix, follower.getName());
              }
          }
      }
  
  }
  