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