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