package org.molgenis.gavin.controller;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.molgenis.auth.User;
import org.molgenis.data.DataService;
import org.molgenis.data.annotation.core.EffectBasedAnnotator;
import org.molgenis.data.annotation.core.RepositoryAnnotator;
import org.molgenis.data.annotation.web.CrudRepositoryAnnotator;
import org.molgenis.data.index.meta.IndexPackage;
import org.molgenis.data.jobs.JobExecutionUpdater;
import org.molgenis.file.FileStore;
import org.molgenis.framework.ui.MolgenisPluginRegistry;
import org.molgenis.gavin.job.GavinJob;
import org.molgenis.gavin.job.GavinJobExecution;
import org.molgenis.gavin.job.GavinJobFactory;
import org.molgenis.gavin.job.meta.GavinJobExecutionMetaData;
import org.molgenis.security.user.UserAccountService;
import org.molgenis.test.data.AbstractMolgenisSpringTest;
import org.molgenis.ui.controller.StaticContentService;
import org.molgenis.ui.menu.MenuReaderService;
import org.molgenis.util.ResourceUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.MailSender;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
import org.testng.annotations.Test;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import static java.io.File.separator;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;
@ContextConfiguration(classes = { GavinControllerTest.Config.class, GavinController.class })
public class GavinControllerTest extends AbstractMolgenisSpringTest
{
@Autowired
private GavinController gavinController;
@Autowired
private ExecutorService executorService;
@Autowired
private GavinJobFactory gavinJobFactory;
@Autowired
private FileStore fileStore;
@Autowired
private UserAccountService userAccountService;
@Autowired
GavinJobExecutionMetaData gavinJobExecutionMetaData;
@Test
public void testInitResourcesPresent() throws Exception
{
Model model = new ExtendedModelMap();
when(gavinJobFactory.getAnnotatorsWithMissingResources()).thenReturn(emptyList());
gavinController.init(model);
assertFalse(model.containsAttribute("annotatorsWithMissingResources"));
}
@Test
public void testInitMissingResources() throws Exception
{
Model model = new ExtendedModelMap();
when(gavinJobFactory.getAnnotatorsWithMissingResources()).thenReturn(singletonList("cadd"));
gavinController.init(model);
assertEquals(model.asMap().get("annotatorsWithMissingResources"), singletonList("cadd"));
}
@Test
public void testAnnotateFile() throws Exception
{
MultipartFile vcf = mock(MultipartFile.class);
GavinJob job = mock(GavinJob.class);
File inputFile = mock(File.class);
File parentDir = mock(File.class);
User user = mock(User.class);
when(user.getUsername()).thenReturn("tommy");
// Job Factory sets the Identifier in the JobExecution object.
ArgumentCaptor<GavinJobExecution> captor = ArgumentCaptor.forClass(GavinJobExecution.class);
when(userAccountService.getCurrentUser()).thenReturn(user);
doAnswer(invocation ->
{
Object[] args = invocation.getArguments();
((GavinJobExecution) args[0]).setIdentifier("ABCDE");
return job;
}).when(gavinJobFactory).createJob(captor.capture());
when(inputFile.getParentFile()).thenReturn(parentDir);
when(vcf.getOriginalFilename()).thenReturn(".vcf");
assertEquals(gavinController.annotateFile(vcf, "annotate-file"),
ResponseEntity.created(URI.create("/plugin/gavin-app/job/ABCDE")).body("/plugin/gavin-app/job/ABCDE"));
verify(fileStore).createDirectory("gavin-app");
verify(fileStore).createDirectory("gavin-app" + separator + "ABCDE");
verify(fileStore).writeToFile(Mockito.any(InputStream.class),
Mockito.eq("gavin-app" + separator + "ABCDE" + separator + "input.tsv"));
verify(executorService).submit(job);
GavinJobExecution jobExecution = captor.getValue();
assertEquals(jobExecution.getFilename(), "annotate-file");
assertEquals(jobExecution.getUser(), "tommy");
}
@Test
public void testResult() throws Exception
{
GavinJobExecution gavinJobExecution = mock(GavinJobExecution.class);
File resultFile = File
.createTempFile("gavin", ".vcf", new File(ResourceUtils.getFile(getClass(), "/").getPath()));
resultFile.deleteOnExit();
when(gavinJobExecution.getFilename()).thenReturn("annotate-file");
when(gavinJobFactory.findGavinJobExecution("ABCDE")).thenReturn(gavinJobExecution);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "gavin-result.vcf"))
.thenReturn(resultFile);
HttpServletResponse response = mock(HttpServletResponse.class);
assertEquals(gavinController.download(response, "ABCDE"), new FileSystemResource(resultFile));
verify(response).setHeader("Content-Disposition", "inline; filename=\"annotate-file-gavin.vcf\"");
}
@Test(expectedExceptions = FileNotFoundException.class, expectedExceptionsMessageRegExp = "No result file found for this job\\. Results are removed every night\\.")
public void testResultNotFound() throws Exception
{
GavinJobExecution gavinJobExecution = mock(GavinJobExecution.class);
File file = mock(File.class);
when(gavinJobExecution.getFilename()).thenReturn("annotate-file-gavin.vcf");
when(gavinJobFactory.findGavinJobExecution("ABCDE")).thenReturn(gavinJobExecution);
when(fileStore.getFile("gavin-app" + separator + "ABCDE" + separator + "gavin-result.vcf")).thenReturn(file);
when(file.exists()).thenReturn(false);
gavinController.download(mock(HttpServletResponse.class), "ABCDE");
}
@Test
public void testCleanUp() throws Exception
{
File gavinAppDir = Mockito.mock(File.class);
File oldJobDir = Mockito.mock(File.class);
File newJobDir = Mockito.mock(File.class);
when(fileStore.getFile("gavin-app")).thenReturn(gavinAppDir);
when(newJobDir.lastModified()).thenReturn(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(23));
when(newJobDir.isDirectory()).thenReturn(true);
when(oldJobDir.lastModified()).thenReturn(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(24) - 1000);
when(oldJobDir.isDirectory()).thenReturn(true);
ArgumentCaptor<FileFilter> fileFilterCaptor = ArgumentCaptor.forClass(FileFilter.class);
when(gavinAppDir.listFiles(fileFilterCaptor.capture())).thenReturn(new File[] { oldJobDir });
when(oldJobDir.getName()).thenReturn("ASDFASDFASDF");
gavinController.cleanUp();
verify(fileStore).deleteDirectory("gavin-app" + File.separator + "ASDFASDFASDF");
assertTrue(fileFilterCaptor.getValue().accept(oldJobDir),
"cleanUp should remove files that are more than 24 hours old");
assertFalse(fileFilterCaptor.getValue().accept(newJobDir),
"cleanUp should leave files that are less than 24 hours old");
}
@Configuration
@ComponentScan({ "org.molgenis.gavin.job.meta", "org.molgenis.data.jobs.model" })
public static class Config
{
@Bean
IndexPackage indexPackage()
{
return mock(IndexPackage.class);
}
@Bean
ExecutorService gavinExecutors()
{
return mock(ExecutorService.class);
}
@Bean
GavinJobFactory gavinJobFactory()
{
return mock(GavinJobFactory.class);
}
@Bean
UserAccountService userAccountService()
{
return mock(UserAccountService.class);
}
@Bean
MolgenisPluginRegistry pluginRegistry()
{
return mock(MolgenisPluginRegistry.class);
}
@Bean
PlatformTransactionManager platformTransactionManager()
{
return mock(PlatformTransactionManager.class);
}
@Bean
CrudRepositoryAnnotator crudRepositoryAnnotator()
{
return mock(CrudRepositoryAnnotator.class);
}
@Bean
DataService dataService()
{
return mock(DataService.class);
}
@Bean
PlatformTransactionManager transactionManager()
{
return mock(PlatformTransactionManager.class);
}
@Bean
UserDetailsService userDetailsService()
{
return mock(UserDetailsService.class);
}
@Bean
JobExecutionUpdater jobExecutionUpdater()
{
return mock(JobExecutionUpdater.class);
}
@Bean
MailSender mailSender()
{
return mock(MailSender.class);
}
@Bean
FileStore fileStore()
{
return mock(FileStore.class);
}
@Bean
RepositoryAnnotator cadd()
{
return mock(RepositoryAnnotator.class);
}
@Bean
RepositoryAnnotator exac()
{
return mock(RepositoryAnnotator.class);
}
@Bean
RepositoryAnnotator snpEff()
{
return mock(RepositoryAnnotator.class);
}
@Bean
EffectBasedAnnotator gavin()
{
return mock(EffectBasedAnnotator.class);
}
@Bean
StaticContentService staticContentService()
{
return mock(StaticContentService.class);
}
@Bean
MenuReaderService menuReaderService()
{
return mock(MenuReaderService.class);
}
}
}