package by.istin.android.xcore.test.db;
import android.app.Application;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.test.ApplicationTestCase;
import android.util.Log;
import by.istin.android.xcore.ContextHolder;
import by.istin.android.xcore.db.impl.sqlite.SQLiteSupport;
import by.istin.android.xcore.provider.impl.DBContentProviderSupport;
import by.istin.android.xcore.source.DataSourceRequest;
import by.istin.android.xcore.model.BigTestEntity;
import by.istin.android.xcore.model.BigTestSubEntity;
import by.istin.android.xcore.utils.CursorUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class TestSQLiteSupport extends ApplicationTestCase<Application> {
private String TEST_ENTITY_CLASS;
private String SUB_ENTITY_CLASS;
public static final int THREAD_COUNT = 20;
private DataSourceRequest DATA_SOURCE_REQUEST;
private SQLiteSupport mSQLiteSupport;
private DBContentProviderSupport dbContentProviderSupport;
public TestSQLiteSupport() {
super(Application.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
createApplication();
mSQLiteSupport = new SQLiteSupport();
mSQLiteSupport.create(getApplication(), new Class[]{BigTestEntity.class, BigTestSubEntity.class});
TEST_ENTITY_CLASS = BigTestEntity.class.getCanonicalName();
SUB_ENTITY_CLASS = BigTestSubEntity.class.getCanonicalName();
DATA_SOURCE_REQUEST = new DataSourceRequest("http://anyurl.com/api");
dbContentProviderSupport = new DBContentProviderSupport(getApplication(), mSQLiteSupport, new Class<?>[]{BigTestEntity.class, BigTestSubEntity.class});
ContextHolder.getInstance().setContext(getApplication());
}
public void testInsert() throws Exception {
createAndClearTables();
insertOneEntity();
checkResults(1);
}
public void testBatch() throws Exception {
createAndClearTables();
ArrayList<ContentProviderOperation> batchInsert = applyInsertBatch();
checkResults(MockStorage.SIZE);
ArrayList<ContentProviderOperation> deleteAllBatchOperation = applyDeleteBatch();
checkResults(0);
ArrayList<ContentProviderOperation> all = new ArrayList<ContentProviderOperation>();
all.addAll(batchInsert);
all.addAll(deleteAllBatchOperation);
dbContentProviderSupport.applyBatch(all);
checkResults(0);
}
private ArrayList<ContentProviderOperation> applyDeleteBatch() throws OperationApplicationException {
ArrayList<ContentProviderOperation> deleteAllBatchOperation = getDeleteAllBatchOperation();
dbContentProviderSupport.applyBatch(deleteAllBatchOperation);
return deleteAllBatchOperation;
}
private ArrayList<ContentProviderOperation> applyInsertBatch() throws OperationApplicationException {
ArrayList<ContentProviderOperation> batchInsert = getBatchInsert();
dbContentProviderSupport.applyBatch(batchInsert);
return batchInsert;
}
private void insertOneEntity() {
ContentValues contentValues = MockStorage.generateSingleEntity(0);
mSQLiteSupport.updateOrInsert(DATA_SOURCE_REQUEST, TEST_ENTITY_CLASS, contentValues);
}
private ArrayList<ContentProviderOperation> getBatchInsert() {
ContentValues[] contentValueses = MockStorage.generateArray();
return DBContentProviderSupport.getContentProviderOperations(DATA_SOURCE_REQUEST, BigTestEntity.class, contentValueses);
}
private ArrayList<ContentProviderOperation> getDeleteAllBatchOperation() {
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
operations.add(DBContentProviderSupport.getDeleteOperation(DATA_SOURCE_REQUEST, BigTestEntity.class));
operations.add(DBContentProviderSupport.getDeleteOperation(DATA_SOURCE_REQUEST, BigTestSubEntity.class));
return operations;
}
public void testDelete() throws Exception {
testBulkInsert();
deleteAll();
checkResults(0);
}
private void deleteAll() {
mSQLiteSupport.delete(TEST_ENTITY_CLASS, null, null);
mSQLiteSupport.delete(SUB_ENTITY_CLASS, null, null);
}
public void testDeleteWithCondition() throws Exception {
testBulkInsert();
deleteWithCondition();
checkResults(MockStorage.SIZE-1);
}
private void deleteWithCondition() {
mSQLiteSupport.delete(TEST_ENTITY_CLASS, BigTestEntity.ID + "= ?", new String[]{"0"});
mSQLiteSupport.delete(SUB_ENTITY_CLASS, BigTestSubEntity.ID + "= ?", new String[]{"0"});
}
public void testBulkInsert() throws Exception {
createAndClearTables();
bulkInsertTestEntity();
checkResults(MockStorage.SIZE);
}
private void bulkInsertTestEntity() {
ContentValues[] contentValues = MockStorage.generateArray();
mSQLiteSupport.updateOrInsert(DATA_SOURCE_REQUEST, TEST_ENTITY_CLASS, contentValues);
}
private void checkResults(int count) {
Cursor cursor = querySubEntity();
if (count == 0) {
assertTrue(CursorUtils.isEmpty(cursor));
} else {
assertEquals(count, cursor.getCount());
}
CursorUtils.close(cursor);
cursor = queryTestEntity();
if (count == 0) {
assertTrue(CursorUtils.isEmpty(cursor));
} else {
assertEquals(count, cursor.getCount());
}
CursorUtils.close(cursor);
}
private Cursor querySubEntity() {
return mSQLiteSupport.query(SUB_ENTITY_CLASS, new String[]{BigTestSubEntity.ID}, null, null, null, null, null, null);
}
private Cursor queryTestEntity() {
return mSQLiteSupport.query(TEST_ENTITY_CLASS, new String[]{BigTestEntity.ID}, null, null, null, null, null, null);
}
private void createAndClearTables() {
mSQLiteSupport.delete(SUB_ENTITY_CLASS, null, null);
mSQLiteSupport.delete(TEST_ENTITY_CLASS, null, null);
}
public void testThreadSafe() throws Exception {
final CountDownLatch latch = new CountDownLatch(THREAD_COUNT*12);
//12 operations
List<Runnable> operations = new ArrayList<Runnable>();
operations.add(new Runnable() {
@Override
public void run() {
bulkInsertTestEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
insertOneEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
deleteAll();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
deleteWithCondition();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
querySubEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
queryTestEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
querySubEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
queryTestEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
querySubEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
queryTestEntity();
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
try {
applyDeleteBatch();
} catch (OperationApplicationException e) {
throw new IllegalStateException(e);
}
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
operations.add(new Runnable() {
@Override
public void run() {
try {
applyInsertBatch();
} catch (OperationApplicationException e) {
throw new IllegalStateException(e);
}
latch.countDown();
Log.d("thread_safe", "thread count " + latch.getCount());
}
});
int size = operations.size();
for (int i = 0; i < THREAD_COUNT*size; i++) {
final int threadNumber = i;
Runnable runner = operations.get(i % size);
new Thread(runner, "TestThread"+i).start();
}
/* all threads are waiting on the latch. */
latch.await(); // release the latch
// all threads are now running concurrently.
}
}