1 /* $Id: test_ncbiexec.cpp 604961 2020-04-05 17:25:42Z lavr $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Vladimir Ivanov
27 *
28 * File Description: Test program for portable exec functions
29 *
30 * Note: On mS-Windows Cygwin should be installed and added to PATH before
31 * run this test program, because we use 'ls' command.
32 *
33 */
34
35 #include <ncbi_pch.hpp>
36 #include <corelib/ncbiapp.hpp>
37 #include <corelib/ncbiargs.hpp>
38 #include <corelib/ncbienv.hpp>
39 #include <corelib/ncbiexec.hpp>
40
41 #if defined(HAVE_UNISTD_H)
42 # include <unistd.h> // for _exit()
43 #endif
44
45 #include <common/test_assert.h> // This header must go last
46
47 #if NCBI_COMPILER_MSVC && (_MSC_VER >= 1400)
48 /* Microsoft does not want to use POSIX name, not to accept POSIX compliance */
49 # define sys_strdup _strdup
50 #else
51 # define sys_strdup strdup
52 #endif /*NCBI_COMPILER_MSVC && _MSC_VER>=1400*/
53
54
55 USING_NCBI_SCOPE;
56
57
58 #define TEST_RESULT_C 99 // Test exit code for current test
59 #define TEST_RESULT_P 0 // Test exit code for test from PATH
60
61 // Array of arguments to test argument quoting in SpawnL/SpawnV
62 const char* s_QuoteArgsTest[] =
63 {
64 "", // reserved: Will be overwritten with application name
65 "SpawnV_Quote", // reserved: Test name
66 "",
67 " ",
68 "\\",
69 " \\",
70 "\\ ",
71 "dir\\",
72 "dir\\path",
73 "d i r\\p a t h",
74 "d i r\\p a t h\\",
75 "a b",
76 "\"a", // "a
77 "a\"b", // a"b
78 "\"a b\"", // "a b"
79 "a\\\\b", // a\\b
80 "a\\\\\\b", // a\\\b
81 "a\\\"b", // a\"b
82 "a\\\\\"b", // a\\"b
83 "a\\\\\\\"b", // a\\\"b
84 "a\\\\\\\\\"b", // a\\\\"b
85 "\"", // "
86 "\"\"", // ""
87 "\"\"\"", // """
88 "\"\"\"\"", // """"
89 "!{} \t\r\n[|&;<>()$`'*?#~=%",
90 NULL
91 };
92
93
94 ////////////////////////////////
95 // Test application
96 //
97
98 class CTest : public CNcbiApplication
99 {
100 public:
101 void Init(void);
102 int Run(void);
103 };
104
105
Init(void)106 void CTest::Init(void)
107 {
108 SetDiagPostLevel(eDiag_Warning);
109 unique_ptr<CArgDescriptions> d(new CArgDescriptions);
110 d->SetUsageContext("test_files",
111 "test file's accessory functions");
112 SetupArgDescriptions(d.release());
113 }
114
115
Run(void)116 int CTest::Run(void)
117 {
118 TExitCode code;
119 TProcessHandle handle;
120
121 string app = GetArguments().GetProgramName();
122 LOG_POST("Application path: " << app);
123
124 // Initialization of variables and structures
125
126 char* app_c = sys_strdup(app.c_str());
127 assert( app_c != 0 );
128
129 const char* app_p = "ls";
130 const char* app_pp = "..";
131
132 const char* my_env[] = // Environment for Spawn*E
133 {
134 "THIS=environment will be",
135 "PASSED=to new process by the",
136 "EXEC=functions",
137 "TEST_NCBI_EXEC=yes",
138 NULL
139 };
140
141 {{
142 #if defined(NCBI_OS_CYGWIN)
143 string path_setting("PATH=");
144 const string& path = GetEnvironment().Get("PATH");
145 #elif defined(NCBI_OS_DARWIN)
146 string path_setting("DYLD_LIBRARY_PATH=");
147 const string& path = GetEnvironment().Get("DYLD_LIBRARY_PATH");
148 #else
149 string path_setting("LD_LIBRARY_PATH=");
150 const string& path = GetEnvironment().Get("LD_LIBRARY_PATH");
151 #endif
152 if (path.size()) {
153 path_setting += path;
154 my_env[0] = sys_strdup(path_setting.c_str());
155 }
156 }}
157
158 const char* args_c[3]; // Arguments for SpawnV[E]
159 args_c[1] = "SpawnV[E]";
160 args_c[2] = NULL;
161
162 const char* args_p[3]; // Arguments for SpawnVP[E]
163 args_p[1] = app_pp;
164 args_p[2] = NULL;
165
166
167 // ResolvePath() test
168
169 assert( CExec::IsExecutable(app_c) );
170 string res_path;
171 res_path = CExec::ResolvePath(app_c);
172 LOG_POST("Resolve path: " << app_c << " -> " << res_path);
173 assert( !res_path.empty() );
174 res_path = CExec::ResolvePath(app_p);
175 LOG_POST("Resolve path: " << app_p << " -> " << res_path);
176 assert( !res_path.empty() );
177 #if defined(NCBI_OS_MSWIN)
178 res_path = CExec::ResolvePath("winver.exe");
179 LOG_POST("Resolve path: " << "winver.exe" << " -> " << res_path);
180 assert( !res_path.empty() );
181 #endif
182
183
184 // System
185
186 #if !defined(NCBI_OS_CYGWIN)
187 // This test doesn't work on GCC/Cygwin
188 assert( CExec::System(0) > 0 );
189 #endif
190 string cmd = app + " System";
191 assert( CExec::System(cmd.c_str()) == TEST_RESULT_C );
192 cmd = string(app_p) + " " + app_pp;
193 assert( CExec::System(cmd.c_str()) == TEST_RESULT_P );
194
195 // Spawn with eWait
196 {{
197 code = CExec::SpawnL (CExec::eWait, app_c, "SpawnL_eWait", NULL).GetExitCode();
198 assert( code == TEST_RESULT_C );
199 code = CExec::SpawnLP (CExec::eWait, app_p, app_pp, NULL).GetExitCode();
200 assert( code == TEST_RESULT_P );
201 code = CExec::SpawnLE (CExec::eWait, app_c, "SpawnLE_eWait", NULL, my_env).GetExitCode();
202 assert( code == TEST_RESULT_C );
203 code = CExec::SpawnLPE(CExec::eWait, app_c, "SpawnLPE_eWait", NULL, my_env).GetExitCode();
204 assert( code == TEST_RESULT_C );
205 code = CExec::SpawnV (CExec::eWait, app_c, args_c).GetExitCode();
206 assert( code == TEST_RESULT_C );
207 code = CExec::SpawnVP (CExec::eWait, app_p, args_p).GetExitCode();
208 assert( code == TEST_RESULT_P );
209 code = CExec::SpawnVE (CExec::eWait, app_c, args_c, my_env).GetExitCode();
210 assert( code == TEST_RESULT_C );
211 code = CExec::SpawnVPE(CExec::eWait, app_c, args_c, my_env).GetExitCode();
212 assert( code == TEST_RESULT_C );
213 }}
214
215 // Spawn with eNoWait, waiting self
216 {{
217 handle = CExec::SpawnL (CExec::eNoWait, app_c, "SpawnL_eNoWait", NULL).GetProcessHandle();
218 assert(CExec::Wait(handle) == TEST_RESULT_C );
219 handle = CExec::SpawnLP (CExec::eNoWait, app_p, app_pp, NULL).GetProcessHandle();
220 assert(CExec::Wait(handle) == TEST_RESULT_P);
221 handle = CExec::SpawnLE (CExec::eNoWait, app_c, "SpawnLE_eNoWait", NULL, my_env).GetProcessHandle();
222 assert(CExec::Wait(handle) == TEST_RESULT_C);
223 handle = CExec::SpawnLPE(CExec::eNoWait, app_c, "SpawnLPE_eNoWait", NULL, my_env).GetProcessHandle();
224 assert(CExec::Wait(handle) == TEST_RESULT_C);
225 }}
226
227 // Spawn with eDetach
228 {{
229 CExec::SpawnL (CExec::eDetach, app_c, "SpawnL_eDetach", NULL);
230 CExec::SpawnLP (CExec::eDetach, app_p, app_pp, NULL);
231 CExec::SpawnLE (CExec::eDetach, app_c, "SpawnLE_eDetach", NULL, my_env);
232 CExec::SpawnLPE(CExec::eDetach, app_c, "SpawnLPE_eDetach",NULL, my_env);
233 CExec::SpawnV (CExec::eDetach, app_c, args_c);
234 CExec::SpawnVP (CExec::eDetach, app_p, args_p);
235 CExec::SpawnVE (CExec::eDetach, app_c, args_c, my_env);
236 CExec::SpawnVPE(CExec::eDetach, app_c, args_c, my_env);
237 }}
238
239 // Spawn with eWaitGroup
240 {{
241 code = CExec::SpawnL(CExec::eWaitGroup, app_c, "SpawnL_eWaitGroup", NULL).GetExitCode();
242 assert( code == TEST_RESULT_C );
243 }}
244
245 // Spawn with eNoWaitGroup, waiting self
246 {{
247 handle = CExec::SpawnL(CExec::eNoWaitGroup, app_c, "SpawnL_eNoWaitGroup", NULL).GetProcessHandle();
248 assert( CExec::Wait(handle) == TEST_RESULT_C );
249 }}
250
251 // Argument quoting test
252 {{
253 code = CExec::SpawnL(CExec::eWait, app_c,
254 "SpawnL_Quote",
255 s_QuoteArgsTest[ 2],
256 s_QuoteArgsTest[ 3],
257 s_QuoteArgsTest[ 4],
258 s_QuoteArgsTest[ 5],
259 s_QuoteArgsTest[ 6],
260 s_QuoteArgsTest[ 7],
261 s_QuoteArgsTest[ 8],
262 s_QuoteArgsTest[ 9],
263 s_QuoteArgsTest[10],
264 s_QuoteArgsTest[11],
265 s_QuoteArgsTest[12],
266 s_QuoteArgsTest[13],
267 s_QuoteArgsTest[14],
268 s_QuoteArgsTest[15],
269 s_QuoteArgsTest[16],
270 s_QuoteArgsTest[17],
271 s_QuoteArgsTest[18],
272 s_QuoteArgsTest[19],
273 s_QuoteArgsTest[20],
274 s_QuoteArgsTest[21],
275 s_QuoteArgsTest[22],
276 s_QuoteArgsTest[23],
277 s_QuoteArgsTest[24],
278 s_QuoteArgsTest[25],
279 NULL).GetExitCode();
280 assert( code == TEST_RESULT_C );
281 code = CExec::SpawnV(CExec::eWait, app_c, s_QuoteArgsTest).GetExitCode();
282 assert( code == TEST_RESULT_C );
283 }}
284
285 // Spawn with eOverlay
286 {{
287 code = CExec::SpawnL(CExec::eOverlay, app_c, "SpawnL_eOverlay", NULL).GetExitCode();
288 assert( code == TEST_RESULT_C );
289 }}
290
291 // At success code below never been executed
292 LOG_POST("\nTEST execution fails!\n");
293
294 return 77;
295 }
296
297
298 ///////////////////////////////////
299 // MAIN
300 //
301
main(int argc,const char * argv[],const char * [])302 int main(int argc, const char* argv[], const char* /*envp*/[])
303 {
304 // Exec from test?
305 if ( argc > 1) {
306 assert(argv[1] && *argv[1]);
307 cout << endl << "Exec: " << argv[1] << endl;
308
309 if ( strstr(argv[1],"Quote")) {
310 // Check arguments
311 const size_t n = sizeof(s_QuoteArgsTest) / sizeof(s_QuoteArgsTest[0]);
312 assert(argc == (n-1));
313 for (int i=2; i<argc; i++) {
314 //cout << i << " = '" << argv[i] << "'" << endl;
315 //cout << i << " = '" << s_QuoteArgsTest[i] << "'" << endl;
316 //cout << i << " = '" << NStr::PrintableString(argv[i]) << "'" << endl;
317 //cout << i << " = '" << NStr::PrintableString(s_QuoteArgsTest[i]) << "'" << endl;
318 cout.flush();
319 assert( NStr::CompareCase(s_QuoteArgsTest[i], argv[i]) == 0 );
320 }
321
322 } else {
323 assert(argc == 2);
324 }
325
326 // View environment
327 /*
328 const char** env_var = &envp[0];
329 while (*env_var) {
330 cout << *env_var << endl;
331 env_var++;
332 }
333 */
334 // Check environment
335 if ( strstr(argv[1],"E_e")) {
336 char* ptr = getenv("TEST_NCBI_EXEC");
337 if (!ptr || !*ptr) {
338 cout << "Environment variable TEST_NCBI_EXEC not found" <<endl;
339 cout.flush();
340 _exit(88);
341 } else {
342 cout << "TEST_NCBI_EXEC=" << ptr << endl;
343 }
344 }
345 cout.flush();
346 _exit(TEST_RESULT_C);
347 }
348 LOG_POST("Start tests:\n");
349
350 // Execute main application function
351 return CTest().AppMain(argc, argv);
352 }
353