package org.molgenis.gavin.job;
import com.google.common.collect.ImmutableMultiset;
import org.mockito.Mock;
import org.molgenis.annotation.cmd.conversion.EffectStructureConverter;
import org.molgenis.data.Entity;
import org.molgenis.data.MolgenisDataException;
import org.molgenis.data.annotation.core.RepositoryAnnotator;
import org.molgenis.data.jobs.Progress;
import org.molgenis.data.meta.model.AttributeFactory;
import org.molgenis.data.meta.model.EntityTypeFactory;
import org.molgenis.data.vcf.model.VcfAttributes;
import org.molgenis.file.FileStore;
import org.molgenis.gavin.job.input.Parser;
import org.molgenis.gavin.job.input.model.LineType;
import org.molgenis.test.data.AbstractMolgenisSpringTest;
import org.molgenis.ui.menu.Menu;
import org.molgenis.ui.menu.MenuReaderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.support.TransactionTemplate;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.io.File;
import java.util.Collections;
import java.util.Iterator;
import static java.io.File.separator;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.molgenis.gavin.controller.GavinController.GAVIN_APP;
import static org.molgenis.gavin.job.input.model.LineType.*;
@ContextConfiguration(classes = { GavinJobTest.Config.class })
public class GavinJobTest extends AbstractMolgenisSpringTest
{
private GavinJob job;
@Autowired
VcfAttributes vcfAttributes;
@Autowired
EntityTypeFactory entityTypeFactory;
@Autowired
AttributeFactory attributeFactory;
@Mock
private Progress progress;
@Mock
private TransactionTemplate transactionTemplate;
@Mock
private Authentication authentication;
@Mock
private FileStore fileStore;
@Mock
private MenuReaderService menuReaderService;
@Mock
private RepositoryAnnotator cadd;
@Mock
private RepositoryAnnotator exac;
@Mock
private RepositoryAnnotator snpeff;
@Mock
private RepositoryAnnotator gavin;
@Mock
private Parser parser;
@Mock
private Menu menu;
@Mock
EffectStructureConverter effectStructureConverter;
@Mock
private File inputFile;
@Mock
private File processedInputFile;
@Mock
private File errorFile;
@Mock
private File caddResult;
@Mock
private File exacResult;
@Mock
private File snpEffResult;
@Mock
private File gavinResult;
@Mock
private AnnotatorRunner annotatorRunner;
@Mock
private GavinJobExecution gavinJobExecution;
@BeforeMethod
public void beforeMethod()
{
initMocks(this);
when(menuReaderService.getMenu()).thenReturn(menu);
when(menu.findMenuItemPath(GAVIN_APP)).thenReturn("/menu/plugins/gavin-app");
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "input.tsv")).thenReturn(inputFile);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "temp-processed-input.vcf"))
.thenReturn(processedInputFile);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "error.txt")).thenReturn(errorFile);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "temp-cadd.vcf")).thenReturn(caddResult);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "temp-exac.vcf")).thenReturn(exacResult);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "temp-snpeff.vcf"))
.thenReturn(snpEffResult);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "gavin-result.vcf"))
.thenReturn(gavinResult);
Iterator<Entity> iterator = Collections.<Entity>emptyList().iterator();
when(cadd.annotate(anyObject(), eq(true))).thenReturn(iterator);
when(exac.annotate(anyObject(), eq(true))).thenReturn(iterator);
when(snpeff.annotate(anyObject(), eq(false))).thenReturn(iterator);
when(gavin.annotate(anyObject(), eq(false))).thenReturn(iterator);
when(gavinJobExecution.getIdentifier()).thenReturn("ABCDE");
when(gavinJobExecution.getInputFileExtension()).thenReturn("tsv");
when(effectStructureConverter.createVcfEntityStructure(anyObject())).thenReturn(iterator);
job = new GavinJob(progress, transactionTemplate, authentication, "ABCDE", fileStore, menuReaderService, cadd,
exac, snpeff, gavin, parser, annotatorRunner, gavinJobExecution);
}
@Test
public void testRunHappyPathVcf() throws Exception
{
final ImmutableMultiset<LineType> lineTypes = ImmutableMultiset.of(COMMENT, COMMENT, VCF, VCF);
when(parser.tryTransform(inputFile, processedInputFile, errorFile)).thenReturn(lineTypes);
job.call(progress);
verify(progress).setProgressMax(5);
verify(progress).progress(0, "Preprocessing input file...");
verify(progress).progress(1, "Annotating with cadd...");
verify(annotatorRunner).runAnnotator(cadd, processedInputFile, caddResult, true);
verify(progress).progress(2, "Annotating with exac...");
verify(annotatorRunner).runAnnotator(exac, caddResult, exacResult, true);
verify(progress).progress(3, "Annotating with snpEff...");
verify(annotatorRunner).runAnnotator(snpeff, exacResult, snpEffResult, false);
verify(progress).progress(4, "Annotating with gavin...");
verify(annotatorRunner).runAnnotator(gavin, snpEffResult, gavinResult, false);
verify(progress).progress(5, "Result is ready for download.");
verify(progress).setResultUrl("/menu/plugins/gavin-app/result/ABCDE");
verify(gavinJobExecution).setLineTypes(lineTypes);
}
@Test
public void testRunHappyPathCadd() throws Exception
{
when(parser.tryTransform(inputFile, processedInputFile, errorFile))
.thenReturn(ImmutableMultiset.of(COMMENT, COMMENT, CADD, CADD));
job.call(progress);
verify(progress).setProgressMax(5);
verify(progress).progress(0, "Preprocessing input file...");
verify(progress)
.status("Parsed input file. Found 4 lines (2 comments, 0 valid VCF, 2 valid CADD, 0 errors, 0 indels without CADD score, 0 skipped)");
verify(progress).progress(1, "File already annotated by cadd, skipping cadd annotation.");
verify(progress).progress(2, "Annotating with exac...");
verify(annotatorRunner).runAnnotator(exac, processedInputFile, exacResult, true);
verify(progress).progress(3, "Annotating with snpEff...");
verify(annotatorRunner).runAnnotator(snpeff, exacResult, snpEffResult, false);
verify(progress).progress(4, "Annotating with gavin...");
verify(annotatorRunner).runAnnotator(gavin, snpEffResult, gavinResult, false);
verify(progress).progress(5, "Result is ready for download.");
verify(progress).setResultUrl("/menu/plugins/gavin-app/result/ABCDE");
}
@Test(expectedExceptions = {
MolgenisDataException.class }, expectedExceptionsMessageRegExp = "Input file contains too many lines\\. Maximum is 100,000\\.")
public void testSkippedThrowsException() throws Exception
{
when(parser.tryTransform(inputFile, processedInputFile, errorFile))
.thenReturn(ImmutableMultiset.of(COMMENT, COMMENT, CADD, VCF, SKIPPED));
job.call(progress);
}
@Test(expectedExceptions = {
MolgenisDataException.class }, expectedExceptionsMessageRegExp = "Not a single valid variant line found\\.")
public void testNoValidLinesThrowsException() throws Exception
{
when(parser.tryTransform(inputFile, processedInputFile, errorFile)).thenReturn(ImmutableMultiset.of());
job.call(progress);
}
@Test(expectedExceptions = {
MolgenisDataException.class }, expectedExceptionsMessageRegExp = "Input file contains mixed line types\\. Please use one type only, either VCF or CADD.")
public void testMixedInputsThrowsException() throws Exception
{
when(parser.tryTransform(inputFile, processedInputFile, errorFile))
.thenReturn(ImmutableMultiset.of(COMMENT, COMMENT, CADD, VCF));
job.call(progress);
}
@Configuration
@ComponentScan({ "org.molgenis.data.vcf.model", "org.molgenis.data.vcf.utils" })
public static class Config
{
}
}