// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: TestHsqlPersistenceManager.java,v 1.9 2006/09/27 16:04:23 spyromus Exp $
//
package com.salas.bb.persistence.backend;
import com.salas.bb.domain.SearchFeed;
import com.salas.bb.domain.StandardArticle;
import com.salas.bb.domain.query.ICriteria;
import com.salas.bb.domain.query.articles.ArticleTextProperty;
import com.salas.bb.domain.query.articles.Query;
import com.salas.bb.domain.query.general.StringContainsCO;
import com.salas.bb.persistence.PersistenceException;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
/**
* This suite contains tests for <code>HsqlPersistenceManager</code> unit.
*/
public class TestHsqlPersistenceManager extends AbstractHsqlPersistenceTestCase
{
/**
* Tests opening several connections in the same thread.
*
* @throws SQLException db error.
*/
public void testSeveralConnectionsSingleThread()
throws SQLException
{
// Init the most modern database
initManager("/resources");
Connection c1 = pm.getConnection();
Connection c2 = pm.getConnection();
assertTrue("Connections should be the same.", c1 == c2);
}
/**
* Tests opening several connections in two different threads.
*
* @throws SQLException db error.
* @throws InterruptedException interruption.
*/
public void testSeveralConnectionsMultiThread()
throws SQLException, InterruptedException
{
// Init the most modern database
initManager("/resources");
final Connection c1 = pm.getConnection();
Thread thread = new Thread()
{
public void run()
{
try
{
Connection c2 = pm.getConnection();
assertTrue("Connection should be the same.", c1 == c2);
c2.close();
} catch (SQLException e)
{
e.printStackTrace();
fail();
}
}
};
thread.start();
thread.join();
}
/**
* Tests the backuping the database.
*
* @throws IOException I/O problem.
*/
public void testBackuping()
throws IOException
{
// Init the most modern database
initManager("/resources");
int version = 1;
assertFalse("There should be no backup for version 1.", pm.isBackupPresent(version));
// Create backup folder for version 1 and check again
pm.makeBackup(version);
assertBackup(version);
}
/**
* Tests that when removing SearchFeed it doesn't clear the ID's of
* the articles this contained because the articles do not belong to
* this feed.
*
* NOTE: It was the reason for most of "Article is not in database" errors
*/
public void testClearFeedIDSearchFeed()
{
Query query = new Query();
ICriteria criteria = query.addCriteria();
criteria.setProperty(ArticleTextProperty.INSTANCE);
criteria.setComparisonOperation(StringContainsCO.INSTANCE);
criteria.setValue("*a*");
SearchFeed feed = new SearchFeed();
feed.setQuery(query);
feed.setArticlesLimit(1);
StandardArticle article = new StandardArticle("aaa");
article.setID(1); // Make impression of that it was already saved
feed.addArticleIfMatching(article);
assertEquals("Article wasn't added.", 1, feed.getArticlesCount());
// Checking
HsqlPersistenceManager.clearFeedID(feed);
assertFalse("Article ID shouldn't be reset because the article doesn't " +
"belong to this feed.", -1 == article.getID());
}
/**
* Tests the connection lifecycle.
*
* @throws SQLException db error.
*/
public void testConnectionReopening() throws SQLException
{
// Init the most modern database
initManager("/resources");
// Get initial connection
Connection con = pm.getConnection();
assertNotNull(con);
assertFalse(con.isClosed());
assertFalse(isSessionClosed(con));
// Close connection and verify
pm.closeConnection();
assertTrue(con.isClosed());
// Get new connection and verify
con = pm.getConnection();
assertFalse(con.isClosed());
assertFalse(isSessionClosed(con));
}
/**
* Tests the connection lifecycle.
*
* @throws SQLException db error.
*/
public void testShutdown() throws SQLException
{
// Init the most modern database
initManager("/resources");
// Shutdown database and verify that the connection is closed
Connection con = pm.getConnection();
pm.shutdown();
assertTrue(con.isClosed());
// Reopen database
con = pm.getConnection();
assertFalse(con.isClosed());
assertFalse(isSessionClosed(con));
}
/**
* We try to start the engine from the incorrect database files and
* check how the database is reset and reinitialized.
*
* @throws SQLException db error.
*/
public void testDatabaseReset() throws SQLException
{
// Init the most modern database
initManager("/data/migration/2.23_bad");
disableLogging(HsqlPersistenceManager.class);
try
{
pm.init();
assertTrue(pm.isDatabaseReset());
} catch (PersistenceException e)
{
fail(e.getMessage());
} finally
{
enableLogging(HsqlPersistenceManager.class);
}
// Check current schema version
int version = pm.getCurrentSchemaVersion();
assertTrue("Database wasn't reset", version > 0);
// Check the status of connection
Connection con = pm.getConnection();
assertFalse(con.isClosed());
assertFalse(isSessionClosed(con));
}
/**
* Checks if the session is closed.
*
* @param con connection.
*
* @return TRUE if closed.
*/
private static boolean isSessionClosed(Connection con)
{
boolean closed = true;
try
{
Statement stmt = con.createStatement();
stmt.executeQuery("SELECT * FROM GUIDES");
closed = false;
} catch (SQLException e)
{
if (e.getErrorCode() != -33) fail(e.getMessage());
}
return closed;
}
/**
* Verifies that backup is present for a given version, i.e. the directory is there
* and it has .properties and .script files.
*
* @param aVersion version to look backup for.
*/
private void assertBackup(int aVersion)
{
assertTrue("There should be backup for version 1.", pm.isBackupPresent(aVersion));
File backupFolder = new File(contextPath +
HsqlPersistenceManager.getBackupFolderName(aVersion));
assertTrue("Backup folder should be present.", backupFolder.exists());
List filesInBackup = Arrays.asList(backupFolder.list());
assertTrue("blogbridge.properties wasn't copied.",
filesInBackup.contains("blogbridge.properties"));
assertTrue("blogbridge.script wasn't copied.",
filesInBackup.contains("blogbridge.script"));
}
// --------------------------------------------------------------------------------------------
// Deleted Feeds Management
// --------------------------------------------------------------------------------------------
/**
* Tests adding new deleted object record.
*
* @throws PersistenceException error.
*/
public void testAddDeletedObjectRecord() throws PersistenceException
{
String gt = "_gt";
String fk = "_fk";
// Init the most modern database
initManager("/resources");
// Remove all deleted records
pm.purgeDeletedObjectRecords();
// Check if the record is there
assertFalse(pm.isDeletedObjectRecordPresent(gt, fk));
// Add new records
pm.addDeletedObjectRecord(gt, fk);
// Check if the record is there
assertTrue(pm.isDeletedObjectRecordPresent(gt, fk));
}
/**
* Tests deleting newly added new deleted object record.
*
* @throws PersistenceException error.
*/
public void testDeleteDeletedObjectRecord() throws PersistenceException
{
String gt = "_gt";
String fk = "_fk";
// Init the most modern database
initManager("/resources");
// Remove all deleted records
pm.purgeDeletedObjectRecords();
// Check if the record is there
assertFalse(pm.isDeletedObjectRecordPresent(gt, fk));
// Add new record and then delete it
pm.addDeletedObjectRecord(gt, fk);
pm.removeDeletedObjectRecord(gt, fk);
// Check if the record is there
assertFalse(pm.isDeletedObjectRecordPresent(gt, fk));
}
}