Skip to content

Commit 4ea5b06

Browse files
committed
Add initial unit test to exercise ClusterBootstrap and remote sequence job
1 parent dd25011 commit 4ea5b06

File tree

5 files changed

+299
-2
lines changed

5 files changed

+299
-2
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
5+
6+
<bean id="pipelineJobService" class="org.labkey.pipeline.api.PipelineJobServiceImpl">
7+
<property name="appProperties">
8+
<bean class="org.labkey.pipeline.api.properties.ApplicationPropertiesImpl">
9+
<property name="toolsDirectory" value="@@SEQUENCEANALYSIS_TOOLS@@" />
10+
</bean>
11+
</property>
12+
<property name="remoteServerProperties">
13+
<bean class="org.labkey.pipeline.api.properties.RemoteServerPropertiesImpl">
14+
<property name="location" value="MockCluster"/>
15+
</bean>
16+
</property>
17+
<property name="statusWriter">
18+
<bean class="org.labkey.pipeline.cluster.NoOpPipelineStatusWriter"/>
19+
</property>
20+
<property name="jobStore">
21+
<bean class="org.labkey.pipeline.api.PipelineJobMarshaller"/>
22+
</property>
23+
<property name="workDirFactory">
24+
<bean class="org.labkey.pipeline.api.WorkDirectoryRemote$Factory">
25+
<property name="tempDirectory" value="@@WORK_DIR@@"/>
26+
</bean>
27+
</property>
28+
</bean>
29+
</beans>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
5+
6+
<bean class="org.labkey.api.pipeline.TaskPipelineRegistrar">
7+
<property name="factoryImpls">
8+
<list>
9+
<bean class="org.labkey.sequenceanalysis.pipeline.SequenceAlignmentTask$Factory">
10+
<property name="location" value="MockCluster" />
11+
</bean>
12+
<bean class="org.labkey.sequenceanalysis.pipeline.SequenceNormalizationTask$Factory">
13+
<property name="location" value="MockCluster" />
14+
</bean>
15+
<bean class="org.labkey.sequenceanalysis.pipeline.PrepareAlignerIndexesTask$Factory">
16+
<property name="location" value="MockCluster" />
17+
</bean>
18+
<bean class="org.labkey.sequenceanalysis.pipeline.AlignmentAnalysisRemoteWorkTask$Factory">
19+
<property name="location" value="MockCluster" />
20+
</bean>
21+
<bean class="org.labkey.sequenceanalysis.pipeline.SequenceOutputHandlerRemoteTask$Factory">
22+
<property name="location" value="MockCluster" />
23+
</bean>
24+
<bean class="org.labkey.sequenceanalysis.pipeline.SequenceReadsetHandlerRemoteTask$Factory">
25+
<property name="location" value="MockCluster" />
26+
</bean>
27+
<bean class="org.labkey.sequenceanalysis.pipeline.AlignmentNormalizationTask$Factory">
28+
<property name="location" value="MockCluster" />
29+
</bean>
30+
</list>
31+
</property>
32+
</bean>
33+
</beans>

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ public Set<Class> getIntegrationTests()
423423
//SequenceIntegrationTests.SequenceAnalysisPipelineTestCase3.class,
424424
SequenceIntegrationTests.SequenceAnalysisPipelineTestCase1.class,
425425
SequenceIntegrationTests.SequenceAnalysisPipelineTestCase2.class,
426-
OutputIntegrationTests.VariantProcessingTest.class
426+
OutputIntegrationTests.VariantProcessingTest.class,
427+
SequenceRemoteIntegrationTests.class
427428
));
428429

429430
return testClasses;

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3137,7 +3137,7 @@ else if (tsNt.getRowCount() > 1)
31373137

31383138
public static void ensureSivMac239Sequence(Container c, Logger log) throws IOException
31393139
{
3140-
TableInfo ti = QueryService.get().getUserSchema(TestContext.get().getUser(), c, SequenceAnalysisSchema.SCHEMA_NAME).getTable(SequenceAnalysisSchema.TABLE_REF_NT_SEQUENCES);
3140+
TableInfo ti = QueryService.get().getUserSchema(TestContext.get().getUser(), c, SequenceAnalysisSchema.SCHEMA_NAME).getTable(SequenceAnalysisSchema.TABLE_REF_NT_SEQUENCES, null);
31413141
SimpleFilter filter = new SimpleFilter(FieldKey.fromString("name"), "SIVmac239_Test");
31423142
//note: dont use container filter so this could include /shared
31433143
//filter.addCondition(FieldKey.fromString("container"), c.getId());
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
package org.labkey.sequenceanalysis;
2+
3+
import org.apache.commons.io.FileUtils;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.apache.commons.lang3.SystemUtils;
6+
import org.jetbrains.annotations.Nullable;
7+
import org.json.JSONObject;
8+
import org.junit.AfterClass;
9+
import org.junit.Assert;
10+
import org.junit.Before;
11+
import org.junit.BeforeClass;
12+
import org.junit.Test;
13+
import org.labkey.api.module.ModuleLoader;
14+
import org.labkey.api.pipeline.PipelineJobService;
15+
import org.labkey.api.pipeline.TaskId;
16+
import org.labkey.api.pipeline.WorkDirectory;
17+
import org.labkey.api.reader.Readers;
18+
import org.labkey.api.writer.PrintWriters;
19+
import org.labkey.sequenceanalysis.pipeline.AlignmentInitTask;
20+
import org.labkey.sequenceanalysis.pipeline.PrepareAlignerIndexesTask;
21+
import org.labkey.sequenceanalysis.pipeline.SequenceAlignmentJob;
22+
23+
import java.io.BufferedReader;
24+
import java.io.File;
25+
import java.io.IOException;
26+
import java.io.PrintWriter;
27+
import java.io.Reader;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
31+
import static org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService.SEQUENCE_TOOLS_PARAM;
32+
33+
public class SequenceRemoteIntegrationTests extends SequenceIntegrationTests.AbstractAnalysisPipelineTestCase
34+
{
35+
private static final String PROJECT_NAME = "SequenceRemoteIntegrationTests";
36+
37+
@Before
38+
@Override
39+
public void setUp() throws Exception
40+
{
41+
super.setUp();
42+
}
43+
44+
@BeforeClass
45+
public static void initialSetUp() throws Exception
46+
{
47+
doInitialSetUp(PROJECT_NAME);
48+
}
49+
50+
private File setupConfigDir(File outDir) throws IOException
51+
{
52+
File baseDir = new File(outDir, "config");
53+
if (baseDir.exists())
54+
{
55+
FileUtils.deleteDirectory(baseDir);
56+
}
57+
58+
baseDir.mkdirs();
59+
60+
File source = new File(_sampleData, "remotePipeline");
61+
FileUtils.copyFile(new File(source, "sequenceanalysisConfig.xml"), new File(baseDir, "sequenceanalysisConfig.xml"));
62+
63+
try (PrintWriter writer = PrintWriters.getPrintWriter(new File(baseDir, "pipelineConfig.xml")); BufferedReader reader = Readers.getReader(new File(source, "pipelineConfig.xml")))
64+
{
65+
String line;
66+
while ((line = reader.readLine()) != null)
67+
{
68+
if (line.contains("@@SEQUENCEANALYSIS_TOOLS@@"))
69+
{
70+
String path = PipelineJobService.get().getConfigProperties().getSoftwarePackagePath(SEQUENCE_TOOLS_PARAM);
71+
if (StringUtils.trimToNull(path) == null)
72+
{
73+
path = PipelineJobService.get().getAppProperties().getToolsDirectory();
74+
}
75+
76+
path = path.replaceAll("\\\\", "/");
77+
line = line.replaceAll("@@SEQUENCEANALYSIS_TOOLS@@", path);
78+
}
79+
else if (line.contains("@@WORK_DIR@@"))
80+
{
81+
line = line.replaceAll("@@WORK_DIR@@", outDir.getPath().replaceAll("\\\\", "/"));
82+
}
83+
84+
writer.println(line);
85+
}
86+
}
87+
88+
return baseDir;
89+
}
90+
91+
@AfterClass
92+
public static void cleanup()
93+
{
94+
doCleanup(PROJECT_NAME);
95+
}
96+
97+
@Override
98+
protected String getProjectName()
99+
{
100+
return PROJECT_NAME;
101+
}
102+
103+
@Test
104+
public void BasicRemoteJob() throws Exception
105+
{
106+
File outDir = new File(_pipelineRoot, "clusterBootstrap");
107+
if (outDir.exists())
108+
{
109+
FileUtils.deleteDirectory(outDir);
110+
}
111+
112+
outDir.mkdirs();
113+
114+
executeJobRemote(outDir, null);
115+
116+
try
117+
{
118+
// Not ideal. This job runs extremely quickly. When the folder cleanup happens, it seems that some process is holding on
119+
// to the sequence file created in setup, so delete fails on that file. Search should be disabled, but there might be another FileWatcher.
120+
// This delay is designed to let that thread catch up.
121+
Thread.sleep(10000);
122+
}
123+
catch (InterruptedException e)
124+
{
125+
throw new RuntimeException(e.getMessage(), e);
126+
}
127+
}
128+
129+
@Test
130+
public void RunBwaRemote() throws Exception
131+
{
132+
if (!isExternalPipelineEnabled())
133+
return;
134+
135+
String jobName = "TestBWAMem_" + System.currentTimeMillis();
136+
JSONObject config = substituteParams(new File(_sampleData, ALIGNMENT_JOB), jobName);
137+
config.put("alignment", "BWA-Mem");
138+
appendSamplesForAlignment(config, _readsets);
139+
140+
SequenceAlignmentJob job = SequenceAlignmentJob.createForReadsets(_project, _context.getUser(), "RemoteJob1", "Test of remote pipeline", config, config.getJSONArray("readsetIds"), false).get(0);
141+
File outDir = new File(_pipelineRoot, "remoteBwa");
142+
if (outDir.exists())
143+
{
144+
FileUtils.deleteDirectory(outDir);
145+
}
146+
147+
outDir.mkdirs();
148+
job.getLogFile().getParentFile().mkdirs();
149+
150+
_readsets.forEach(rs -> job.getSequenceSupport().cacheReadset(rs));
151+
152+
//Force the init task to run
153+
job.setActiveTaskId(new TaskId(AlignmentInitTask.class));
154+
AlignmentInitTask task = (AlignmentInitTask)job.getActiveTaskFactory().createTask(job);
155+
WorkDirectory wd = job.getActiveTaskFactory().createWorkDirectory(job.getJobGUID(), job, job.getLogger());
156+
task.setWorkDirectory(wd);
157+
task.run();
158+
159+
//Now move to remote tasks
160+
job.setActiveTaskId(new TaskId(PrepareAlignerIndexesTask.class));
161+
162+
File jobFile = new File(outDir, "bwaRemote.job.json.txt");
163+
job.writeToFile(jobFile);
164+
165+
executeJobRemote(outDir, jobFile);
166+
167+
//TODO: check outputs
168+
Assert.assertEquals(1, 1);
169+
}
170+
171+
protected void executeJobRemote(File workDir, @Nullable File jobJson) throws IOException
172+
{
173+
List<String> args = new ArrayList<>();
174+
args.add(System.getProperty("java.home") + "/bin/java" + (SystemUtils.IS_OS_WINDOWS ? ".exe" : ""));
175+
176+
File labkeyBootstrap = new File(System.getProperty("catalina.home"), "lib/labkeyBootstrap.jar");
177+
args.add("-cp");
178+
args.add(labkeyBootstrap.getPath());
179+
args.add("org.labkey.bootstrap.ClusterBootstrap");
180+
181+
File webappDir = new File(ModuleLoader.getServletContext().getRealPath(""));
182+
args.add("-modulesdir=" + new File(webappDir.getParentFile(), "modules").getPath());
183+
args.add("-webappdir=" + webappDir.getPath());
184+
185+
File configDir = setupConfigDir(workDir);
186+
args.add("-configdir=" + configDir.getPath());
187+
188+
if (jobJson != null)
189+
{
190+
args.add(jobJson.toURI().toString());
191+
}
192+
193+
ProcessBuilder pb = new ProcessBuilder(args);
194+
pb.directory(workDir);
195+
196+
Process proc;
197+
try
198+
{
199+
pb.redirectErrorStream(true);
200+
proc = pb.start();
201+
File logFile = new File(workDir, "clusterBootstrap.txt");
202+
try (BufferedReader procReader = Readers.getReader(proc.getInputStream());PrintWriter writer = PrintWriters.getPrintWriter(logFile))
203+
{
204+
String line;
205+
while ((line = procReader.readLine()) != null)
206+
{
207+
writer.println(line);
208+
}
209+
}
210+
211+
proc.waitFor();
212+
213+
if (proc.exitValue() != 0)
214+
{
215+
try (BufferedReader reader = Readers.getReader(logFile))
216+
{
217+
_log.error("Output from ClusterBootstrap:");
218+
String line;
219+
while ((line = reader.readLine()) != null)
220+
{
221+
_log.error(line);
222+
}
223+
}
224+
}
225+
226+
Assert.assertEquals("Non-zero exit from ClusterBootstrap", 0, proc.exitValue());
227+
}
228+
catch (InterruptedException | IOException e)
229+
{
230+
throw new RuntimeException(e);
231+
}
232+
}
233+
234+
}

0 commit comments

Comments
 (0)