test_ncbi_process.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:8k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: test_ncbi_process.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:09:49  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: test_ncbi_process.cpp,v 1000.1 2004/06/01 19:09:49 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Aaron Ucko, Vladimir Ivanov
  35.  *
  36.  *
  37.  */
  38. #include <ncbi_pch.hpp>
  39. #include <corelib/ncbiapp.hpp>
  40. #include <corelib/ncbienv.hpp>
  41. #include <corelib/ncbiargs.hpp>
  42. #include <corelib/ncbiexec.hpp>
  43. #include <corelib/ncbifile.hpp>
  44. #include <corelib/ncbi_system.hpp>
  45. #include <corelib/ncbi_process.hpp>
  46. #include <test/test_assert.h>  /* This header must go last */
  47. USING_NCBI_SCOPE;
  48. /////////////////////////////////
  49. // General tests
  50. //
  51. static void Test_Process(void)
  52. {
  53.     LOG_POST("nProcess tests:n");
  54.     string app = CNcbiApplication::Instance()->GetArguments().GetProgramName();
  55.     TPid pid;
  56.     {{
  57.         LOG_POST("CMD = " << app << " -sleep 3");
  58.         pid = CExec::SpawnL(CExec::eNoWait, app.c_str(), "-sleep", "3", 0);
  59.         LOG_POST("PID = " << pid);
  60.         CProcess process(pid, CProcess::eHandle);
  61.         assert(process.IsAlive());
  62.         assert(process.Wait() == 88);
  63.         assert(!process.IsAlive());
  64.     }}
  65.     {{
  66.         LOG_POST("CMD = " << app << " -sleep 10");
  67.         pid = CExec::SpawnL(CExec::eNoWait, app.c_str(), "-sleep", "10", 0);
  68.         LOG_POST("PID = " << pid);
  69.         CProcess process(pid, CProcess::eHandle);
  70.         assert(process.IsAlive());
  71.         assert( process.Wait(2000) == -1);
  72.         assert(process.Kill());
  73.         assert(!process.IsAlive());
  74.         int exitcode = process.Wait();
  75.         LOG_POST("Wait(pid) = " << exitcode);
  76.         assert(exitcode != 88);
  77.     }}
  78. }
  79. /////////////////////////////////
  80. // PIDGuard test
  81. //
  82. // NOTE:  ppid is int rather than TPid in these two functions because we need
  83. //        it to be signed.
  84. static void Test_PIDGuardChild(int ppid, string lockfile)
  85. {
  86. string s_app =
  87.         CNcbiApplication::Instance()->GetArguments().GetProgramName();
  88. string s_pid = NStr::IntToString(ppid);
  89.     int ret_code = CExec::SpawnL(CExec::eWait, s_app.c_str(),
  90.                                  "-parent", s_pid.c_str() ,
  91.                                  "-lockfile", lockfile.c_str(), 0); 
  92. assert( !ret_code );
  93. }
  94. static void Test_PIDGuard(int ppid, string lockfile)
  95. {
  96.     if (lockfile.empty()) {
  97.         // Fixed names are usually more appropriate, but here we don't
  98.         // want independent tests to step on each other....
  99.         lockfile = CFile::GetTmpName();
  100.     }
  101.     CFile lf(lockfile);
  102.     TPid my_pid = CProcess::GetCurrentPid();
  103.     assert(my_pid > 0);
  104.     LOG_POST("nTest_PIDGuard starting:nmy_pid = " << my_pid
  105.              << ", ppid = " << ppid << ", lockfile = " << lockfile << 'n');
  106.     // Parent
  107.     if (ppid == 0) {
  108.         CPIDGuard guard(lockfile);
  109.         {
  110.             CPIDGuard guard2(lockfile);
  111.         }
  112.         assert(lf.Exists());
  113.         Test_PIDGuardChild(my_pid, lockfile);
  114.         assert(lf.Exists());
  115.         guard.Release();
  116.         assert(!lf.Exists());
  117.         Test_PIDGuardChild(-1, lockfile);
  118.         assert(lf.Exists());
  119. #if defined(NCBI_OS_MSWIN)
  120.         // Additional check on stuck child process.
  121.         //
  122.         // On some Windows machines OS report that child process is still
  123.         // running even if we already have its exit code.
  124.         CNcbiIfstream in(lockfile.c_str());
  125.         if (in.good()) {
  126.             int child_pid = 0;
  127.             in >> child_pid;
  128.             if ( child_pid > 0 ) {
  129. CProcess child(child_pid, CProcess::ePid);
  130. child.Wait();
  131.             }
  132.         }
  133.         in.close();
  134. #endif
  135.         Test_PIDGuardChild(-2, lockfile);
  136.         assert(!lf.Exists());
  137.     }
  138.     // Child run with parent lock open
  139.     else if (ppid > 0) {
  140.         try {
  141.             LOG_POST("Expect an exception now.");
  142.             CPIDGuard guard(lockfile);
  143.             ERR_POST("Should have been locked (by parent)");
  144.             _TROUBLE;
  145.         } catch (CPIDGuardException& e) {
  146.             LOG_POST(e.what());
  147.             assert(e.GetErrCode() == CPIDGuardException::eStillRunning);
  148.             assert(e.GetPID() == ppid);
  149.         }
  150.     } else if (ppid == -1) {
  151.         new CPIDGuard(lockfile); // deliberate leak
  152.         LOG_POST("Left stale lock.");
  153.     } else if (ppid == -2) {
  154.         CPIDGuard guard(lockfile);
  155.         TPid old_pid = guard.GetOldPID();
  156.         assert(old_pid > 0);
  157.         LOG_POST("Old PID was " << old_pid);
  158.     } else {
  159.         _TROUBLE;
  160.     }
  161.     CPIDGuard unique_guard(CFile::GetTmpName());
  162. }
  163. /////////////////////////////////
  164. // Test application
  165. //
  166. class CTestApplication : public CNcbiApplication
  167. {
  168. public:
  169.     virtual void Init(void);
  170.     virtual int  Run (void);
  171. };
  172. void CTestApplication::Init(void)
  173. {
  174.     // Set error posting and tracing on maximum
  175.     SetDiagTrace(eDT_Enable);
  176.     SetDiagPostFlag(eDPF_All);
  177.     SetDiagPostLevel(eDiag_Info);
  178.     // Create command-line argument descriptions class
  179.     auto_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
  180.     // Specify USAGE context
  181.     arg_desc->SetUsageContext(GetArguments().GetProgramBasename(),
  182.                               "Test process management functions");
  183.     // Specific to Process test
  184.     arg_desc->AddDefaultKey("sleep", "sec", "for internal use only",
  185.                             CArgDescriptions::eInteger, "0");
  186.     // Specific to PID guard test
  187.     arg_desc->AddDefaultKey("parent", "PID", "for internal use only",
  188.                             CArgDescriptions::eInteger, "0");
  189.     arg_desc->AddDefaultKey("lockfile", "filename", "parent's lock file",
  190.                             CArgDescriptions::eString, kEmptyStr);
  191.     // Setup arg.descriptions for this application
  192.     SetupArgDescriptions(arg_desc.release());
  193. }
  194. int CTestApplication::Run(void)
  195. {
  196.     CArgs args = GetArgs();
  197.     // Is this an instance executed from process test?
  198.     int sec = args["sleep"].AsInteger();
  199.     if ( sec ) {
  200.         LOG_POST("Client is sleeping " << sec << " sec.");
  201.         SleepSec(sec);
  202.         return 88;
  203.     }
  204.     // Main tests
  205.     // General tests
  206.     if ( !args["parent"].AsInteger() ) {
  207.         Test_Process();
  208.     }
  209.     // PIDGuard tests
  210.     Test_PIDGuard(args["parent"].AsInteger(), args["lockfile"].AsString());
  211.     return 0;
  212. }
  213.   
  214. ///////////////////////////////////
  215. // APPLICATION OBJECT  and  MAIN
  216. //
  217. static CTestApplication theTestApplication;
  218. int main(int argc, const char* argv[])
  219. {
  220.     // Execute main application function
  221.     return theTestApplication.AppMain(argc, argv, 0, eDS_Default, 0);
  222. }
  223. /*
  224.  * ===========================================================================
  225.  * $Log: test_ncbi_process.cpp,v $
  226.  * Revision 1000.1  2004/06/01 19:09:49  gouriano
  227.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  228.  *
  229.  * Revision 1.3  2004/05/18 17:05:31  ivanov
  230.  * CPIDGuard tests:
  231.  *     Use CExec::SpawnL() instead System() to run child process.
  232.  *     Added some new asserts.
  233.  *
  234.  * Revision 1.2  2004/05/14 13:59:51  gorelenk
  235.  * Added include of ncbi_pch.hpp
  236.  *
  237.  * Revision 1.1  2003/09/25 16:59:11  ivanov
  238.  * Initial revision
  239.  *
  240.  * ===========================================================================
  241.  */