Merge pull request #1342 from mwoodiupui/DS-2805

[DS-2805] Improper Hibernate Date comparisons
This commit is contained in:
Mark H. Wood
2016-04-14 17:12:45 -04:00
6 changed files with 238 additions and 2 deletions

View File

@@ -24,7 +24,25 @@ import java.util.Date;
* @author kevinvandevelde at atmire.com
*/
public interface ChecksumHistoryDAO extends GenericDAO<ChecksumHistory> {
/**
* Delete all ChecksumHistory rows with retention date before the given and
* the specified result code.
*
* @param context
* @param retentionDate row must be older than this to be deleted.
* @param checksumResultCode row must have this result to be deleted.
* @return number of rows deleted.
* @throws SQLException
*/
public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode checksumResultCode) throws SQLException;
/**
* Delete all ChecksumHistory rows for the given Bitstream.
*
* @param context
* @param bitstream
* @throws SQLException
*/
public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException;
}

View File

@@ -44,8 +44,8 @@ public class ChecksumHistoryDAOImpl extends AbstractHibernateDAO<ChecksumHistory
public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode resultCode) throws SQLException {
String hql = "delete from ChecksumHistory where processEndDate < :processEndDate AND checksumResult.resultCode=:resultCode";
Query query = createQuery(context, hql);
query.setParameter("processEndDate", retentionDate);
query.setParameter("result", resultCode);
query.setTimestamp("processEndDate", retentionDate);
query.setParameter("resultCode", resultCode);
return query.executeUpdate();
}

View File

@@ -0,0 +1,12 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Database access for the Checksum Checker tool, which looks for unexpected
* changes in Bitstream content.
*/
package org.dspace.checker.dao.impl;

View File

@@ -0,0 +1,166 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.checker.dao.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.dspace.AbstractUnitTest;
import org.dspace.checker.ChecksumResultCode;
import org.dspace.content.Bitstream;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.CoreHelpers;
import org.dspace.core.HibernateDBConnection;
import org.hibernate.Query;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author mwood
*/
public class ChecksumHistoryDAOImplTest
extends AbstractUnitTest
{
public ChecksumHistoryDAOImplTest()
{
}
@BeforeClass
public static void setUpClass()
throws SQLException, ClassNotFoundException
{
}
@AfterClass
public static void tearDownClass()
{
}
@Before
public void setUp()
{
}
@After
public void tearDown()
throws SQLException
{
}
/**
* Test of deleteByDateAndCode method, of class ChecksumHistoryDAOImpl.
*/
@Test
public void testDeleteByDateAndCode()
throws Exception
{
System.out.println("deleteByDateAndCode");
GregorianCalendar cal = new GregorianCalendar();
Date retentionDate = cal.getTime();
ChecksumResultCode resultCode = ChecksumResultCode.CHECKSUM_MATCH;
// Create two older rows
HibernateDBConnection dbc = (HibernateDBConnection) CoreHelpers.getDBConnection(context);
Query qry = dbc.getSession().createSQLQuery(
"INSERT INTO checksum_history"
+ "(check_id, process_end_date, result, bitstream_id)"
+ " VALUES (:id, :date, :result, :bitstream)");
int checkId = 0;
// Row with matching result code
BitstreamService bss = ContentServiceFactory.getInstance().getBitstreamService();
InputStream is = new ByteArrayInputStream(new byte[0]);
Bitstream bs = bss.create(context, is);
context.turnOffAuthorisationSystem();
bss.update(context, bs);
context.restoreAuthSystemState();
cal.roll(Calendar.DATE, -1);
Date matchDate = cal.getTime();
checkId++;
qry.setInteger("id", checkId);
qry.setDate("date", matchDate);
qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name());
qry.setString("bitstream", bs.getID().toString()); // FIXME identifier not being set???
qry.executeUpdate();
// Row with nonmatching result code
cal.roll(Calendar.DATE, -1);
Date noMatchDate = cal.getTime();
checkId++;
qry.setInteger("id", checkId);
qry.setDate("date", noMatchDate);
qry.setString("result", ChecksumResultCode.CHECKSUM_NO_MATCH.name());
qry.setString("bitstream", bs.getID().toString());
qry.executeUpdate();
// Create one newer row
cal.roll(Calendar.DATE, +3);
Date futureDate = cal.getTime();
checkId++;
qry.setInteger("id", checkId);
qry.setDate("date", new java.sql.Date(futureDate.getTime()));
qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name());
qry.setString("bitstream", bs.getID().toString());
qry.executeUpdate();
// Test!
ChecksumHistoryDAOImpl instance = new ChecksumHistoryDAOImpl();
int expResult = 1;
int result = instance.deleteByDateAndCode(context, retentionDate,
resultCode);
assertEquals(expResult, result);
// See if matching old row is gone.
qry = dbc.getSession().createQuery(
"SELECT COUNT(*) FROM ChecksumHistory WHERE process_end_date = :date");
long count;
qry.setDate("date", matchDate);
count = (Long) qry.uniqueResult();
assertEquals("Should find no row at matchDate", count, 0);
// See if nonmatching old row is still present.
qry.setDate("date", noMatchDate);
count = (Long) qry.uniqueResult();
assertEquals("Should find one row at noMatchDate", count, 1);
// See if new row is still present.
qry.setDate("date", futureDate);
count = (Long) qry.uniqueResult();
assertEquals("Should find one row at futureDate", count, 1);
}
/**
* Test of deleteByBitstream method, of class ChecksumHistoryDAOImpl.
*/
/*
@Test
public void testDeleteByBitstream()
throws Exception
{
System.out.println("deleteByBitstream");
Bitstream bitstream = null;
ChecksumHistoryDAOImpl instance = new ChecksumHistoryDAOImpl();
instance.deleteByBitstream(context, bitstream);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
*/
}

View File

@@ -0,0 +1,13 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
* Tests for the Checksum Checker tool, which looks for unexpected alterations
* in Bitstream content.
*/
package org.dspace.checker.dao.impl;

View File

@@ -0,0 +1,27 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.core;
/**
* Methods for breaking rules that hamper testing. Not to be used in production.
*
* @author mwood
*/
public class CoreHelpers
{
/**
* Expose a Context's DBConnection.
*
* @param ctx
* @return
*/
static public DBConnection getDBConnection(Context ctx)
{
return ctx.getDBConnection();
}
}