/*
* Copyright (C) 2012, Katy Hilgenberg.
* Special acknowledgments to: Knowledge & Data Engineering Group, University of Kassel (http://www.kde.cs.uni-kassel.de).
* Contact: sdcf@cs.uni-kassel.de
*
* This file is part of the SDCFramework (Sensor Data Collection Framework) project.
*
* The SDCFramework is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The SDCFramework 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SDCFramework. If not, see <http://www.gnu.org/licenses/>.
*/
package de.unikassel.android.sdcframework.persistence.tests;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;
import de.unikassel.android.sdcframework.data.Sample;
import de.unikassel.android.sdcframework.data.independent.AccelerometerSampleData;
import de.unikassel.android.sdcframework.data.independent.BluetoothSampleData;
import de.unikassel.android.sdcframework.data.independent.GPSSampleData;
import de.unikassel.android.sdcframework.data.independent.GSMSampleData;
import de.unikassel.android.sdcframework.data.independent.FileReferenceSampleData;
import de.unikassel.android.sdcframework.data.independent.GeoLocation;
import de.unikassel.android.sdcframework.data.independent.TwitterSampleData;
import de.unikassel.android.sdcframework.data.independent.WifiSampleData;
import de.unikassel.android.sdcframework.data.tests.TestAccelerometerSampleData;
import de.unikassel.android.sdcframework.data.tests.TestBluetoothSampleData;
import de.unikassel.android.sdcframework.data.tests.TestGPSSampleData;
import de.unikassel.android.sdcframework.data.tests.TestGSMSampleData;
import de.unikassel.android.sdcframework.data.tests.TestSampleCollection;
import de.unikassel.android.sdcframework.data.tests.TestWifiSampleData;
import de.unikassel.android.sdcframework.devices.facade.SensorDeviceIdentifier;
import de.unikassel.android.sdcframework.devices.facade.SensorDevicePriorities;
import de.unikassel.android.sdcframework.persistence.DatabaseAdapterImpl;
import de.unikassel.android.sdcframework.persistence.facade.DatabaseSample;
import de.unikassel.android.sdcframework.test.DelegatingMockContext;
import android.test.AndroidTestCase;
/**
* @author Katy Hilgenberg
*
*/
public class TestDatabaseAdapter extends AndroidTestCase
{
/**
* The maximum database size for all not size base tests
*/
private final static long dbMaxDefaultSize = 1024 * 1024;
/**
* The test database name
*/
public final static String testDBName = "TestDatabase";
/*
* (non-Javadoc)
*
* @see android.test.AndroidTestCase#setUp()
*/
protected void setUp() throws Exception
{
setContext( new DelegatingMockContext( getContext() ) );
getContext().deleteDatabase( testDBName );
super.setUp();
}
/*
* (non-Javadoc)
*
* @see android.test.AndroidTestCase#tearDown()
*/
protected void tearDown() throws Exception
{
getContext().deleteDatabase( testDBName );
super.tearDown();
}
/**
* Test method for creation, open, close and initial record count
*/
public final void testDatabaseAdapter()
{
try
{
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
}
catch ( Exception e )
{
fail( "Unexpected exception while creating database adapter" );
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
try
{
dbAdapter.open();
}
catch ( Exception e )
{
fail( "Unexpected exception in open database adapter" );
}
try
{
long count = dbAdapter.getRecordCount();
assertEquals( "Expected empty database", 0, count );
}
catch ( Exception e )
{
fail( "Unexpected exception while requesting record count " );
}
try
{
dbAdapter.close();
}
catch ( Exception e )
{
fail( "Unexpected exception in open database adapter" );
}
}
/**
* Test method for sample insertion.
*/
public final void testInsertSamples()
{
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
dbAdapter.open();
try
{
dbAdapter.insertSamples( sc );
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to insert samples into database" );
}
long count = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected record count in database", sc.size(), count );
// try to read samples with another adapter instance
dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
dbAdapter.open();
count = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected record count in database", sc.size(), count );
// test erase of all records
dbAdapter.open();
boolean success = false;
try
{
success = dbAdapter.deleteAll();
count = dbAdapter.getRecordCount();
dbAdapter.close();
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to insert samples into database" );
}
assertEquals( "Expected empty database", 0, count );
assertTrue( "Failed to delete all records", success );
}
/**
* Simple test method for sample insertion and removal
*/
public final void testInsertAndRemove()
{
Collection< DatabaseSample > sc = new Vector< DatabaseSample >();
Sample sample =
new Sample( SensorDeviceIdentifier.GPS, System.currentTimeMillis(),
SensorDevicePriorities.Level0.ordinal(), true );
sample.setData( TestGPSSampleData.createInitializedGPSSampleData() );
GeoLocation location = new GeoLocation();
location.setLat( 180. );
location.setLon( -27. );
sample.setLocation( location );
try
{
sc.add( new DatabaseSample( sample ) );
}
catch ( Exception e )
{
e.printStackTrace();
fail( "Unexpected exception during creation of database samples" );
}
// insert the sample
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
assertEquals( "Expected sample added", 1, insertSamples( sc, dbAdapter ) );
// remove the sample and test for same content
sc.clear();
dbAdapter.open();
boolean success = dbAdapter.removeSamplesHighestPrioFirst( 1, sc );
long currentCount = dbAdapter.getRecordCount();
dbAdapter.close();
assertTrue( "Failed to remove sample from database", success );
assertEquals( "Unexpected record count in database", 0, currentCount );
assertEquals( "Unexpected removed sample count", 1, sc.size() );
DatabaseSample dbSample = sc.iterator().next();
assertEquals( "Expected same content in removed sample", sample,
dbSample.toSample() );
}
/**
* Test method for sample insertion and removal by oldest time stamp.
*/
public final void testRemoveSamples()
{
int limit = 3;
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
for ( DatabaseSample sample : sc )
{
int prio =
(int) ( Math.random() * SensorDevicePriorities.values().length );
sample.priority = prio;
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
long count = insertSamples( sc, dbAdapter );
// tests successive removal of records
Collection< DatabaseSample > removedSamples =
new Vector< DatabaseSample >();
int removedSampleCount = 0;
while ( count > 0 )
{
try
{
dbAdapter.open();
boolean success =
dbAdapter.removeSamplesOldestTimeStampFirst( limit, removedSamples );
long currentCount = dbAdapter.getRecordCount();
dbAdapter.close();
removedSampleCount += Math.min( limit, count );
count = Math.max( 0, count - limit );
assertTrue( "Failed to remove " + limit + " records from database",
success );
assertEquals( "Unexpected record count in database", count,
currentCount );
assertEquals( "Unexpected sample count removed", removedSamples.size(),
removedSampleCount );
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to remove samples from database" );
}
}
// test final states
dbAdapter.open();
count = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected record count in database", 0, count );
assertEquals( "Unexpected sample count removed from db", sc.size(),
removedSampleCount );
// test if samples have been removed in descending priority and ascending
// time stamp order
DatabaseSample lastSample = null;
for ( DatabaseSample sample : removedSamples )
{
if ( lastSample != null )
{
if ( lastSample.priority == sample.priority )
{
// tests ascending order by time stamp for samples with same priority
assertTrue(
"Expected current sample timestamp " + sample.timeStamp
+ " more than last sample timestamp "
+ lastSample.timeStamp,
lastSample.timeStamp <= sample.timeStamp );
}
}
lastSample = sample;
}
}
/**
* Test method for sample insertion and removal by lowest priority.
*/
public final void testRemoveSamplesByLowestPriority()
{
int limit = 3;
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
for ( DatabaseSample sample : sc )
{
int prio =
(int) ( Math.random() * SensorDevicePriorities.values().length );
sample.priority = prio;
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
long count = insertSamples( sc, dbAdapter );
// tests successive removal of records
Collection< DatabaseSample > removedSamples =
new Vector< DatabaseSample >();
int removedSampleCount = 0;
while ( count > 0 )
{
try
{
dbAdapter.open();
boolean success =
dbAdapter.removeSamplesLowestPrioFirst( limit, removedSamples );
long currentCount = dbAdapter.getRecordCount();
dbAdapter.close();
removedSampleCount += Math.min( limit, count );
count = Math.max( 0, count - limit );
assertTrue( "Failed to remove " + limit + " records from database",
success );
assertEquals( "Unexpected record count in database", count,
currentCount );
assertEquals( "Unexpected sample count removed", removedSamples.size(),
removedSampleCount );
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to remove samples from database" );
}
}
// test final states
dbAdapter.open();
count = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected record count in database", 0, count );
assertEquals( "Unexpected sample count removed from db", sc.size(),
removedSampleCount );
// test if samples have been removed in descending priority and ascending
// time stamp order
DatabaseSample lastSample = null;
for ( DatabaseSample sample : removedSamples )
{
if ( lastSample != null )
{
// tests ascending sort by priority
assertTrue(
"Expected priority level of current sample less than last sample",
lastSample.priority >= sample.priority );
if ( lastSample.priority == sample.priority )
{
// tests ascending order by time stamp for samples with same priority
assertTrue(
"Expected current sample timestamp " + sample.timeStamp
+ " more than last sample timestamp "
+ lastSample.timeStamp,
lastSample.timeStamp <= sample.timeStamp );
}
}
lastSample = sample;
}
}
/**
* Test method for sample insertion and removal by highest priority.
*/
public final void testRemoveSamplesByHighestPriority()
{
int limit = 3;
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
for ( DatabaseSample sample : sc )
{
int prio =
(int) ( Math.random() * SensorDevicePriorities.values().length );
sample.priority = prio;
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
long count = insertSamples( sc, dbAdapter );
// tests successive removal of records
Collection< DatabaseSample > removedSamples =
new Vector< DatabaseSample >();
int removedSampleCount = 0;
while ( count > 0 )
{
try
{
dbAdapter.open();
boolean success =
dbAdapter.removeSamplesHighestPrioFirst( limit, removedSamples );
long currentCount = dbAdapter.getRecordCount();
dbAdapter.close();
removedSampleCount += Math.min( limit, count );
count = Math.max( 0, count - limit );
assertTrue( "Failed to remove " + limit + " records from database",
success );
assertEquals( "Unexpected record count in database", count,
currentCount );
assertEquals( "Unexpected sample count removed", removedSamples.size(),
removedSampleCount );
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to remove samples from database" );
}
}
// test final states
dbAdapter.open();
count = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected record count in database", 0, count );
assertEquals( "Unexpected sample count removed from db", sc.size(),
removedSampleCount );
// test if samples have been removed in ascending priority and ascending
// time stamp order
DatabaseSample lastSample = null;
for ( DatabaseSample sample : removedSamples )
{
if ( lastSample != null )
{
// tests ascending sort by priority
assertTrue(
"Expected priority level of current sample more than last sample",
lastSample.priority <= sample.priority );
if ( lastSample.priority == sample.priority )
{
// tests ascending order by time stamp for samples with same priority
assertTrue(
"Expected current sample timestamp " + sample.timeStamp
+ " more than last sample timestamp "
+ lastSample.timeStamp,
lastSample.timeStamp <= sample.timeStamp );
}
}
lastSample = sample;
}
}
/**
* Test method for sample deletion by oldest time stamp
*/
public final void testDeleteSamplesWithOldestTimestamp()
{
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
for ( DatabaseSample sample : sc )
{
int prio =
(int) ( Math.random() * SensorDevicePriorities.values().length );
sample.priority = prio;
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
insertSamples( sc, dbAdapter );
// tests deletion of oldest records
try
{
dbAdapter.open();
long recordCountBefore = dbAdapter.getRecordCount();
long countToDelete = recordCountBefore / 2;
long removedSampleCount =
dbAdapter.deleteSamplesOrdered( countToDelete, false );
long recordCountAfter = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected return value for delete records",
countToDelete,
removedSampleCount );
assertEquals( "Unexpected count of deleted records", countToDelete,
recordCountBefore - recordCountAfter );
Collection< DatabaseSample > remainingSamples =
new Vector< DatabaseSample >();
dbAdapter.open();
dbAdapter.removeSamplesOldestTimeStampFirst( recordCountAfter,
remainingSamples );
dbAdapter.close();
List< DatabaseSample > originalSamples =
new ArrayList< DatabaseSample >( sc );
Comparator< DatabaseSample > comparator =
new Comparator< DatabaseSample >()
{
@Override
public int compare( DatabaseSample o1, DatabaseSample o2 )
{
return (int) ( o1.timeStamp - o2.timeStamp );
}
};
Collections.sort( originalSamples, comparator );
for ( int i = 0; i < removedSampleCount; ++i )
{
DatabaseSample sample = originalSamples.get( i );
assertFalse(
"Expected oldest original samples not in collection of remaing samples",
remainingSamples.contains( sample ) );
}
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to delete samples from database" );
}
}
/**
* Test method for sample deletion by lowest priority first
*/
public final void testDeleteSamplesLowestPrioFirst()
{
// create Test data to write to database
Collection< DatabaseSample > sc = getCollectionWithTestData();
for ( DatabaseSample sample : sc )
{
int prio =
(int) ( Math.random() * SensorDevicePriorities.values().length );
sample.priority = prio;
}
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
insertSamples( sc, dbAdapter );
// tests deletion of oldest records
try
{
dbAdapter.open();
long recordCountBefore = dbAdapter.getRecordCount();
long countToDelete = recordCountBefore / 2;
long removedSampleCount =
dbAdapter.deleteSamplesOrdered( countToDelete, true );
long recordCountAfter = dbAdapter.getRecordCount();
dbAdapter.close();
assertEquals( "Unexpected return value for delete records",
countToDelete,
removedSampleCount );
assertEquals( "Unexpected count of deleted records", countToDelete,
recordCountBefore - recordCountAfter );
Collection< DatabaseSample > remainingSamples =
new Vector< DatabaseSample >();
dbAdapter.open();
dbAdapter.removeSamplesOldestTimeStampFirst( recordCountAfter,
remainingSamples );
dbAdapter.close();
List< DatabaseSample > originalSamples =
new ArrayList< DatabaseSample >( sc );
Comparator< DatabaseSample > comparator =
new Comparator< DatabaseSample >()
{
@Override
public int compare( DatabaseSample o1, DatabaseSample o2 )
{
int result = o2.priority - o1.priority;
if ( result == 0 )
{
result = (int) ( o1.timeStamp - o2.timeStamp );
}
return result;
}
};
Collections.sort( originalSamples, comparator );
for ( int i = 0; i < removedSampleCount; ++i )
{
DatabaseSample sample = originalSamples.get( i );
assertFalse(
"Expected oldest original samples with lowest priority deleted",
remainingSamples.contains( sample ) );
}
}
catch ( Exception e )
{
dbAdapter.close();
fail( "Unexpected exception while trying to delete samples from database" );
}
}
/**
* Test method for sample insertion and removal by highest priority.
*/
public final void testSetMaximumDatabaseSize()
{
getContext().deleteDatabase( testDBName );
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
dbAdapter.open();
// test initial maximum size
assertEquals( "Expected new maximum size set", dbMaxDefaultSize,
dbAdapter.getMaximumDatabaseSize() );
// change maximum size
long size = dbAdapter.getPageSize() * 10;
assertEquals( "Expected size update successful", size,
dbAdapter.setMaximumDatabaseSize( size ) );
assertEquals( "Expected new maximum size set", size,
dbAdapter.getMaximumDatabaseSize() );
dbAdapter.close();
// tests for new instance
dbAdapter.open();
assertEquals( "Expected new maximum size set", size,
dbAdapter.getMaximumDatabaseSize() );
dbAdapter.close();
}
/**
* Test method for sample insertion and removal by highest priority.
*/
public final void testMaximumDatabaseSizeExceeded()
{
getContext().deleteDatabase( testDBName );
DatabaseAdapterImpl dbAdapter =
new DatabaseAdapterImpl( testDBName, dbMaxDefaultSize, getContext() );
dbAdapter.open();
// limit size
long maxSize = dbAdapter.getPageSize() * 10;
assertEquals( "Expected new maximum size set", maxSize,
dbAdapter.setMaximumDatabaseSize( maxSize ) );
// create Test data to write to database
Collection< DatabaseSample > sc = new Vector< DatabaseSample >();
try
{
for ( int i = 0; i < 200; ++i )
{
sc.add( new DatabaseSample( TestSampleCollection.createSample(
SensorDeviceIdentifier.GSM,
TestGSMSampleData.createInitializedGSMSampleData() ) ) );
}
}
catch ( Exception e )
{
fail( "Unexpected exception" );
}
assertEquals( "Unexpected size of sample collection", 200, sc.size() );
// write to DB to trigger size exceeded exception
try
{
// insert test data
dbAdapter.insertSamples( sc );
assertEquals( "Expected " + sc.size() + " records added", sc.size(),
dbAdapter.getRecordCount() );
fail( "Expected exception due to DB size limit exceeded" );
}
catch ( Exception e )
{}
finally
{
dbAdapter.close();
}
}
/**
* Method to insert a sample collection into the given database
*
* @param sampleCollection
* the sample collection to insert into database
* @param dbAdapter
* the database adapter
* @return the current record count in database
*/
public static long insertSamples(
Collection< DatabaseSample > sampleCollection,
DatabaseAdapterImpl dbAdapter )
{
dbAdapter.open();
// insert test data and store record count
try
{
dbAdapter.insertSamples( sampleCollection );
}
catch ( Exception e )
{
e.printStackTrace();
fail( "Unexpected exception during sample insertion" );
}
long count = dbAdapter.getRecordCount();
dbAdapter.close();
return count;
}
/**
* Does fill a sample collection with database sample test data
*
* @return a database sample collection
*/
public static final Collection< DatabaseSample > getCollectionWithTestData()
{
Collection< DatabaseSample > sampleCollection =
new Vector< DatabaseSample >();
try
{
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample(
SensorDeviceIdentifier.Accelerometer,
new AccelerometerSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Wifi,
new WifiSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Bluetooth,
new BluetoothSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.GSM,
new GSMSampleData() ) ) );
GPSSampleData sampleData = new GPSSampleData();
sampleData.setLatitude( 77.7 );
sampleData.setLongitude( 12.3 );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.GPS,
sampleData ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Audio,
new FileReferenceSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Twitter,
new TwitterSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample(
SensorDeviceIdentifier.Accelerometer,
TestAccelerometerSampleData.createInitializedAccelerometerSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Wifi,
TestWifiSampleData.createInitializedWifiSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.Bluetooth,
TestBluetoothSampleData.createInitializedBluetoothSampleData() ) ) );
sampleCollection.add( new DatabaseSample(
TestSampleCollection.createSample( SensorDeviceIdentifier.GSM,
TestGSMSampleData.createInitializedGSMSampleData() ) ) );
GeoLocation loc = new GeoLocation();
loc.setLat( Math.random() * 180 );
loc.setLon( Math.random() * 180 );
DatabaseSample databaseSample =
new DatabaseSample( TestSampleCollection.createSample(
SensorDeviceIdentifier.GSM,
TestGSMSampleData.createInitializedGSMSampleData() ) );
databaseSample.location = loc.toXML();
sampleCollection.add( databaseSample );
}
catch ( Exception e )
{
e.printStackTrace();
fail( "Unexpected exception during creation of database samples" );
}
return sampleCollection;
}
/**
* Does create a collection with a specific amount of test database samples
*
* @param count
* the count of samples to create
* @return the created test data
*/
public static Collection< DatabaseSample > createTestData( long count )
{
Collection< DatabaseSample > sc = new Vector< DatabaseSample >();
try
{
for ( long i = 0; i < count; ++i )
{
GeoLocation loc = new GeoLocation();
loc.setLat( Math.random() * 180 );
loc.setLon( Math.random() * 180 );
DatabaseSample databaseSample =
new DatabaseSample( TestSampleCollection.createSample(
SensorDeviceIdentifier.GSM,
TestGSMSampleData.createInitializedGSMSampleData() ) );
databaseSample.location = loc.toXML();
sc.add( databaseSample );
}
}
catch ( Exception e )
{
e.printStackTrace();
fail( "Unexpected exception during creation of database samples" );
}
return sc;
}
}