Salome HOME
Porting SALOME KERNEL to CMake
[modules/kernel.git] / src / Launcher / BatchTest.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "BatchTest.hxx"
24 #include "Launcher.hxx"
25
26 #ifdef WITH_LIBBATCH
27 #include <Batch/Batch_Date.hxx>
28 #include <Batch/Batch_MpiImpl.hxx>
29 #endif
30
31 #include "utilities.h"
32
33 #include <sys/stat.h>
34 #include <iostream>
35 #include <fstream>
36 #ifdef WIN32
37 # include <io.h>
38 #endif
39 BatchTest::BatchTest(const Engines::ResourceDefinition& batch_descr) 
40 {
41 #ifdef WITH_LIBBATCH
42   _batch_descr = batch_descr;
43
44   // Getting date
45   Batch::Date date = Batch::Date(time(0));
46   _date = date.str();
47   int lend = _date.size() ;
48   int i = 0 ;
49   while (i < lend) 
50   {
51     if (_date[i] == '/' || _date[i] == '-' || _date[i] == ':' ) 
52     {
53       _date[i] = '_' ;
54     }
55     i++ ;
56   }
57   
58   // Creating test temporary file
59   _test_filename =  "/tmp/";
60   _test_filename +=  _date + "_test_cluster_file_";
61   _test_filename += _batch_descr.hostname.in();
62   _base_filename = _date + "_test_cluster_file_" + _batch_descr.hostname.in();
63 #endif
64 }
65
66 BatchTest::~BatchTest() {}
67
68 bool
69 BatchTest::test()
70 {
71   bool rtn = false;
72   INFOS(std::endl 
73         << "--- Testing batch Machine :" << std::endl
74         << "--- Name       : " << _batch_descr.hostname << std::endl
75         << "--- hostname      : " << _batch_descr.hostname << std::endl
76         << "--- Protocol   : " << _batch_descr.protocol << std::endl
77         << "--- User Name  : " << _batch_descr.username << std::endl
78         << "--- Batch Type : " << _batch_descr.batch << std::endl
79         << "--- MPI Impl   : " << _batch_descr.mpiImpl << std::endl
80         << "--- Appli Path : " << _batch_descr.applipath << std::endl
81        );
82
83   std::string result_connection("Not Tested");
84   std::string result_filecopy("Not Tested");
85   std::string result_getresult("Not Tested");
86   std::string result_jobsubmit_simple("Not Tested");
87   std::string result_jobsubmit_mpi("Not Tested");
88   std::string result_appli("Not Tested");
89
90   result_connection = test_connection();
91   result_filecopy = test_filecopy();
92   result_getresult = test_getresult();
93   result_jobsubmit_simple = test_jobsubmit_simple();
94   result_jobsubmit_mpi = test_jobsubmit_mpi();
95   result_appli = test_appli();
96
97   INFOS(std::endl
98         << "--- Test results" << std::endl
99         << "--- Connection          : " << result_connection << std::endl
100         << "--- File copy           : " << result_filecopy << std::endl
101         << "--- Get results         : " << result_getresult << std::endl
102         << "--- Submit simple job   : " << result_jobsubmit_simple << std::endl
103         << "--- Submit mpi job      : " << result_jobsubmit_mpi << std::endl
104         << "--- Application         : " << result_appli << std::endl
105        );
106   
107   if (result_connection == "OK"       && 
108       result_filecopy == "OK"         &&
109       result_getresult == "OK"        &&
110       result_jobsubmit_simple == "OK" &&
111       result_jobsubmit_mpi == "OK"    &&
112       result_appli == "OK")
113     rtn = true;
114       
115   return rtn;
116 }
117
118 // For this test we use : hostname, protocol, username
119 std::string
120 BatchTest::test_connection()
121 {
122   int status;
123   std::string command;
124   std::string result("Failed : ");
125   std::string hostname = _batch_descr.hostname.in();
126   std::string username = _batch_descr.username.in();
127   std::string protocol = _batch_descr.protocol.in();
128
129   // Basic tests
130   if(hostname == "")
131   {
132     result += "hostname is empty !";
133     return result;
134   }
135   if(username == "")
136   {
137     result += "username is empty !";
138     return result;
139   }
140   if( protocol != "rsh" && protocol != "ssh")
141   {
142     result += "protocol unknown ! (" + protocol + ")";
143     return result;
144   }
145
146   // Build command
147   command += protocol
148           + " "
149           + username + "@" + hostname;
150
151   // Test
152   status = system(command.c_str());
153   if(status) {
154     std::ostringstream oss;
155     oss << status;
156     result += "Error of connection on remote host ! status = ";
157     result += oss.str();
158     return result;
159   }
160
161   result = "OK";
162   return result;
163 }
164
165 // For this test we use : hostname, protocol, username
166 std::string
167 BatchTest::test_filecopy()
168 {
169   int status;
170   std::string home;
171   std::string command;
172   std::string result("Failed : ");
173   std::string hostname = _batch_descr.hostname.in();
174   std::string username = _batch_descr.username.in();
175   std::string protocol = _batch_descr.protocol.in();
176
177   // Getting home directory
178   std::string rst = get_home(&home);
179   if(rst != "") {
180     result += rst;
181     return result;
182   }
183
184   // Writing into the tempory file
185   command = "echo Hello > " +  _test_filename;
186   status = system(command.c_str());
187   if(status) {
188     std::ostringstream oss;
189     oss << status;
190     result += "Error in creating tempory file ! status = ";
191     result += oss.str();
192     return result;
193   }
194
195   // Build command
196   command = "scp";
197   if(protocol == "rsh")
198     command = "rcp";
199   command += " " + _test_filename + " "
200           + username + "@" + hostname + ":" + home;
201
202   // Test
203   status = system(command.c_str());
204   if(status) {
205     std::ostringstream oss;
206     oss << status;
207     result += "Error in copy file on remote host ! status = ";
208     result += oss.str();
209     return result;
210   }
211
212   result = "OK";
213   return result;
214 }
215
216 // For this test we use : hostname, protocol, username
217 std::string
218 BatchTest::test_getresult()
219 {
220   int status;
221   std::string home;
222   std::string command;
223   std::string result("Failed : ");
224   std::string hostname = _batch_descr.hostname.in();
225   std::string username = _batch_descr.username.in();
226   std::string protocol = _batch_descr.protocol.in();
227
228   // Getting home directory
229   std::string rst = get_home(&home);
230   if(rst != "") {
231     result += rst;
232     return result;
233   }
234
235   // Build command
236   command = "scp";
237   if(protocol == "rsh")
238     command = "rcp";
239   command += " " + username + "@" + hostname + ":" + home 
240           + "/" + _base_filename + " " + _test_filename + "_copy";
241
242   // Test
243   status = system(command.c_str());
244   if(status) {
245     std::ostringstream oss;
246     oss << status;
247     result += "Error in copy file from remote host ! status = ";
248     result += oss.str();
249     return result;
250   }
251   
252   // Compare files
253   std::ifstream src_file(_test_filename.c_str());
254   if (!src_file)
255   {
256     result += "Error in reading temporary file ! filename = " + _test_filename;
257     return result;
258   }
259   std::string cp_filename = _test_filename + "_copy";
260   std::ifstream cp_file(cp_filename.c_str());
261   if (!cp_file)
262   {
263     result += "Error in reading temporary copy file ! filename = " + cp_filename;
264     return result;
265   }
266   std::string src_firstline;
267   std::string cp_firstline;
268   std::getline(src_file, src_firstline);
269   std::getline(cp_file, cp_firstline);
270   src_file.close();
271   cp_file.close();
272   if (src_firstline != cp_firstline)
273   {
274     result += "Error source file and copy file are not equa ! source = " + src_firstline + " copy = " + cp_firstline;
275     return result;
276   }
277
278   result = "OK";
279   return result;
280 }
281
282 std::string 
283 BatchTest::test_jobsubmit_simple() 
284 {
285   int status;
286   std::string home;
287   std::string command;
288   std::string result("Failed : ");
289   std::string hostname = _batch_descr.hostname.in();
290   std::string username = _batch_descr.username.in();
291   std::string protocol = _batch_descr.protocol.in();
292   std::string batch_type = _batch_descr.batch.in();
293
294   // Basic test
295   if (batch_type == "lsf")
296   {
297     INFOS("test_jobsubmit_simple not yet implemented for lsf... return OK");
298     result = "OK";
299     return result;
300   }
301   if (batch_type == "ccc")
302   {
303     INFOS("test_jobsubmit_simple not yet implemented for ccc... return OK");
304     result = "OK";
305     return result;
306   }
307   if (batch_type == "slurm")
308   {
309     INFOS("test_jobsubmit_simple not yet implemented for slurm... return OK");
310     result = "OK";
311     return result;
312   }
313   if (batch_type == "sge")
314   {
315     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
316     result = "OK";
317     return result;
318   }
319   if (batch_type != "pbs")
320   {
321     result += "Batch type unknown ! : " + batch_type;
322     return result;
323   }
324
325   // Getting home directory
326   std::string rst = get_home(&home);
327   if(rst != "") {
328     result += rst;
329     return result;
330   }
331
332   // PBS test
333   std::string _test_file_simple = _test_filename + "_simple";
334   std::ofstream file;
335   file.open(_test_file_simple.c_str(), std::ofstream::out);
336   file << "#!/bin/bash\n"
337        << "#PBS -l nodes=1\n"
338        << "#PBS -l walltime=00:01:00\n"
339        << "#PBS -o " + home + "/" + _date + "_simple_output.log\n"
340        << "#PBS -e " + home + "/" + _date + "_simple_error.log\n"
341        << "echo Bonjour\n"
342        << "echo Error >&2\n";
343   file.flush();
344   file.close();
345
346
347   // Build command for copy
348   command = "scp";
349   if(protocol == "rsh")
350     command = "rcp";
351   command += " " + _test_file_simple + " "
352           + username + "@" + hostname + ":" + home;
353   status = system(command.c_str());
354   if(status) {
355     std::ostringstream oss;
356     oss << status;
357     result += "Error in copy job file to remote host ! status = ";
358     result += oss.str();
359     return result;
360   }
361
362   // Build command for submit job
363   std::string file_job_name = _test_filename + "_jobid";
364   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_simple > " + file_job_name;
365   status = system(command.c_str());
366   if(status) {
367     std::ostringstream oss;
368     oss << status;
369     result += "Error in sending qsub to remote host ! status = ";
370     result += oss.str();
371     return result;
372   }
373   std::string jobid;
374   std::ifstream file_job(file_job_name.c_str());
375   if (!file_job)
376   {
377     result += "Error in reading temporary file ! filename = " + file_job_name;
378     return result;
379   }
380   std::getline(file_job, jobid);
381   file_job.close();
382  
383   // Wait the end of the job
384   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
385   bool stop = false;
386   while (!stop) 
387   {
388     status = system(command.c_str());
389     if(status && status != 153 && status != 256*153)
390     {
391       std::ostringstream oss;
392       oss << status;
393       result += "Error in sending qstat to remote host ! status = ";
394       result += oss.str();
395       return result;
396     }
397
398     if(status == 153 || status == 256*153 )
399       stop = true;
400 #ifdef WIN32
401     Sleep(1);
402 #else
403     sleep(1);
404 #endif
405   }
406
407   // Build command for getting results
408   command = "scp";
409   if(protocol == "rsh")
410     command = "rcp";
411   command += " " 
412           + username + "@" + hostname + ":" + home + "/" + _date + "_simple* /tmp";
413   status = system(command.c_str());
414   if(status) {
415     std::ostringstream oss;
416     oss << status;
417     result += "error in getting file result of qsub simple to remote host ! status = ";
418     result += oss.str();
419     return result;
420   }
421   
422   // Test results
423   std::string normal_input;
424   std::string file_normal_name = "/tmp/" + _date + "_simple_output.log";
425   std::ifstream file_normal(file_normal_name.c_str());
426   if (!file_normal)
427   {
428     result += "Error in reading temporary file ! filename = " + file_normal_name;
429     return result;
430   }
431   std::getline(file_normal, normal_input);
432   file_normal.close();
433   if (normal_input != "Bonjour")
434   {
435     result += "error from simple ouput file ! waiting for Bonjour and get : " + normal_input;
436     return result;
437   }
438   std::string error_input;
439   std::string file_error_name = "/tmp/" + _date + "_simple_error.log";
440   std::ifstream file_error(file_error_name.c_str());
441   if (!file_error)
442   {
443     result += "Error in reading temporary file ! filename = " + file_error_name;
444     return result;
445   }
446   std::getline(file_error, error_input);
447   file_error.close();
448   if (error_input != "Error")
449   {
450     result += "error from simple error file ! waiting for Error and get : " + error_input;
451     return result;
452   }
453   result = "OK";
454   return result;
455 }
456
457 std::string 
458 BatchTest::test_jobsubmit_mpi() 
459 {
460 #ifdef WITH_LIBBATCH
461   int status;
462   std::string home;
463   std::string command;
464   MpiImpl * mpiImpl;
465   std::string result("Failed : ");
466   std::string hostname = _batch_descr.hostname.in();
467   std::string username = _batch_descr.username.in();
468   std::string protocol = _batch_descr.protocol.in();
469   std::string batch_type = _batch_descr.batch.in();
470   std::string mpi_type = _batch_descr.mpiImpl.in();
471
472   // Basic test
473   if(mpi_type == "lam")
474     mpiImpl = new MpiImpl_LAM();
475   else if(mpi_type == "mpich1")
476     mpiImpl = new MpiImpl_MPICH1();
477   else if(mpi_type == "mpich2")
478     mpiImpl = new MpiImpl_MPICH2();
479   else if(mpi_type == "openmpi")
480     mpiImpl = new MpiImpl_OPENMPI();
481   else if(mpi_type == "slurmmpi")
482     mpiImpl = new MpiImpl_SLURM();
483   else
484   {
485     result += "Error MPI impl not supported : " + mpi_type;
486     return result;
487   }
488
489   // LSF et SGE not yet implemented...
490   if (batch_type == "lsf")
491   {
492     INFOS("test_jobsubmit_simple not yet implemented for lsf... return OK");
493     result = "OK";
494     return result;
495   }
496
497   if (batch_type == "ccc")
498   {
499     INFOS("test_jobsubmit_simple not yet implemented for ccc... return OK");
500     result = "OK";
501     return result;
502   }
503
504   if (batch_type == "slurm")
505   {
506     INFOS("test_jobsubmit_simple not yet implemented for slurm... return OK");
507     result = "OK";
508     return result;
509   }
510
511   if (batch_type == "sge")
512   {
513     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
514     result = "OK";
515     return result;
516   }
517
518   // Getting home directory
519   std::string rst = get_home(&home);
520   if(rst != "") {
521     result += rst;
522     return result;
523   }
524
525   // MPI test
526   std::string _test_file_script = _test_filename + "_script";
527   std::ofstream file_script;
528   file_script.open(_test_file_script.c_str(), std::ofstream::out);
529   file_script << "#!/bin/bash\n"
530               << "echo HELLO MPI\n";
531   file_script.flush();
532   file_script.close();
533 #ifdef WIN32
534   _chmod
535 #else
536   chmod
537 #endif
538     (_test_file_script.c_str(), 0x1ED);
539
540   std::string _test_file_mpi = _test_filename + "_mpi";
541   std::ofstream file_mpi;
542   file_mpi.open(_test_file_mpi.c_str(), std::ofstream::out);
543   file_mpi << "#!/bin/bash\n"
544            << "#PBS -l nodes=1\n"
545            << "#PBS -l walltime=00:01:00\n"
546            << "#PBS -o " << home << "/" << _date << "_mpi_output.log\n"
547            << "#PBS -e " << home << "/" << _date << "_mpi_error.log\n"
548            << mpiImpl->boot("${PBS_NODEFILE}", 1)
549            << mpiImpl->run("${PBS_NODEFILE}", 1, _base_filename + "_script")
550            << mpiImpl->halt();
551   file_mpi.flush();
552   file_mpi.close();
553
554
555   // Build command for copy
556   command = "scp";
557   if(protocol == "rsh")
558     command = "rcp";
559   command += " " + _test_file_script + " "
560           + username + "@" + hostname + ":" + home;
561   status = system(command.c_str());
562   if(status) {
563     std::ostringstream oss;
564     oss << status;
565     result += "Error in copy job file to remote host ! status = ";
566     result += oss.str();
567     return result;
568   }
569   command = "scp";
570   if(protocol == "rsh")
571     command = "rcp";
572   command += " " + _test_file_mpi + " "
573           + username + "@" + hostname + ":" + home;
574   status = system(command.c_str());
575   if(status) {
576     std::ostringstream oss;
577     oss << status;
578     result += "Error in copy job file to remote host ! status = ";
579     result += oss.str();
580     return result;
581   }
582
583   // Build command for submit job
584   std::string file_job_name = _test_filename + "_jobid";
585   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_mpi > " + file_job_name;
586   status = system(command.c_str());
587   if(status) {
588     std::ostringstream oss;
589     oss << status;
590     result += "Error in sending qsub to remote host ! status = ";
591     result += oss.str();
592     return result;
593   }
594   std::string jobid;
595   std::ifstream file_job(file_job_name.c_str());
596   if (!file_job)
597   {
598     result += "Error in reading temporary file ! filename = " + file_job_name;
599     return result;
600   }
601   std::getline(file_job, jobid);
602   file_job.close();
603  
604   // Wait the end of the job
605   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
606   bool stop = false;
607   while (!stop) 
608   {
609     status = system(command.c_str());
610     if(status && status != 153 && status != 256*153)
611     {
612       std::ostringstream oss;
613       oss << status;
614       result += "Error in sending qstat to remote host ! status = ";
615       result += oss.str();
616       return result;
617     }
618
619     if(status == 153 || status == 256*153 )
620       stop = true;
621 #ifdef WIN32
622     Sleep(1);
623 #else
624     sleep(1);
625 #endif
626   }
627
628   // Build command for getting results
629   command = "scp";
630   if(protocol == "rsh")
631     command = "rcp";
632   command += " " 
633           + username + "@" + hostname + ":" + home + "/" + _date + "_mpi* /tmp";
634   status = system(command.c_str());
635   if(status) {
636     std::ostringstream oss;
637     oss << status;
638     result += "error in getting file result of qsub mpi from remote host ! status = ";
639     result += oss.str();
640     return result;
641   }
642   
643   // Test results
644   std::string normal_input;
645   std::string file_normal_name = "/tmp/" + _date + "_mpi_output.log";
646   std::ifstream file_normal(file_normal_name.c_str());
647   if (!file_normal)
648   {
649     result += "Error in reading temporary file ! filename = " + file_normal_name;
650     return result;
651   }
652   bool test_ok = false;
653   while (std::getline(file_normal, normal_input))
654   {
655     if (normal_input == "HELLO MPI")
656       test_ok = true;
657   }
658   file_normal.close();
659   if (!test_ok)
660   {
661     result += "error from mpi ouput file ! waiting for HELLO MPI please watch /tmp/" + _date + "_mpi_output.log file";
662     return result;
663   }
664   result = "OK";
665   return result;  
666 #else
667   throw LauncherException("Method BatchTest::test_jobsubmit_mpi is not available "
668                           "(libBatch was not present at compilation time)");
669 #endif
670 }
671
672 std::string 
673 BatchTest::test_appli()
674 {
675   int status;
676   std::string home;
677   std::string command;
678   std::string result("Failed : ");
679   std::string hostname = _batch_descr.hostname.in();
680   std::string username = _batch_descr.username.in();
681   std::string protocol = _batch_descr.protocol.in();
682   std::string applipath = _batch_descr.applipath.in();
683   
684   // Getting home directory
685   std::string rst = get_home(&home);
686   if(rst != "") {
687     result += rst;
688     return result;
689   }
690
691   std::string _test_file_appli = _test_filename + "_appli_test";
692   std::ofstream file_appli;
693   file_appli.open(_test_file_appli.c_str(), std::ofstream::out);
694   file_appli << "#!/bin/bash\n"
695              << "if [ -f " << applipath << "/runAppli ]\n"
696              << "then\n"
697              << "  echo OK\n"
698              << "else\n"
699              << "  echo NOK\n"
700              << "fi\n";
701   file_appli.flush();
702   file_appli.close();
703
704   // Build command for copy
705   command = "scp";
706   if(protocol == "rsh")
707     command = "rcp";
708   command += " " + _test_file_appli + " "
709           + username + "@" + hostname + ":" + home;
710   status = system(command.c_str());
711   if(status) {
712     std::ostringstream oss;
713     oss << status;
714     result += "Error in copy appli test file to remote host ! status = ";
715     result += oss.str();
716     return result;
717   }
718
719   // Launch test
720   command = protocol + " " + username + "@" + hostname 
721           + " sh " + home + "/" + _base_filename + "_appli_test > " 
722           + _test_filename + "_appli_test_result";
723
724   status = system(command.c_str());
725   if(status) {
726     std::ostringstream oss;
727     oss << status;
728     result += "Error in launching appli test on remote host ! status = ";
729     result += oss.str();
730     return result;
731   }
732
733   // Read test result
734   std::string rst_appli;
735   std::string file_appli_result_name = _test_filename + "_appli_test_result";
736   std::ifstream file_appli_result(file_appli_result_name.c_str());
737   if (!file_appli_result)
738   {
739     result += "Error in reading temporary file ! filename = " + file_appli_result_name;
740     return result;
741   }
742   std::getline(file_appli_result, rst_appli);
743   file_appli_result.close();
744   
745   if (rst_appli != "OK")
746   {
747     result += "Error checking application on remote host ! result = " + rst;
748     return result;
749   }
750
751   result = "OK";
752   return result;
753 }
754
755 // Useful methods
756 std::string
757 BatchTest::get_home(std::string * home)
758 {
759   int status;
760   std::string result = "";
761   std::string command;
762   std::string hostname = _batch_descr.hostname.in();
763   std::string username = _batch_descr.username.in();
764   std::string protocol = _batch_descr.protocol.in();
765   std::string file_home_name = _test_filename + "_home";
766
767   command = protocol + " " + username + "@" + hostname + " 'echo $HOME' > " + file_home_name; 
768   status = system(command.c_str());
769   if(status) {
770     std::ostringstream oss;
771     oss << status;
772     result += "Error in getting home directory ! status = ";
773     result += oss.str();
774     return result;
775   }
776
777   std::ifstream file_home(file_home_name.c_str());
778   if (!file_home)
779   {
780     result += "Error in reading temporary file ! filename = " + file_home_name;
781     return result;
782   }
783   std::getline(file_home, *home);
784   file_home.close();
785   return result;
786 }