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