Archive for the ‘Tech’ Category

Better jUnit-ing

Sunday, April 2nd, 2006

jUnit has been around for a long time. But there are always better techniques to implement old ways. I have provided below an efficient junit aprroach integrated with DbUnit and Spring with support for transaction and hibernate open session. Significant features are:

  • Integration with DbUnit: DbUnit puts database into a known state between test runs. Pre-loads database with known data set before the test
  • Transaction support using spring: After each test all changes made by the test are rolled back. Hence there is no need to programatically undo channges made by the test. Much cleaner code. (Thanks, Jim)
  • After each test, clear the pre-loaded data set from database
  • Support for open session in view: Web applications using Hibernate with lazy loading need to keep the session open till the view is rendered. (Read more)

/**
* Junit test integrated with DbUnit and spring. Provides support for
* transaction and open session. This wraps each test method with a
* transaction and rollbacks after the method exits. DbUnit
* is used to load up the table with initial set of values.
*/

public class MyTest extends AbstractTransactionalDataSourceSpringContextTests {

private SessionFactory sessionFactory;
private Session session;
private static ConfigurableApplicationContext factory;
private final String[] TABLES = { “EmployeeTable”, “DepartmentTable” };
private final String DATA_FILE = “data.xml”;
private final String[] CONFIG_LOCATIONS = { “spring-context.xml” };

public static Test suite() {
return new TestSuite(MyTest.class);
}

protected String[] getConfigLocations() {
return CONFIG_LOCATIONS;
}

// This method is used to perform any setup operations, such as
// populating a database table, within the transaction.
protected void onSetUpInTransaction() throws Exception {
super.onSetUpInTransaction();
if (factory == null) {
factory = new ClassPathXmlApplicationContext(getConfigLocations());
}
// Load test data using DBUnit
DataSource ds = (DataSource) factory.getBean(”dataSource”);
Connection con = DataSourceUtils.getConnection(ds);
IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
IDataSet dataSet = new FlatXmlDataSet(Thread.currentThread().
getContextClassLoader().getResourceAsStream(DATA_FILE));
try {
DatabaseOperation.CLEAN_INSERT.execute(dbUnitCon, dataSet);
} finally {
DataSourceUtils.releaseConnection(con, ds);
}
// Support of open session
sessionFactory = (SessionFactory) factory.getBean(”sessionFactory”);
session = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
}

protected void onTearDownAfterTransaction() throws Exception {
// delete table entries
deleteFromTables(TABLES);
// release session
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
session = holder.getSession();
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.releaseSession(session, sessionFactory);
}

public void testSomething() throws Exception {
// …
}

}

Access denied error in MySQL

Friday, March 31st, 2006

Have you been frustrated with Access denied for user ‘chinnu’@’localhost’ errors even though as root you granted following privileges:

GRANT ALL PRIVILEGES ON MyDb.* to 'chinnu'@'%' WITH GRANT OPTION;

While % means any host, you probably did not see the behavior you expected.

MySQL performs access control in two stages. First, it tries to connect you with the username/password provided. Next, it checks if you have the privileges to perform your request. Entries in tables user, db and host of mysql database are used for access control.

Lets say this is our user table:

--------------------
Host      |  User
--------------------
%         |  root
%         |  chinnu
localhost |  root
localhost |
-------------------

% in Host means ‘any host’ and blank in User means any user or anonymous user. Note that the value % is less specific when compared to value localhost. MySQL, when performing access control, sorts this table with the most-specific Host at the top. So, we have something like

--------------------
Host      |  User
--------------------
localhost |  root
localhost |
%         |  chinnu
%         |  root
-------------------

When chinnu tries to login from localhost, there are two matching rows. Guess what, the first match wins. This means that chinnu is effectively logged in as an anonymous user. The anonymous user may not have privileges for MyDb, hence the access denied errors.

How to verify?
If you managed to connect execute SELECT CURRENT_USER(). If you get result as @localhost and not chinnu@localhost, you have the issue described above.

How to solve this?
Solution-1: Grant privileges for ‘chinnu’@’localhost’ in addition to ‘chinnu’@’%’
Solution-2: Just get rid of the anonymous user