package com.github.mongobee;
import static com.github.mongobee.changeset.ChangeEntry.CHANGELOG_COLLECTION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.net.UnknownHostException;
import java.util.Collections;
import org.bson.Document;
import org.jongo.Jongo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.github.fakemongo.Fongo;
import com.github.mongobee.changeset.ChangeEntry;
import com.github.mongobee.dao.ChangeEntryDao;
import com.github.mongobee.exception.MongobeeConfigurationException;
import com.github.mongobee.exception.MongobeeException;
import com.github.mongobee.test.changelogs.MongobeeTestResource;
import com.mongodb.DB;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;
@RunWith(MockitoJUnitRunner.class)
public class MongobeeTest {
@InjectMocks
private Mongobee runner = new Mongobee();
@Mock
private ChangeEntryDao dao;
private DB fakeDb;
private MongoDatabase fakeMongoDatabase;
@Before
public void init() throws MongobeeException, UnknownHostException {
fakeDb = new Fongo("testServer").getDB("mongobeetest");
fakeMongoDatabase = new Fongo("testServer").getDatabase("mongobeetest");
when(dao.connectMongoDb(any(MongoClientURI.class), anyString()))
.thenReturn(fakeMongoDatabase);
when(dao.getDb()).thenReturn(fakeDb);
when(dao.getMongoDatabase()).thenReturn(fakeMongoDatabase);
doCallRealMethod().when(dao).save(any(ChangeEntry.class));
runner.setDbName("mongobeetest");
runner.setEnabled(true);
runner.setChangeLogsScanPackage(MongobeeTestResource.class.getPackage().getName());
}
@Test(expected = MongobeeConfigurationException.class)
public void shouldThrowAnExceptionIfNoDbNameSet() throws Exception {
Mongobee runner = new Mongobee(new MongoClientURI("mongodb://localhost:27017/"));
runner.setEnabled(true);
runner.setChangeLogsScanPackage(MongobeeTestResource.class.getPackage().getName());
runner.execute();
}
@Test
public void shouldExecute9ChangeSets() throws Exception {
// given
when(dao.acquireProcessLock()).thenReturn(true);
when(dao.isNewChange(any(ChangeEntry.class))).thenReturn(true);
// when
runner.execute();
// then
verify(dao, times(12)).save(any(ChangeEntry.class)); // 12 changesets saved to dbchangelog
// dbchangelog collection checking
long change1 = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_CHANGEID, "test1")
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(1, change1);
long change2 = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_CHANGEID, "test2")
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(1, change2);
long change3 = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_CHANGEID, "test3")
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(1, change3);
long change4 = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_CHANGEID, "test4")
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(1, change4);
long change5 = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_CHANGEID, "test5")
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(1, change5);
long changeAll = fakeMongoDatabase.getCollection(CHANGELOG_COLLECTION).count(new Document()
.append(ChangeEntry.KEY_AUTHOR, "testuser"));
assertEquals(11, changeAll);
}
@Test
public void shouldPassOverChangeSets() throws Exception {
// given
when(dao.isNewChange(any(ChangeEntry.class))).thenReturn(false);
// when
runner.execute();
// then
verify(dao, times(0)).save(any(ChangeEntry.class)); // no changesets saved to dbchangelog
}
@Test
public void shouldUsePreConfiguredMongoTemplate() throws Exception {
MongoTemplate mt = mock(MongoTemplate.class);
when(mt.getCollectionNames()).thenReturn(Collections.EMPTY_SET);
when(dao.acquireProcessLock()).thenReturn(true);
when(dao.isNewChange(any(ChangeEntry.class))).thenReturn(true);
runner.setMongoTemplate(mt);
runner.afterPropertiesSet();
verify(mt).getCollectionNames();
}
@Test
public void shouldUsePreConfiguredJongo() throws Exception {
Jongo jongo = mock(Jongo.class);
when(dao.acquireProcessLock()).thenReturn(true);
when(jongo.getDatabase()).thenReturn(null);
runner.setJongo(jongo);
runner.afterPropertiesSet();
verify(jongo).getDatabase();
}
@Test
public void shouldExecuteProcessWhenLockAcquired() throws Exception {
// given
when(dao.acquireProcessLock()).thenReturn(true);
// when
runner.execute();
// then
verify(dao, atLeastOnce()).isNewChange(any(ChangeEntry.class));
}
@Test
public void shouldReleaseLockAfterWhenLockAcquired() throws Exception {
// given
when(dao.acquireProcessLock()).thenReturn(true);
// when
runner.execute();
// then
verify(dao).releaseProcessLock();
}
@Test
public void shouldNotExecuteProcessWhenLockNotAcquired() throws Exception {
// given
when(dao.acquireProcessLock()).thenReturn(false);
// when
runner.execute();
// then
verify(dao, never()).isNewChange(any(ChangeEntry.class));
}
@Test
public void shouldReturnExecutionStatusBasedOnDao() throws Exception {
// given
when(dao.isProccessLockHeld()).thenReturn(true);
boolean inProgress = runner.isExecutionInProgress();
// then
assertTrue(inProgress);
}
@SuppressWarnings("unchecked")
@Test
public void shouldReleaseLockWhenExceptionInMigration() throws Exception {
// given
// would be nicer with a mock for the whole execution, but this would mean breaking out to separate class..
// this should be "good enough"
when(dao.acquireProcessLock()).thenReturn(true);
when(dao.isNewChange(any(ChangeEntry.class))).thenThrow(RuntimeException.class);
// when
// have to catch the exception to be able to verify after
try {
runner.execute();
} catch (Exception e) {
// do nothing
}
// then
verify(dao).releaseProcessLock();
}
@After
public void cleanUp() {
runner.setMongoTemplate(null);
runner.setJongo(null);
}
}