/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.broad.igv.plugin.mongocollab;
import com.mongodb.*;
import org.apache.log4j.Logger;
import org.broad.igv.AbstractHeadlessTest;
import org.broad.igv.feature.BasicFeature;
import org.broad.igv.util.FileUtils;
import org.broad.igv.util.RuntimeUtils;
import org.broad.igv.util.TestUtils;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import java.awt.*;
import java.io.*;
import static org.junit.Assert.*;
/**
* Tests of our integration with MongoDB for collaboration/annotation
* Starts MongoDB on a separate process, host machine must have Mongo and
* test runner must be pointed to it by {@link #MONGO_EXEC_KEY}
* @author jacob
* @date 2013-Sep-10
*/
public class MongoCollabPluginTest extends AbstractHeadlessTest {
private static Logger log = Logger.getLogger(MongoCollabPluginTest.class);
private static String testFileSpecPath = TestUtils.DATA_DIR + "localMongo.db.spec";
private static Thread mongoProc;
private static String MONGO_EXEC_KEY = "MONGO_EXEC_PATH";
/**
* See build.xml for default value
*/
private static String MONGO_EXEC_PATH;
@BeforeClass
public static void setUpClass() throws Exception{
AbstractHeadlessTest.setUpClass();
MONGO_EXEC_PATH = System.getProperty(MONGO_EXEC_KEY, MONGO_EXEC_PATH);
log.info("Mongo exec path: " + MONGO_EXEC_PATH);
Assume.assumeTrue(MONGO_EXEC_PATH != null && MONGO_EXEC_PATH.length() > 0);
startTestMongo();
assumeTestDBRunning();
emptyTestCollection();
}
@AfterClass
public static void tearDownClass() throws Exception{
AbstractHeadlessTest.tearDownClass();
try{
emptyTestCollection();
}catch(Exception e){
log.error(e.getMessage(), e);
}
try {
stopTestMongo();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
@Test
public void testReadSpec() throws Exception{
MongoCollabPlugin.Locator locator = getTestLocator();
assertEquals("localhost", locator.host);
assertEquals(27017, locator.port);
}
@Test
public void testGetCollection() throws Exception{
MongoCollabPlugin.Locator locator = assumeTestDBRunning();
DBCollection collection = MongoCollabPlugin.getCollection(locator);
assertNotNull(collection);
}
@Test
public void testInsertFeature() throws Exception{
MongoCollabPlugin.Locator locator = assumeTestDBRunning();
BasicFeature feat = new BasicFeature("chromo", 50, 100);
//Set name/desc which look like colors, to make sure color parsing isn't activated
feat.setColor(Color.magenta);
feat.setName("0,1,2");
feat.setDescription("mydescription,is,here");
DBFeature dbFeat = DBFeature.create(feat);
assertNull(dbFeat.get_id());
DBCollection coll = MongoCollabPlugin.getCollection(locator);
coll.setObjectClass(DBFeature.class);
String err = MongoCollabPlugin.saveFeature(coll, dbFeat);
assertNull(err);
assertNotNull(dbFeat.get_id());
DBFeature retrievedFeat = (DBFeature) coll.find(new BasicDBObject("_id", dbFeat.get_id())).next();
TestUtils.assertFeaturesEqual(dbFeat, retrievedFeat);
assertEquals(dbFeat.getColor(), retrievedFeat.getColor());
assertEquals(dbFeat.getName(), retrievedFeat.getName());
assertEquals(dbFeat.getDescription(), retrievedFeat.getDescription());
}
@Test
public void testInsertFeatures() throws Exception{
DBCollection collection = emptyTestCollection();
int inserted = MongoCollabPlugin.insertFeaturesFromFile(collection, TestUtils.DATA_DIR + "bed/test.bed");
assertEquals(inserted, collection.count());
assertTrue(inserted > 0);
}
/**
* Assumes that test DB is running, return Locator (for convenience)
* if it is.
* @return
* @throws Exception
*/
public static MongoCollabPlugin.Locator assumeTestDBRunning() throws Exception{
MongoCollabPlugin.Locator locator = getTestLocator();
Assume.assumeTrue(canAccessDB(locator));
return locator;
}
public static DBCollection emptyTestCollection() throws Exception{
DBCollection collection = MongoCollabPlugin.getCollection(getTestLocator());
collection.dropIndexes();
collection.drop();
return collection;
}
public static MongoCollabPlugin.Locator getTestLocator() throws IOException{
try {
return new MongoCollabPlugin.Locator(testFileSpecPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
public static boolean canAccessDB(MongoCollabPlugin.Locator locator){
try {
Mongo mongo = MongoCollabPlugin.getMongo(locator.host, locator.port);
return mongo.getDatabaseNames() != null;
} catch (Exception e) {
return false;
}
}
static void startTestMongo() throws Exception{
String mongoExecPath = MONGO_EXEC_PATH;
int port = getTestLocator().port;
String dbRelPath = TestUtils.DATA_DIR + "mongodbtmp";
final File dbDir = new File(dbRelPath);
String dbAbsPath = dbDir.getAbsolutePath();
if(!dbDir.exists()){
dbDir.mkdirs();
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
FileUtils.deleteDir(dbDir);
}
});
}
final String[] commands = new String[]{mongoExecPath, "--port", "" + port, "--dbpath", dbAbsPath};
Thread runnable = new Thread(){
private Process proc;
@Override
public void run() {
try {
proc = RuntimeUtils.startExternalProcess(commands, null, null);
InputStream is = proc.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line = br.readLine()) != null){
log.debug(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void interrupt() {
if(this.proc != null){
this.proc.destroy();
}
super.interrupt();
}
};
runnable.start();
mongoProc = runnable;
//Need to wait for startup
Thread.sleep(5000);
}
// @Test
// public void testShutdown() throws Exception{
// assertTrue(canAccessDB(getTestLocator()));
// assertFalse(stopTestMongo());
// }
/**
* Stop the test Mongo instance
* @return state of server when done. False = stopped, true = running
* @throws IOException
*/
static boolean stopTestMongo() throws Exception{
MongoCollabPlugin.Locator testLocator = getTestLocator();
Mongo mongo = MongoCollabPlugin.getMongo(testLocator.host, testLocator.port);
DB db = mongo.getDB("admin");
//This actually works (from localhost only), but the java driver throws an error for some reason
try{
CommandResult command = db.command( new BasicDBObject( "shutdown", 1 ) );
}catch(Exception e){
}
Thread.sleep(5000);
if(mongoProc != null && mongoProc.isAlive()){
mongoProc.interrupt();
mongoProc.stop();
}
return canAccessDB(testLocator);
}
}