xref: /AOO41X/main/sal/qa/osl/process/osl_process.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sal.hxx"
30 
31 #include <testshl/simpleheader.hxx>
32 #include <osl/process.h>
33 #include <osl/file.hxx>
34 #include <osl/thread.h>
35 #include <rtl/ustring.hxx>
36 #include <unistd.h>
37 #include <signal.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <osl/module.hxx>
42 
43 #if ( defined WNT )                     // Windows
44 #include <tools/prewin.h>
45 #	define WIN32_LEAN_AND_MEAN
46 // #	include <windows.h>
47 #   include <tchar.h>
48 #include <tools/postwin.h>
49 #endif
50 
51 #include "rtl/allocator.hxx"
52 
53 #include <iostream>
54 #include <fstream>
55 #include <vector>
56 #include <algorithm>
57 #include <iterator>
58 #include <string>
59 
60 #if defined(WNT) || defined(OS2)
61 	const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child.exe");
62 #else
63 	const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child");
64 #endif
65 
66 
67 //########################################
68 std::string OUString_to_std_string(const rtl::OUString& oustr)
69 {
70     rtl::OString ostr = rtl::OUStringToOString(oustr, osl_getThreadTextEncoding());
71     return std::string(ostr.getStr());
72 }
73 
74 //########################################
75 using namespace osl;
76 using namespace rtl;
77 
78 /** print a UNI_CODE String.
79 */
80 inline void printUString( const ::rtl::OUString & str )
81 {
82 	rtl::OString aString;
83 
84 	t_print("#printUString_u# " );
85 	aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US );
86 	t_print("%s\n", aString.getStr( ) );
87 }
88 
89 /** get binary Path.
90 */
91 inline ::rtl::OUString getExecutablePath( void )
92 {
93 	::rtl::OUString dirPath;
94 	osl::Module::getUrlFromAddress( ( void* ) &getExecutablePath, dirPath );
95 	dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') );
96 	dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1);
97 	dirPath += rtl::OUString::createFromAscii("bin");
98 	return dirPath;
99 }
100 
101 //rtl::OUString CWD = getExecutablePath();
102 
103 //########################################
104 class Test_osl_joinProcess : public CppUnit::TestFixture
105 {
106     const OUString join_param_;
107     const OUString wait_time_;
108     OUString suCWD;
109     OUString suExecutableFileURL;
110 
111     rtl_uString* parameters_[2];
112     int          parameters_count_;
113 
114 public:
115 
116     Test_osl_joinProcess() :
117         join_param_(OUString::createFromAscii("-join")),
118         wait_time_(OUString::createFromAscii("1")),
119         parameters_count_(2)
120     {
121         parameters_[0] = join_param_.pData;
122         parameters_[1] = wait_time_.pData;
123         suCWD = getExecutablePath();
124         suExecutableFileURL = suCWD;
125         suExecutableFileURL += rtl::OUString::createFromAscii("/");
126         suExecutableFileURL += EXECUTABLE_NAME;
127     }
128 
129     /*-------------------------------------
130         Start a process and join with this
131         process specify a timeout so that
132         osl_joinProcessWithTimeout returns
133         osl_Process_E_TimedOut
134      -------------------------------------*/
135 
136     void osl_joinProcessWithTimeout_timeout_failure()
137     {
138         oslProcess process;
139         oslProcessError osl_error = osl_executeProcess(
140             suExecutableFileURL.pData,
141             parameters_,
142             parameters_count_,
143             osl_Process_NORMAL,
144             osl_getCurrentSecurity(),
145             suCWD.pData,
146             NULL,
147             0,
148             &process);
149 
150         CPPUNIT_ASSERT_MESSAGE
151         (
152             "osl_createProcess failed",
153             osl_error == osl_Process_E_None
154         );
155 
156         TimeValue timeout;
157         timeout.Seconds = 1;
158         timeout.Nanosec = 0;
159 
160         osl_error = osl_joinProcessWithTimeout(process, &timeout);
161 
162         CPPUNIT_ASSERT_MESSAGE
163         (
164             "osl_joinProcessWithTimeout returned without timeout failure",
165             osl_Process_E_TimedOut == osl_error
166         );
167 
168         osl_error = osl_terminateProcess(process);
169 
170         CPPUNIT_ASSERT_MESSAGE
171         (
172             "osl_terminateProcess failed",
173             osl_error == osl_Process_E_None
174         );
175 
176         osl_freeProcessHandle(process);
177     }
178 
179     /*-------------------------------------
180         Start a process and join with this
181         process specify a timeout so that
182         osl_joinProcessWithTimeout returns
183         osl_Process_E_None
184      -------------------------------------*/
185 
186     void osl_joinProcessWithTimeout_without_timeout_failure()
187     {
188         oslProcess process;
189         oslProcessError osl_error = osl_executeProcess(
190             suExecutableFileURL.pData,
191             parameters_,
192             parameters_count_,
193             osl_Process_NORMAL,
194             osl_getCurrentSecurity(),
195             suCWD.pData,
196             NULL,
197             0,
198             &process);
199 
200         CPPUNIT_ASSERT_MESSAGE
201         (
202             "osl_createProcess failed",
203             osl_error == osl_Process_E_None
204         );
205 
206         TimeValue timeout;
207         timeout.Seconds = 10;
208         timeout.Nanosec = 0;
209 
210         osl_error = osl_joinProcessWithTimeout(process, &timeout);
211 
212         CPPUNIT_ASSERT_MESSAGE
213         (
214             "osl_joinProcessWithTimeout returned with failure",
215             osl_Process_E_None == osl_error
216         );
217 
218         osl_freeProcessHandle(process);
219     }
220 
221      /*-------------------------------------
222         Start a process and join with this
223         process specify an infinite timeout
224      -------------------------------------*/
225 
226     void osl_joinProcessWithTimeout_infinite()
227     {
228         oslProcess process;
229         oslProcessError osl_error = osl_executeProcess(
230             suExecutableFileURL.pData,
231             parameters_,
232             parameters_count_,
233             osl_Process_NORMAL,
234             osl_getCurrentSecurity(),
235             suCWD.pData,
236             NULL,
237             0,
238             &process);
239 
240         CPPUNIT_ASSERT_MESSAGE
241         (
242             "osl_createProcess failed",
243             osl_error == osl_Process_E_None
244         );
245 
246         osl_error = osl_joinProcessWithTimeout(process, NULL);
247 
248         CPPUNIT_ASSERT_MESSAGE
249         (
250             "osl_joinProcessWithTimeout returned with failure",
251             osl_Process_E_None == osl_error
252         );
253 
254         osl_freeProcessHandle(process);
255     }
256 
257      /*-------------------------------------
258         Start a process and join with this
259         process using osl_joinProcess
260      -------------------------------------*/
261 
262      void osl_joinProcess()
263     {
264         oslProcess process;
265         oslProcessError osl_error = osl_executeProcess(
266             suExecutableFileURL.pData,
267             parameters_,
268             parameters_count_,
269             osl_Process_NORMAL,
270             osl_getCurrentSecurity(),
271             suCWD.pData,
272             NULL,
273             0,
274             &process);
275 
276         CPPUNIT_ASSERT_MESSAGE
277         (
278             "osl_createProcess failed",
279             osl_error == osl_Process_E_None
280         );
281 
282         osl_error = ::osl_joinProcess(process);
283 
284         CPPUNIT_ASSERT_MESSAGE
285         (
286             "osl_joinProcess returned with failure",
287             osl_Process_E_None == osl_error
288         );
289 
290         osl_freeProcessHandle(process);
291     }
292 
293     CPPUNIT_TEST_SUITE(Test_osl_joinProcess);
294     CPPUNIT_TEST(osl_joinProcessWithTimeout_timeout_failure);
295     CPPUNIT_TEST(osl_joinProcessWithTimeout_without_timeout_failure);
296     CPPUNIT_TEST(osl_joinProcessWithTimeout_infinite);
297     CPPUNIT_TEST(osl_joinProcess);
298     CPPUNIT_TEST_SUITE_END();
299 };
300 
301 //#########################################################
302 
303 typedef std::vector<std::string, rtl::Allocator<std::string> >  string_container_t;
304 typedef string_container_t::const_iterator string_container_const_iter_t;
305 typedef string_container_t::iterator       string_container_iter_t;
306 
307 //#########################################################
308 class exclude : public std::unary_function<std::string, bool>
309 {
310 public:
311     //------------------------------------------------
312     exclude(const string_container_t& exclude_list)
313     {
314         string_container_const_iter_t iter     = exclude_list.begin();
315         string_container_const_iter_t iter_end = exclude_list.end();
316         for (/**/; iter != iter_end; ++iter)
317             exclude_list_.push_back(env_var_name(*iter));
318     }
319 
320     //------------------------------------------------
321     bool operator() (const std::string& env_var) const
322     {
323         return (exclude_list_.end() !=
324                 std::find(
325                     exclude_list_.begin(),
326                     exclude_list_.end(),
327                     env_var_name(env_var)));
328     }
329 
330 private:
331     //-------------------------------------------------
332     // extract the name from an environment variable
333     // that is given in the form "NAME=VALUE"
334     std::string env_var_name(const std::string& env_var) const
335     {
336         std::string::size_type pos_equal_sign =
337             env_var.find_first_of("=");
338 
339         if (std::string::npos != pos_equal_sign)
340             return std::string(env_var, 0, pos_equal_sign);
341 
342         return std::string();
343     }
344 
345 private:
346     string_container_t exclude_list_;
347 };
348 
349 #ifdef WNT
350     void read_parent_environment(string_container_t* env_container)
351     {
352         LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings());
353         LPTSTR p   = env;
354 
355         while (size_t l = _tcslen(p))
356         {
357             env_container->push_back(std::string(p));
358             p += l + 1;
359         }
360         FreeEnvironmentStrings(env);
361     }
362 #else
363     extern char** environ;
364     void read_parent_environment(string_container_t* env_container)
365     {
366         for (int i = 0; NULL != environ[i]; i++)
367             env_container->push_back(std::string(environ[i]));
368     }
369 #endif
370 
371 //#########################################################
372 class Test_osl_executeProcess : public CppUnit::TestFixture
373 {
374     const OUString env_param_;
375 
376     OUString     temp_file_path_;
377     rtl_uString* parameters_[2];
378     int          parameters_count_;
379     OUString	suCWD;
380     OUString	suExecutableFileURL;
381 
382 public:
383 
384     //------------------------------------------------
385     // ctor
386     Test_osl_executeProcess() :
387         env_param_(OUString::createFromAscii("-env")),
388         parameters_count_(2)
389     {
390         parameters_[0] = env_param_.pData;
391         suCWD = getExecutablePath();
392         suExecutableFileURL = suCWD;
393         suExecutableFileURL += rtl::OUString::createFromAscii("/");
394         suExecutableFileURL += EXECUTABLE_NAME;
395     }
396 
397     //------------------------------------------------
398     virtual void setUp()
399     {
400         temp_file_path_ = create_temp_file();
401         parameters_[1]  = temp_file_path_.pData;
402     }
403 
404     //------------------------------------------------
405     OUString create_temp_file()
406     {
407         OUString temp_file_url;
408         FileBase::RC rc = FileBase::createTempFile(0, 0, &temp_file_url);
409         CPPUNIT_ASSERT_MESSAGE("createTempFile failed", FileBase::E_None == rc);
410 
411         OUString temp_file_path;
412         rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path);
413         CPPUNIT_ASSERT_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None == rc);
414 
415         return temp_file_path;
416     }
417 
418    //------------------------------------------------
419     void read_child_environment(string_container_t* env_container)
420     {
421         OString temp_file_name = OUStringToOString(OUString(
422             parameters_[1]), osl_getThreadTextEncoding());
423         std::ifstream file(temp_file_name.getStr());
424 
425         CPPUNIT_ASSERT_MESSAGE
426         (
427             "I/O error, cannot open child environment file",
428             file.is_open()
429         );
430 
431         std::string line;
432         while (std::getline(file, line))
433             env_container->push_back(line);
434     }
435 
436     //------------------------------------------------
437     void dump_env(const string_container_t& env, OUString file_name)
438     {
439         OString fname = OUStringToOString(file_name, osl_getThreadTextEncoding());
440         std::ofstream file(fname.getStr());
441         std::ostream_iterator<std::string> oi(file, "\n");
442 		std::copy(env.begin(), env.end(), oi);
443     }
444 
445     //------------------------------------------------
446     // environment of the child process that was
447     // started. The child process writes his
448     // environment into a file
449     bool compare_environments()
450     {
451         string_container_t parent_env;
452         read_parent_environment(&parent_env);
453 
454         string_container_t child_env;
455 		read_child_environment(&child_env);
456 
457 		return ((parent_env.size() == child_env.size()) &&
458 		        (std::equal(child_env.begin(), child_env.end(), parent_env.begin())));
459     }
460 
461     //------------------------------------------------
462     // compare the equal environment parts and the
463     // different part of the child environment
464     bool compare_merged_environments(const string_container_t& different_env_vars)
465     {
466         string_container_t parent_env;
467         read_parent_environment(&parent_env);
468 
469         //remove the environment variables that we have changed
470         //in the child environment from the read parent environment
471         parent_env.erase(
472             std::remove_if(parent_env.begin(), parent_env.end(), exclude(different_env_vars)),
473             parent_env.end());
474 
475         //read the child environment and exclude the variables that
476         //are different
477         string_container_t child_env;
478         read_child_environment(&child_env);
479 
480         //partition the child environment into the variables that
481         //are different to the parent environment (they come first)
482         //and the variables that should be equal between parent
483         //and child environment
484         string_container_iter_t iter_logical_end =
485             std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars));
486 
487         string_container_t different_child_env_vars(child_env.begin(), iter_logical_end);
488         child_env.erase(child_env.begin(), iter_logical_end);
489 
490         bool common_env_size_equals    = (parent_env.size() == child_env.size());
491         bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin());
492 
493 		bool different_env_size_equals    = (different_child_env_vars.size() == different_env_vars.size());
494 		bool different_env_content_equals =
495 		    std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin());
496 
497         return (common_env_size_equals && common_env_content_equals &&
498                 different_env_size_equals && different_env_content_equals);
499     }
500 
501     //------------------------------------------------
502     // test that parent and child process have the
503     // same environment when osl_executeProcess will
504     // be called with out setting new environment
505     // variables
506    void osl_execProc_parent_equals_child_environment()
507     {
508         oslProcess process;
509         oslProcessError osl_error = osl_executeProcess(
510             suExecutableFileURL.pData,
511             parameters_,
512             parameters_count_,
513             osl_Process_NORMAL,
514             NULL,
515             suCWD.pData,
516             NULL,
517             0,
518             &process);
519 
520         CPPUNIT_ASSERT_MESSAGE
521         (
522             "osl_createProcess failed",
523             osl_error == osl_Process_E_None
524         );
525 
526         osl_error = ::osl_joinProcess(process);
527 
528         CPPUNIT_ASSERT_MESSAGE
529         (
530             "osl_joinProcess returned with failure",
531             osl_Process_E_None == osl_error
532         );
533 
534         osl_freeProcessHandle(process);
535 
536         CPPUNIT_ASSERT_MESSAGE
537         (
538             "Parent an child environment not equal",
539             compare_environments()
540         );
541     }
542 
543     //------------------------------------------------
544     #define ENV1 "PAT=a:\\"
545     #define ENV2 "PATHb=b:\\"
546     #define ENV3 "Patha=c:\\"
547     #define ENV4 "Patha=d:\\"
548 
549     void osl_execProc_merged_child_environment()
550     {
551         rtl_uString* child_env[4];
552         OUString env1 = OUString::createFromAscii(ENV1);
553         OUString env2 = OUString::createFromAscii(ENV2);
554         OUString env3 = OUString::createFromAscii(ENV3);
555         OUString env4 = OUString::createFromAscii(ENV4);
556 
557         child_env[0] = env1.pData;
558         child_env[1] = env2.pData;
559         child_env[2] = env3.pData;
560         child_env[3] = env4.pData;
561 
562         oslProcess process;
563         oslProcessError osl_error = osl_executeProcess(
564             suExecutableFileURL.pData,
565             parameters_,
566             parameters_count_,
567             osl_Process_NORMAL,
568             NULL,
569             suCWD.pData,
570             child_env,
571             sizeof(child_env)/sizeof(child_env[0]),
572             &process);
573 
574         CPPUNIT_ASSERT_MESSAGE
575         (
576             "osl_createProcess failed",
577             osl_error == osl_Process_E_None
578         );
579 
580         osl_error = ::osl_joinProcess(process);
581 
582         CPPUNIT_ASSERT_MESSAGE
583         (
584             "osl_joinProcess returned with failure",
585             osl_Process_E_None == osl_error
586         );
587 
588         osl_freeProcessHandle(process);
589 
590         string_container_t different_child_env_vars;
591         different_child_env_vars.push_back(ENV1);
592         different_child_env_vars.push_back(ENV2);
593         different_child_env_vars.push_back(ENV4);
594 
595         CPPUNIT_ASSERT_MESSAGE
596         (
597             "osl_execProc_merged_child_environment",
598             compare_merged_environments(different_child_env_vars)
599         );
600     }
601 
602     void osl_execProc_test_batch()
603     {
604         oslProcess process;
605         rtl::OUString suBatch = suCWD + rtl::OUString::createFromAscii("/") + rtl::OUString::createFromAscii("batch.bat");
606         oslProcessError osl_error = osl_executeProcess(
607             suBatch.pData,
608             NULL,
609             0,
610             osl_Process_NORMAL,
611             NULL,
612             suCWD.pData,
613             NULL,
614             0,
615             &process);
616 
617         CPPUNIT_ASSERT_MESSAGE
618         (
619             "osl_createProcess failed",
620             osl_error == osl_Process_E_None
621         );
622 
623         osl_error = ::osl_joinProcess(process);
624 
625         CPPUNIT_ASSERT_MESSAGE
626         (
627             "osl_joinProcess returned with failure",
628             osl_Process_E_None == osl_error
629         );
630 
631         osl_freeProcessHandle(process);
632     }
633 
634     void osl_execProc_exe_name_in_argument_list()
635     {
636         rtl_uString* params[3];
637 
638         params[0] = suExecutableFileURL.pData;
639         params[1] = env_param_.pData;
640         params[2] = temp_file_path_.pData;
641         oslProcess process;
642         oslProcessError osl_error = osl_executeProcess(
643             NULL,
644             params,
645             3,
646             osl_Process_NORMAL,
647             NULL,
648             suCWD.pData,
649             NULL,
650             0,
651             &process);
652 
653         CPPUNIT_ASSERT_MESSAGE
654         (
655             "osl_createProcess failed",
656             osl_error == osl_Process_E_None
657         );
658 
659         osl_error = ::osl_joinProcess(process);
660 
661         CPPUNIT_ASSERT_MESSAGE
662         (
663             "osl_joinProcess returned with failure",
664             osl_Process_E_None == osl_error
665         );
666 
667         osl_freeProcessHandle(process);
668     }
669 
670     CPPUNIT_TEST_SUITE(Test_osl_executeProcess);
671     CPPUNIT_TEST(osl_execProc_parent_equals_child_environment);
672     CPPUNIT_TEST(osl_execProc_merged_child_environment);
673     CPPUNIT_TEST(osl_execProc_test_batch);
674     CPPUNIT_TEST(osl_execProc_exe_name_in_argument_list);
675     CPPUNIT_TEST_SUITE_END();
676 };
677 
678 //#####################################
679 // register test suites
680 //CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_joinProcess,    "Test_osl_joinProcess");
681 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_executeProcess, "Test_osl_executeProcess");
682 
683 NOADDITIONAL;
684 
685