1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: osl_process.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
34 #include <cppunit/simpleheader.hxx>
35 #include <osl/process.h>
36 #include <osl/file.hxx>
37 #include <osl/thread.h>
38 #include <rtl/ustring.hxx>
44 #include <osl/module.hxx>
46 #if ( defined WNT ) // Windows
47 #include <tools/prewin.h>
48 # define WIN32_LEAN_AND_MEAN
49 // # include <windows.h>
51 #include <tools/postwin.h>
54 #include "rtl/allocator.hxx"
63 #if defined(WNT) || defined(OS2)
64 const rtl::OUString EXECUTABLE_NAME
= rtl::OUString::createFromAscii("osl_process_child.exe");
66 const rtl::OUString EXECUTABLE_NAME
= rtl::OUString::createFromAscii("osl_process_child");
70 //########################################
71 std::string
OUString_to_std_string(const rtl::OUString
& oustr
)
73 rtl::OString ostr
= rtl::OUStringToOString(oustr
, osl_getThreadTextEncoding());
74 return std::string(ostr
.getStr());
77 //########################################
81 /** print a UNI_CODE String.
83 inline void printUString( const ::rtl::OUString
& str
)
87 t_print("#printUString_u# " );
88 aString
= ::rtl::OUStringToOString( str
, RTL_TEXTENCODING_ASCII_US
);
89 t_print("%s\n", aString
.getStr( ) );
94 inline ::rtl::OUString
getExecutablePath( void )
96 ::rtl::OUString dirPath
;
97 osl::Module::getUrlFromAddress( ( void* ) &getExecutablePath
, dirPath
);
98 dirPath
= dirPath
.copy( 0, dirPath
.lastIndexOf('/') );
99 dirPath
= dirPath
.copy( 0, dirPath
.lastIndexOf('/') + 1);
100 dirPath
+= rtl::OUString::createFromAscii("bin");
104 //rtl::OUString CWD = getExecutablePath();
106 //########################################
107 class Test_osl_joinProcess
: public CppUnit::TestFixture
109 const OUString join_param_
;
110 const OUString wait_time_
;
112 OUString suExecutableFileURL
;
114 rtl_uString
* parameters_
[2];
115 int parameters_count_
;
119 Test_osl_joinProcess() :
120 join_param_(OUString::createFromAscii("-join")),
121 wait_time_(OUString::createFromAscii("1")),
124 parameters_
[0] = join_param_
.pData
;
125 parameters_
[1] = wait_time_
.pData
;
126 suCWD
= getExecutablePath();
127 suExecutableFileURL
= suCWD
;
128 suExecutableFileURL
+= rtl::OUString::createFromAscii("/");
129 suExecutableFileURL
+= EXECUTABLE_NAME
;
132 /*-------------------------------------
133 Start a process and join with this
134 process specify a timeout so that
135 osl_joinProcessWithTimeout returns
136 osl_Process_E_TimedOut
137 -------------------------------------*/
139 void osl_joinProcessWithTimeout_timeout_failure()
142 oslProcessError osl_error
= osl_executeProcess(
143 suExecutableFileURL
.pData
,
147 osl_getCurrentSecurity(),
153 CPPUNIT_ASSERT_MESSAGE
155 "osl_createProcess failed",
156 osl_error
== osl_Process_E_None
163 osl_error
= osl_joinProcessWithTimeout(process
, &timeout
);
165 CPPUNIT_ASSERT_MESSAGE
167 "osl_joinProcessWithTimeout returned without timeout failure",
168 osl_Process_E_TimedOut
== osl_error
171 osl_error
= osl_terminateProcess(process
);
173 CPPUNIT_ASSERT_MESSAGE
175 "osl_terminateProcess failed",
176 osl_error
== osl_Process_E_None
179 osl_freeProcessHandle(process
);
182 /*-------------------------------------
183 Start a process and join with this
184 process specify a timeout so that
185 osl_joinProcessWithTimeout returns
187 -------------------------------------*/
189 void osl_joinProcessWithTimeout_without_timeout_failure()
192 oslProcessError osl_error
= osl_executeProcess(
193 suExecutableFileURL
.pData
,
197 osl_getCurrentSecurity(),
203 CPPUNIT_ASSERT_MESSAGE
205 "osl_createProcess failed",
206 osl_error
== osl_Process_E_None
210 timeout
.Seconds
= 10;
213 osl_error
= osl_joinProcessWithTimeout(process
, &timeout
);
215 CPPUNIT_ASSERT_MESSAGE
217 "osl_joinProcessWithTimeout returned with failure",
218 osl_Process_E_None
== osl_error
221 osl_freeProcessHandle(process
);
224 /*-------------------------------------
225 Start a process and join with this
226 process specify an infinite timeout
227 -------------------------------------*/
229 void osl_joinProcessWithTimeout_infinite()
232 oslProcessError osl_error
= osl_executeProcess(
233 suExecutableFileURL
.pData
,
237 osl_getCurrentSecurity(),
243 CPPUNIT_ASSERT_MESSAGE
245 "osl_createProcess failed",
246 osl_error
== osl_Process_E_None
249 osl_error
= osl_joinProcessWithTimeout(process
, NULL
);
251 CPPUNIT_ASSERT_MESSAGE
253 "osl_joinProcessWithTimeout returned with failure",
254 osl_Process_E_None
== osl_error
257 osl_freeProcessHandle(process
);
260 /*-------------------------------------
261 Start a process and join with this
262 process using osl_joinProcess
263 -------------------------------------*/
265 void osl_joinProcess()
268 oslProcessError osl_error
= osl_executeProcess(
269 suExecutableFileURL
.pData
,
273 osl_getCurrentSecurity(),
279 CPPUNIT_ASSERT_MESSAGE
281 "osl_createProcess failed",
282 osl_error
== osl_Process_E_None
285 osl_error
= ::osl_joinProcess(process
);
287 CPPUNIT_ASSERT_MESSAGE
289 "osl_joinProcess returned with failure",
290 osl_Process_E_None
== osl_error
293 osl_freeProcessHandle(process
);
296 CPPUNIT_TEST_SUITE(Test_osl_joinProcess
);
297 CPPUNIT_TEST(osl_joinProcessWithTimeout_timeout_failure
);
298 CPPUNIT_TEST(osl_joinProcessWithTimeout_without_timeout_failure
);
299 CPPUNIT_TEST(osl_joinProcessWithTimeout_infinite
);
300 CPPUNIT_TEST(osl_joinProcess
);
301 CPPUNIT_TEST_SUITE_END();
304 //#########################################################
306 typedef std::vector
<std::string
, rtl::Allocator
<std::string
> > string_container_t
;
307 typedef string_container_t::const_iterator string_container_const_iter_t
;
308 typedef string_container_t::iterator string_container_iter_t
;
310 //#########################################################
311 class exclude
: public std::unary_function
<std::string
, bool>
314 //------------------------------------------------
315 exclude(const string_container_t
& exclude_list
)
317 string_container_const_iter_t iter
= exclude_list
.begin();
318 string_container_const_iter_t iter_end
= exclude_list
.end();
319 for (/**/; iter
!= iter_end
; ++iter
)
320 exclude_list_
.push_back(env_var_name(*iter
));
323 //------------------------------------------------
324 bool operator() (const std::string
& env_var
) const
326 return (exclude_list_
.end() !=
328 exclude_list_
.begin(),
330 env_var_name(env_var
)));
334 //-------------------------------------------------
335 // extract the name from an environment variable
336 // that is given in the form "NAME=VALUE"
337 std::string
env_var_name(const std::string
& env_var
) const
339 std::string::size_type pos_equal_sign
=
340 env_var
.find_first_of("=");
342 if (std::string::npos
!= pos_equal_sign
)
343 return std::string(env_var
, 0, pos_equal_sign
);
345 return std::string();
349 string_container_t exclude_list_
;
353 void read_parent_environment(string_container_t
* env_container
)
355 LPTSTR env
= reinterpret_cast<LPTSTR
>(GetEnvironmentStrings());
358 while (size_t l
= _tcslen(p
))
360 env_container
->push_back(std::string(p
));
363 FreeEnvironmentStrings(env
);
366 extern char** environ
;
367 void read_parent_environment(string_container_t
* env_container
)
369 for (int i
= 0; NULL
!= environ
[i
]; i
++)
370 env_container
->push_back(std::string(environ
[i
]));
374 //#########################################################
375 class Test_osl_executeProcess
: public CppUnit::TestFixture
377 const OUString env_param_
;
379 OUString temp_file_path_
;
380 rtl_uString
* parameters_
[2];
381 int parameters_count_
;
383 OUString suExecutableFileURL
;
387 //------------------------------------------------
389 Test_osl_executeProcess() :
390 env_param_(OUString::createFromAscii("-env")),
393 parameters_
[0] = env_param_
.pData
;
394 suCWD
= getExecutablePath();
395 suExecutableFileURL
= suCWD
;
396 suExecutableFileURL
+= rtl::OUString::createFromAscii("/");
397 suExecutableFileURL
+= EXECUTABLE_NAME
;
400 //------------------------------------------------
403 temp_file_path_
= create_temp_file();
404 parameters_
[1] = temp_file_path_
.pData
;
407 //------------------------------------------------
408 OUString
create_temp_file()
410 OUString temp_file_url
;
411 FileBase::RC rc
= FileBase::createTempFile(0, 0, &temp_file_url
);
412 CPPUNIT_ASSERT_MESSAGE("createTempFile failed", FileBase::E_None
== rc
);
414 OUString temp_file_path
;
415 rc
= FileBase::getSystemPathFromFileURL(temp_file_url
, temp_file_path
);
416 CPPUNIT_ASSERT_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None
== rc
);
418 return temp_file_path
;
421 //------------------------------------------------
422 void read_child_environment(string_container_t
* env_container
)
424 OString temp_file_name
= OUStringToOString(OUString(
425 parameters_
[1]), osl_getThreadTextEncoding());
426 std::ifstream
file(temp_file_name
.getStr());
428 CPPUNIT_ASSERT_MESSAGE
430 "I/O error, cannot open child environment file",
435 while (std::getline(file
, line
))
436 env_container
->push_back(line
);
439 //------------------------------------------------
440 void dump_env(const string_container_t
& env
, OUString file_name
)
442 OString fname
= OUStringToOString(file_name
, osl_getThreadTextEncoding());
443 std::ofstream
file(fname
.getStr());
444 std::ostream_iterator
<std::string
> oi(file
, "\n");
445 std::copy(env
.begin(), env
.end(), oi
);
448 //------------------------------------------------
449 // environment of the child process that was
450 // started. The child process writes his
451 // environment into a file
452 bool compare_environments()
454 string_container_t parent_env
;
455 read_parent_environment(&parent_env
);
457 string_container_t child_env
;
458 read_child_environment(&child_env
);
460 return ((parent_env
.size() == child_env
.size()) &&
461 (std::equal(child_env
.begin(), child_env
.end(), parent_env
.begin())));
464 //------------------------------------------------
465 // compare the equal environment parts and the
466 // different part of the child environment
467 bool compare_merged_environments(const string_container_t
& different_env_vars
)
469 string_container_t parent_env
;
470 read_parent_environment(&parent_env
);
472 //remove the environment variables that we have changed
473 //in the child environment from the read parent environment
475 std::remove_if(parent_env
.begin(), parent_env
.end(), exclude(different_env_vars
)),
478 //read the child environment and exclude the variables that
480 string_container_t child_env
;
481 read_child_environment(&child_env
);
483 //partition the child environment into the variables that
484 //are different to the parent environment (they come first)
485 //and the variables that should be equal between parent
486 //and child environment
487 string_container_iter_t iter_logical_end
=
488 std::stable_partition(child_env
.begin(), child_env
.end(), exclude(different_env_vars
));
490 string_container_t
different_child_env_vars(child_env
.begin(), iter_logical_end
);
491 child_env
.erase(child_env
.begin(), iter_logical_end
);
493 bool common_env_size_equals
= (parent_env
.size() == child_env
.size());
494 bool common_env_content_equals
= std::equal(child_env
.begin(), child_env
.end(), parent_env
.begin());
496 bool different_env_size_equals
= (different_child_env_vars
.size() == different_env_vars
.size());
497 bool different_env_content_equals
=
498 std::equal(different_env_vars
.begin(), different_env_vars
.end(), different_child_env_vars
.begin());
500 return (common_env_size_equals
&& common_env_content_equals
&&
501 different_env_size_equals
&& different_env_content_equals
);
504 //------------------------------------------------
505 // test that parent and child process have the
506 // same environment when osl_executeProcess will
507 // be called with out setting new environment
509 void osl_execProc_parent_equals_child_environment()
512 oslProcessError osl_error
= osl_executeProcess(
513 suExecutableFileURL
.pData
,
523 CPPUNIT_ASSERT_MESSAGE
525 "osl_createProcess failed",
526 osl_error
== osl_Process_E_None
529 osl_error
= ::osl_joinProcess(process
);
531 CPPUNIT_ASSERT_MESSAGE
533 "osl_joinProcess returned with failure",
534 osl_Process_E_None
== osl_error
537 osl_freeProcessHandle(process
);
539 CPPUNIT_ASSERT_MESSAGE
541 "Parent an child environment not equal",
542 compare_environments()
546 //------------------------------------------------
547 #define ENV1 "PAT=a:\\"
548 #define ENV2 "PATHb=b:\\"
549 #define ENV3 "Patha=c:\\"
550 #define ENV4 "Patha=d:\\"
552 void osl_execProc_merged_child_environment()
554 rtl_uString
* child_env
[4];
555 OUString env1
= OUString::createFromAscii(ENV1
);
556 OUString env2
= OUString::createFromAscii(ENV2
);
557 OUString env3
= OUString::createFromAscii(ENV3
);
558 OUString env4
= OUString::createFromAscii(ENV4
);
560 child_env
[0] = env1
.pData
;
561 child_env
[1] = env2
.pData
;
562 child_env
[2] = env3
.pData
;
563 child_env
[3] = env4
.pData
;
566 oslProcessError osl_error
= osl_executeProcess(
567 suExecutableFileURL
.pData
,
574 sizeof(child_env
)/sizeof(child_env
[0]),
577 CPPUNIT_ASSERT_MESSAGE
579 "osl_createProcess failed",
580 osl_error
== osl_Process_E_None
583 osl_error
= ::osl_joinProcess(process
);
585 CPPUNIT_ASSERT_MESSAGE
587 "osl_joinProcess returned with failure",
588 osl_Process_E_None
== osl_error
591 osl_freeProcessHandle(process
);
593 string_container_t different_child_env_vars
;
594 different_child_env_vars
.push_back(ENV1
);
595 different_child_env_vars
.push_back(ENV2
);
596 different_child_env_vars
.push_back(ENV4
);
598 CPPUNIT_ASSERT_MESSAGE
600 "osl_execProc_merged_child_environment",
601 compare_merged_environments(different_child_env_vars
)
605 void osl_execProc_test_batch()
608 rtl::OUString suBatch
= suCWD
+ rtl::OUString::createFromAscii("/") + rtl::OUString::createFromAscii("batch.bat");
609 oslProcessError osl_error
= osl_executeProcess(
620 CPPUNIT_ASSERT_MESSAGE
622 "osl_createProcess failed",
623 osl_error
== osl_Process_E_None
626 osl_error
= ::osl_joinProcess(process
);
628 CPPUNIT_ASSERT_MESSAGE
630 "osl_joinProcess returned with failure",
631 osl_Process_E_None
== osl_error
634 osl_freeProcessHandle(process
);
637 void osl_execProc_exe_name_in_argument_list()
639 rtl_uString
* params
[3];
641 params
[0] = suExecutableFileURL
.pData
;
642 params
[1] = env_param_
.pData
;
643 params
[2] = temp_file_path_
.pData
;
645 oslProcessError osl_error
= osl_executeProcess(
656 CPPUNIT_ASSERT_MESSAGE
658 "osl_createProcess failed",
659 osl_error
== osl_Process_E_None
662 osl_error
= ::osl_joinProcess(process
);
664 CPPUNIT_ASSERT_MESSAGE
666 "osl_joinProcess returned with failure",
667 osl_Process_E_None
== osl_error
670 osl_freeProcessHandle(process
);
673 CPPUNIT_TEST_SUITE(Test_osl_executeProcess
);
674 CPPUNIT_TEST(osl_execProc_parent_equals_child_environment
);
675 CPPUNIT_TEST(osl_execProc_merged_child_environment
);
676 CPPUNIT_TEST(osl_execProc_test_batch
);
677 CPPUNIT_TEST(osl_execProc_exe_name_in_argument_list
);
678 CPPUNIT_TEST_SUITE_END();
681 //#####################################
682 // register test suites
683 //CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_joinProcess, "Test_osl_joinProcess");
684 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_executeProcess
, "Test_osl_executeProcess");