JAL-1189 JAL-3130 patch broken tests
[jalview.git] / test / jalview / bin / CommandLineOperations.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.bin;
22
23 import jalview.gui.JvOptionPane;
24
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.util.ArrayList;
30
31 import org.testng.Assert;
32 import org.testng.FileAssert;
33 import org.testng.annotations.BeforeClass;
34 import org.testng.annotations.BeforeTest;
35 import org.testng.annotations.DataProvider;
36 import org.testng.annotations.Test;
37
38 import io.github.classgraph.ClassGraph;
39 import io.github.classgraph.ModuleRef;
40 import io.github.classgraph.ScanResult;
41
42 public class CommandLineOperations
43 {
44
45   @BeforeClass(alwaysRun = true)
46   public void setUpJvOptionPane()
47   {
48     JvOptionPane.setInteractiveMode(false);
49     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
50   }
51
52   private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed
53                                                 // on
54                                                 // full test run than on
55                                                 // individual tests
56
57   private static final int SETUP_TIMEOUT = 9000;
58
59   private static final int MINFILESIZE_SMALL = 2096;
60
61   private static final int MINFILESIZE_BIG = 4096;
62
63   private ArrayList<String> successfulCMDs = new ArrayList<>();
64
65   /***
66    * from
67    * http://stackoverflow.com/questions/808276/how-to-add-a-timeout-value-when
68    * -using-javas-runtime-exec
69    * 
70    * @author jimp
71    * 
72    */
73   private static class Worker extends Thread
74   {
75     private final Process process;
76
77     private BufferedReader outputReader;
78
79     private BufferedReader errorReader;
80
81     private Integer exit;
82
83     private Worker(Process process)
84     {
85       this.process = process;
86     }
87
88     @Override
89     public void run()
90     {
91       try
92       {
93         exit = process.waitFor();
94       } catch (InterruptedException ignore)
95       {
96         return;
97       }
98     }
99
100     public BufferedReader getOutputReader()
101     {
102       return outputReader;
103     }
104
105     public void setOutputReader(BufferedReader outputReader)
106     {
107       this.outputReader = outputReader;
108     }
109
110     public BufferedReader getErrorReader()
111     {
112       return errorReader;
113     }
114
115     public void setErrorReader(BufferedReader errorReader)
116     {
117       this.errorReader = errorReader;
118     }
119   }
120
121   private static ClassGraph scanner = null;
122
123   private static String classpath = null;
124
125   private static String modules = null;
126
127   public synchronized static String getClassPath()
128   {
129     if (scanner == null)
130     {
131       scanner = new ClassGraph();
132       ScanResult scan = scanner.scan();
133       classpath = scan.getClasspath();
134       modules = "";
135       for (ModuleRef mr : scan.getModules())
136       {
137         modules.concat(mr.getName());
138       }
139     }
140     while (classpath == null)
141     {
142       try
143       {
144         Thread.sleep(10);
145       } catch (InterruptedException x)
146       {
147
148       }
149     }
150     return classpath;
151   }
152
153   private Worker getJalviewDesktopRunner(boolean withAwt, String cmd,
154           int timeout)
155   {
156     // Note: JAL-3065 - don't include quotes for lib/* because the arguments are
157     // not expanded by the shell
158     String classpath = getClassPath();
159     String _cmd = "java " + (withAwt ? "-Djava.awt.headless=true" : "")
160             + " -classpath " + classpath
161             + (modules.length() > 2 ? "--add-modules=\"" + modules + "\""
162                     : "")
163             + " jalview.bin.Jalview ";
164     Process ls2_proc = null;
165     Worker worker = null;
166     try
167     {
168       ls2_proc = Runtime.getRuntime().exec(_cmd + cmd);
169     } catch (Throwable e1)
170     {
171       e1.printStackTrace();
172     }
173     if (ls2_proc != null)
174     {
175       BufferedReader outputReader = new BufferedReader(
176               new InputStreamReader(ls2_proc.getInputStream()));
177       BufferedReader errorReader = new BufferedReader(
178               new InputStreamReader(ls2_proc.getErrorStream()));
179       worker = new Worker(ls2_proc);
180       worker.start();
181       try
182       {
183         worker.join(timeout);
184       } catch (InterruptedException e)
185       {
186         System.err.println("Thread interrupted");
187       }
188       worker.setOutputReader(outputReader);
189       worker.setErrorReader(errorReader);
190     }
191     return worker;
192   }
193
194   @BeforeTest(alwaysRun = true)
195   public void initialize()
196   {
197     new CommandLineOperations();
198   }
199
200   @BeforeTest(alwaysRun = true)
201   public void setUpForHeadlessCommandLineInputOperations()
202           throws IOException
203   {
204     String cmds = "nodisplay -open examples/uniref50.fa -sortbytree -props test/jalview/io/testProps.jvprops -colour zappo "
205             + "-jabaws http://www.compbio.dundee.ac.uk/jabaws -nosortbytree "
206             + "-features examples/testdata/plantfdx.features -annotations examples/testdata/plantfdx.annotations -tree examples/testdata/uniref50_test_tree";
207     Worker worker = getJalviewDesktopRunner(true, cmds, SETUP_TIMEOUT);
208     String ln = null;
209     while ((ln = worker.getOutputReader().readLine()) != null)
210     {
211       System.out.println(ln);
212       successfulCMDs.add(ln);
213     }
214     while ((ln = worker.getErrorReader().readLine()) != null)
215     {
216       System.err.println(ln);
217     }
218   }
219
220   @BeforeTest(alwaysRun = true)
221   public void setUpForCommandLineInputOperations() throws IOException
222   {
223     String cmds = "-open examples/uniref50.fa -noquestionnaire -nousagestats";
224     Worker worker = getJalviewDesktopRunner(false, cmds, SETUP_TIMEOUT);
225     String ln = null;
226     int count = 0;
227     while ((ln = worker.getErrorReader().readLine()) != null)
228     {
229       System.out.println(ln);
230       successfulCMDs.add(ln);
231       if (++count > 5)
232       {
233         break;
234       }
235     }
236     if (worker != null && worker.exit == null)
237     {
238       worker.interrupt();
239       Thread.currentThread().interrupt();
240       worker.process.destroy();
241     }
242   }
243
244   @Test(groups = { "Functional" }, dataProvider = "allInputOperationsData")
245   public void testAllInputOperations(String expectedString,
246           String failureMsg)
247   {
248     Assert.assertTrue(successfulCMDs.contains(expectedString), failureMsg);
249   }
250
251   @Test(
252     groups =
253     { "Functional", "testben" },
254     dataProvider = "headlessModeOutputOperationsData")
255   public void testHeadlessModeOutputOperations(String harg, String type,
256           String fileName, boolean withAWT, int expectedMinFileSize,
257           int timeout)
258   {
259     String cmd = harg + type + " " + fileName;
260     // System.out.println(">>>>>>>>>>>>>>>> Command : " + cmd);
261     File file = new File(fileName);
262     file.deleteOnExit();
263     Worker worker = getJalviewDesktopRunner(withAWT, cmd, timeout);
264     assertNotNull(worker, "worker is null");
265     String msg = "Didn't create an output" + type + " file at '"
266             + file.getAbsolutePath() + "'.[" + harg + "]";
267     assertTrue(file.exists(), msg);
268     FileAssert.assertFile(file, msg);
269     FileAssert.assertMinLength(file, expectedMinFileSize);
270     if (worker != null && worker.exit == null)
271     {
272       worker.interrupt();
273       Thread.currentThread().interrupt();
274       worker.process.destroy();
275       Assert.fail("Jalview did not exit after " + type
276               + " generation (try running test again to verify - timeout at "
277               + timeout + "ms). [" + harg + "]");
278     }
279     file.delete();
280   }
281
282   @DataProvider(name = "allInputOperationsData")
283   public Object[][] getHeadlessModeInputParams()
284   {
285     return new Object[][] {
286         // headless mode input operations
287         { "CMD [-color zappo] executed successfully!",
288             "Failed command : -color zappo" },
289         { "CMD [-props test/jalview/io/testProps.jvprops] executed successfully!",
290             "Failed command : -props File" },
291         { "CMD [-sortbytree] executed successfully!",
292             "Failed command : -sortbytree" },
293         { "CMD [-jabaws http://www.compbio.dundee.ac.uk/jabaws] executed successfully!",
294             "Failed command : -jabaws http://www.compbio.dundee.ac.uk/jabaws" },
295         { "CMD [-open examples/uniref50.fa] executed successfully!",
296             "Failed command : -open examples/uniref50.fa" },
297         { "CMD [-nosortbytree] executed successfully!",
298             "Failed command : -nosortbytree" },
299         { "CMD [-features examples/testdata/plantfdx.features]  executed successfully!",
300             "Failed command : -features examples/testdata/plantfdx.features" },
301         { "CMD [-annotations examples/testdata/plantfdx.annotations] executed successfully!",
302             "Failed command : -annotations examples/testdata/plantfdx.annotations" },
303         { "CMD [-tree examples/testdata/uniref50_test_tree] executed successfully!",
304             "Failed command : -tree examples/testdata/uniref50_test_tree" },
305         // non headless mode input operations
306         { "CMD [-nousagestats] executed successfully!",
307             "Failed command : -nousagestats" },
308         { "CMD [-noquestionnaire] executed successfully!",
309             "Failed command : -noquestionnaire" } };
310   }
311
312   @DataProvider(name = "headlessModeOutputOperationsData")
313   public static Object[][] getHeadlessModeOutputParams()
314   {
315     // JBPNote: I'm not clear why need to specify full path for output file
316     // when running tests on build server, but we will keep this patch for now
317     // since it works.
318     // https://issues.jalview.org/browse/JAL-1889?focusedCommentId=21609&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-21609
319     String workingDir = "test/jalview/bin/";
320     return new Object[][] { { "nodisplay -open examples/uniref50.fa",
321         " -eps", workingDir + "test_uniref50_out.eps", true,
322         MINFILESIZE_BIG, TEST_TIMEOUT },
323         { "nodisplay -open examples/uniref50.fa", " -eps",
324             workingDir + "test_uniref50_out.eps", false,
325             MINFILESIZE_BIG, TEST_TIMEOUT },
326         { "nogui -open examples/uniref50.fa", " -eps",
327             workingDir + "test_uniref50_out.eps", true, MINFILESIZE_BIG,
328             TEST_TIMEOUT },
329         { "nogui -open examples/uniref50.fa", " -eps",
330             workingDir + "test_uniref50_out.eps", false,
331             MINFILESIZE_BIG, TEST_TIMEOUT },
332         { "headless -open examples/uniref50.fa", " -eps",
333             workingDir + "test_uniref50_out.eps", true, MINFILESIZE_BIG,
334             TEST_TIMEOUT },
335         { "headless -open examples/uniref50.fa", " -svg",
336             workingDir + "test_uniref50_out.svg", false,
337             MINFILESIZE_BIG, TEST_TIMEOUT },
338         { "headless -open examples/uniref50.fa", " -png",
339             workingDir + "test_uniref50_out.png", true, MINFILESIZE_BIG,
340             TEST_TIMEOUT },
341         { "headless -open examples/uniref50.fa", " -html",
342             workingDir + "test_uniref50_out.html", true,
343             MINFILESIZE_BIG, TEST_TIMEOUT },
344         { "headless -open examples/uniref50.fa", " -fasta",
345             workingDir + "test_uniref50_out.mfa", true, MINFILESIZE_SMALL,
346             TEST_TIMEOUT },
347         { "headless -open examples/uniref50.fa", " -clustal",
348             workingDir + "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
349             TEST_TIMEOUT },
350         { "headless -open examples/uniref50.fa", " -msf",
351             workingDir + "test_uniref50_out.msf", true, MINFILESIZE_SMALL,
352             TEST_TIMEOUT },
353         { "headless -open examples/uniref50.fa", " -pileup",
354             workingDir + "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
355             TEST_TIMEOUT },
356         { "headless -open examples/uniref50.fa", " -pir",
357             workingDir + "test_uniref50_out.pir", true, MINFILESIZE_SMALL,
358             TEST_TIMEOUT },
359         { "headless -open examples/uniref50.fa", " -pfam",
360             workingDir + "test_uniref50_out.pfam", true, MINFILESIZE_SMALL,
361             TEST_TIMEOUT },
362         { "headless -open examples/uniref50.fa", " -blc",
363             workingDir + "test_uniref50_out.blc", true, MINFILESIZE_SMALL,
364             TEST_TIMEOUT },
365         { "headless -open examples/uniref50.fa", " -jalview",
366             workingDir + "test_uniref50_out.jvp", true, MINFILESIZE_SMALL,
367             TEST_TIMEOUT }, };
368   }
369 }