/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 integration.anyframe.services.transaction;

import integration.anyframe.services.AbstractTest;
import integration.anyframe.services.transaction.sample.TransactionTestSampleService;
import integration.anyframe.services.transaction.sample.TransactionVo;

import java.math.BigDecimal;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import anyframe.core.query.IQueryService;
import anyframe.core.query.QueryServiceException;

public abstract class AbstractTransactionServiceTest extends AbstractTest {

	protected TransactionTestSampleService service = null;

	protected PlatformTransactionManager transactionManager = null;

	protected void setup() {
		super.setup();
		try {
			testInit();
		} catch (Exception e) {
			// ignore this exception
		}
	}

	/**
	 * 테스트 코드를 샐행하기 위한 test table 생성
	 */
	public void testInit() throws Exception {
		IQueryService m_service = (IQueryService) context
				.getBean("queryService");

		// Try to drop the table. It may not exist and throw an exception.
		System.out.println("Attempting to drop old table");
		m_service.updateBySQL("DROP TABLE IF EXISTS transactiontest",
				new String[] {}, new Object[] {});

		// Create the table that we will use in this test.
		// Different depending on the db. Please add new statements as new
		// databases are tested.
		System.out.println("Create new table");
		m_service.updateBySQL("CREATE TABLE transactiontest ("
				+ "col1 VARCHAR(100) NOT NULL, " + "col2 VARCHAR(100) , "
				+ "col3 NUMERIC(100) NOT NULL)", new String[] {},
				new Object[] {});
	}

	public void testInsertCommit() throws Exception {
		// 1. get previous commit count
		int prevCommitCount = service.getCommitCount();
		TransactionVo vo = new TransactionVo();
		vo.setCol1(Thread.currentThread().getName() + "-col1");
		vo.setCol2(Thread.currentThread().getName() + "-col2");
		vo.setCol3(new BigDecimal(System.currentTimeMillis()));
		// 2. execute insert commit
		service.insertData(vo);
		// 3. assert
		boolean checked = prevCommitCount + 1 == service.getCommitCount();
		if (!checked)
			throw new Exception("fail to insert commit.");
	}

	public void testInsertRollback() throws Exception {
		Thread.sleep(500);
		
		// 1. get previous commit count and rollback count		
		int prevCommitCount = service.getCommitCount();
		int prevRollbackCount = service.getRollbackCount();
		DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
		txDefinition
				.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus txStatus = transactionManager
				.getTransaction(txDefinition);
		try {
			// 2. execute commit twice with a same data
			TransactionVo vo = new TransactionVo();
			vo.setCol1(Thread.currentThread().getName() + "-col1");
			vo.setCol2(Thread.currentThread().getName() + "-col2");
			vo.setCol3(new BigDecimal(System.currentTimeMillis()));
			service.insertData(vo);
			service.insertData(vo);
			transactionManager.commit(txStatus);
		} catch (QueryServiceException e) {
			// 3. execute rollback
			transactionManager.rollback(txStatus);
		} finally {
			// 4. assert
			boolean checkedCommit = prevCommitCount == service.getCommitCount();
			if (!checkedCommit)
				throw new Exception("fail to get commit count.");
			
			boolean checkedRollback = prevRollbackCount + 2 == service.getRollbackCount();
			if (!checkedRollback)
				throw new Exception("fail to get rollback count.");
		}

	}

	public void testUpdateCommit() throws Exception {
		Thread.sleep(500);
		// 1. get previous commit count		
		int prevCommitCount = service.getCommitCount();
		TransactionVo vo = new TransactionVo();
		vo.setCol1(Thread.currentThread().getName() + "-col1");
		vo.setCol2(Thread.currentThread().getName() + "-col2");
		vo.setCol3(new BigDecimal(System.currentTimeMillis()));
		// 2. execute insert commit
		service.insertData(vo);
		// 3. execute update commit
		vo.setCol2(Thread.currentThread().getName() + "-col2-modified");		
		service.updateData(vo);
		// 4. assert
		boolean checked = prevCommitCount + 2 == service.getCommitCount();
		if (!checked)
			throw new Exception("fail to commit count.");		
	}

	public void testUpdateRollback() throws Exception {
		Thread.sleep(500);
		// 1. get previous commit count and rollback count				
		int prevCommitCount = service.getCommitCount();
		int prevRollbackCount = service.getRollbackCount();
		DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
		txDefinition
				.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus txStatus = transactionManager
				.getTransaction(txDefinition);
		try {
			TransactionVo vo = new TransactionVo();
			vo.setCol1(Thread.currentThread().getName() + "-col1");
			vo.setCol2(Thread.currentThread().getName() + "-col2");
			vo.setCol3(new BigDecimal(System.currentTimeMillis()));
			service.insertData(vo);
			vo.setCol2(Thread.currentThread().getName() + "-col2-modified");
			service.updateData(vo);
			// 2. execute commit twice with a same data
			service.insertData(vo);
			transactionManager.commit(txStatus);
		} catch (QueryServiceException e) {
			// 3. execute rollback			
			transactionManager.rollback(txStatus);
		} finally {
			// 4. assert
			boolean checkedCommit = prevCommitCount == service.getCommitCount();
			if (!checkedCommit)
				throw new Exception("fail to get commit count.");
			
			boolean checkedRollback = prevRollbackCount + 3 == service.getRollbackCount();
			if (!checkedRollback)
				throw new Exception("fail to get rollback count.");			
		}

	}

	public void testRemoveCommit() throws Exception {
		Thread.sleep(500);
		// 1. get previous commit count				
		int prevCommitCount = service.getCommitCount();
		TransactionVo vo = new TransactionVo();
		vo.setCol1(Thread.currentThread().getName() + "-col1");
		vo.setCol2(Thread.currentThread().getName() + "-col2");
		vo.setCol3(new BigDecimal(System.currentTimeMillis()));
		// 2. execute insert and remove commit
		service.insertData(vo);
		service.removeData(vo);
		// 3. assert
		boolean checked = prevCommitCount + 2 == service.getCommitCount();
		if (!checked)
			throw new Exception("fail to commit count.");			
	}

	public void testRemoveRollback() throws Exception {
		Thread.sleep(500);
		// 1. get previous commit count and rollback count				
		int prevCommitCount = service.getCommitCount();
		int prevRollbackCount = service.getRollbackCount();
		DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
		txDefinition
				.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus txStatus = transactionManager
				.getTransaction(txDefinition);
		try {
			TransactionVo vo = new TransactionVo();
			vo.setCol1(Thread.currentThread().getName() + "-col1");
			vo.setCol2(Thread.currentThread().getName() + "-col2");
			vo.setCol3(new BigDecimal(System.currentTimeMillis()));
			service.insertData(vo);
			service.removeData(vo);
			// 2. execute commit twice with a same data			
			service.insertData(vo);			
			service.insertData(vo);
			transactionManager.commit(txStatus);
		} catch (QueryServiceException e) {
			// 3. execute rollback	
			transactionManager.rollback(txStatus);
		} finally {
			// 4. assert
			boolean checkedCommit = prevCommitCount == service.getCommitCount();
			if (!checkedCommit)
				throw new Exception("fail to get commit count.");
			
			boolean checkedRollback = prevRollbackCount + 4 == service.getRollbackCount();
			if (!checkedRollback)
				throw new Exception("fail to get rollback count.");				
		}

	}

}
