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 java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.List;
  
  import org.apache.commons.lang.ArrayUtils;
  import org.testng.annotations.Test;
  
  import com.alibaba.cobar.client.entities.Offer;
  import com.alibaba.cobar.client.support.utils.CollectionUtils;
  import com.alibaba.cobar.client.support.vo.BatchInsertTask;
  
  @Test(sequential=true)
  public class CobarSqlMapClientTemplateWithComposedRuleRouterTest extends
          AbstractTestNGCobarClientTest {
      private static final String OFFER_CREATION_SQL = "com.alibaba.cobar.client.entities.Offer.create";
  
      public CobarSqlMapClientTemplateWithComposedRuleRouterTest() {
          super(new String[] { "META-INF/spring/cobar-client-appctx.xml",
                  "META-INF/spring/datasources-appctx.xml",
                  "META-INF/spring/namespace-sqlaction-composed-router-appctx.xml" });
      }
  
      public void testInsertOnCobarSqlMapClientTemplate() {
          Offer offer = new Offer();
          offer.setGmtUpdated(new Date());
          offer.setMemberId(129L);
          offer.setSubject("some offer");
          Object pk = getSqlMapClientTemplate().insert(OFFER_CREATION_SQL, offer);
          assertNotNull(pk);
  
          String confirmSQL = "SELECT memberId FROM offers where id=" + pk;
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
  
          offer = new Offer();
          offer.setGmtUpdated(new Date());
          offer.setMemberId(130L);
          offer.setSubject("some offer");
          pk = null;
          pk = getSqlMapClientTemplate().insert(OFFER_CREATION_SQL, offer);
          assertNotNull(pk);
          
          confirmSQL = "SELECT memberId FROM offers where id=" + pk;
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
      }
  
      public void testInsertOnCobarSqlMapClientTemplateWithoutFoundRule() {
          Offer offer = new Offer();
          offer.setGmtUpdated(new Date());
          offer.setMemberId(128L);
          offer.setSubject("some offer");
          Object pk = getSqlMapClientTemplate().insert(OFFER_CREATION_SQL, offer);
          assertNotNull(pk);
  
          String confirmSQL = "SELECT memberId FROM offers where id=" + pk;
          verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
          verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
      }
  
      public void testBatchInsertOnCobarClientTemplateNormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          Object pk = batchInsertOffersAsFixtureForLaterUse(memberIds);
          assertNotNull(pk);
          assertTrue(pk instanceof Collection<?>);
  
          for (int i = 0; i < memberIds.length; i++) {
              String confirmSQL = "select subject from offers where memberId=" + memberIds[i];
              if (i < 3) {
                  verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
              } else {
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
                  verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
              }
          }
      }
  
      public void testDeleteOnCobarSqlMapClientTemplateNormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          // 1. empty data bases
          String sqlAction = "com.alibaba.cobar.client.entities.Offer.deleteByMemberId";
          for (Long mid : memberIds) {
              Offer offer = new Offer();
              offer.setMemberId(mid);
              int affectedRows = getSqlMapClientTemplate().delete(sqlAction, offer);
              assertEquals(0, affectedRows);
          }
          // 2. insert data fixtures
          batchInsertOffersAsFixtureForLaterUse(memberIds);
          for (int i = 0; i < memberIds.length; i++) {
              String confirmSQL = "select subject from offers where memberId=" + memberIds[i];
              if (i < 3) {
                  verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
              } else {
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s);
                  verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m);
                  verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s);
              }
          }
          // 3. perform deletion and assertion
          for (Long mid : memberIds) {
              Offer offer = new Offer();
              offer.setMemberId(mid);
              int affectedRows = getSqlMapClientTemplate().delete(sqlAction, offer);
              assertEquals(1, affectedRows);
          }
      }
  
      public void testDeleteOnCobarSqlMapClientTemplateAbnormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          batchInsertOffersAsFixtureForLaterUse(memberIds);
  
          String deleteSqlAction = "com.alibaba.cobar.client.entities.Offer.delete";
          // no rule can be found for this, so currently, it will be performed against default data source
          for (int i = 0; i < memberIds.length; i++) {
              String selectSQL = "select id from offers where memberId=" + memberIds[i];
              if (i < 3) {
                  Long id = jt1m.queryForLong(selectSQL);
                  int affectedRows = getSqlMapClientTemplate().delete(deleteSqlAction, id);
                  assertEquals(1, affectedRows);
              } else {
                  Long id = jt2m.queryForLong(selectSQL);
                  int affectedRows = getSqlMapClientTemplate().delete(deleteSqlAction, id);
                  assertEquals(0, affectedRows);
              }
          }
      }
  
      @SuppressWarnings("unchecked")
      public void testQueryForListOnCobarSqlMapClientTemplateNormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          batchInsertOffersAsFixtureForLaterUse(memberIds);
  
          List<Offer> offers = (List<Offer>) getSqlMapClientTemplate().queryForList(
                  "com.alibaba.cobar.client.entities.Offer.findAll");
          assertTrue(CollectionUtils.isNotEmpty(offers));
          assertEquals(7, offers.size());
          for (Offer offer : offers) {
              assertTrue(ArrayUtils.contains(memberIds, offer.getMemberId()));
          }
  
          offers = null;
          offers = (List<Offer>) getSqlMapClientTemplate().queryForList(
                  "com.alibaba.cobar.client.entities.Offer.findByMemberIdRange", 300L);
          assertTrue(CollectionUtils.isNotEmpty(offers));
          assertEquals(3, offers.size());
          Long[] partialMemberIds = new Long[] { 1L, 129L, 257L };
          for (Offer offer : offers) {
              assertTrue(ArrayUtils.contains(partialMemberIds, offer.getMemberId()));
          }
      }
  
      public void testQueryForObjectOnCobarSqlMapClientTemplateNormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          batchInsertOffersAsFixtureForLaterUse(memberIds);
  
          // scenario 1: no routing rules are found for current sql action, so only records residing on default data source can be returned.
          String selectSqlActionOne = "com.alibaba.cobar.client.entities.Offer.load";
          for (int i = 0; i < memberIds.length; i++) {
              String confirmSQL = "select id from offers where memberId=" + memberIds[i];
              if (i < 3) {
                  Long id = jt1m.queryForLong(confirmSQL);
                  Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionOne,
                          id);
                  assertNotNull(offer);
                  assertEquals(memberIds[i], offer.getMemberId());
              } else {
                  Long id = jt2m.queryForLong(confirmSQL);
                  Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionOne,
                          id);
                  assertNull(offer);
              }
          }
          // scenario 2: fallback sharding rules can be found for current sql action, so all requested records are returned normally.
          String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId";
          for (Long mid : memberIds) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo,
                      parameter);
              assertNotNull(offer);
              assertEquals(mid, offer.getMemberId());
          }
      }
  
      public void testUpdateOnCobarSqlMapClientTemplateNormally() {
          Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 386L };
          batchInsertOffersAsFixtureForLaterUse(memberIds);
  
          String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId";
          String offerSubject = "_SUBEJCT_";
          for (Long mid : memberIds) {
              // 1. assertion before update
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo,
                      parameter);
              assertNotNull(offer);
              assertEquals("fake offer", offer.getSubject());
              // 2. assertion on update
              offer.setSubject(offerSubject);
              int affectedRows = getSqlMapClientTemplate().update(
                      "com.alibaba.cobar.client.entities.Offer.update", offer);
              assertEquals(1, affectedRows);
              // 3. assertion after update
              offer = null;
              offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, parameter);
              assertNotNull(offer);
              assertEquals(offerSubject, offer.getSubject());
          }
  
      }
  
      private Object batchInsertOffersAsFixtureForLaterUse(Long[] memberIds) {
          List<Offer> offers = new ArrayList<Offer>();
          for (Long mid : memberIds) {
              Offer offer = new Offer();
              offer.setGmtUpdated(new Date());
              offer.setMemberId(mid);
              offer.setSubject("fake offer");
              offers.add(offer);
          }
  
          Object pk = getSqlMapClientTemplate().insert(
                  "com.alibaba.cobar.client.entities.Offer.batchInsert", new BatchInsertTask(offers));
          return pk;
      }
  
  }
  