/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sal.hxx" #include #include #include #define t_print printf #include #include #include #include #include #include #include #include #include #include #if ( defined WNT ) // Windows #include # include #include #endif #include "rtl/allocator.hxx" #include #include #include #include #include #include #ifdef UNX #if defined( MACOSX ) # include # define environ (*_NSGetEnviron()) # else extern char** environ; # endif #endif #if defined(WNT) || defined(OS2) const rtl::OUString EXECUTABLE_NAME (RTL_CONSTASCII_USTRINGPARAM("osl_process_child.exe")); #else const rtl::OUString EXECUTABLE_NAME (RTL_CONSTASCII_USTRINGPARAM("osl_process_child")); #endif //######################################## std::string OUString_to_std_string(const rtl::OUString& oustr) { rtl::OString ostr = rtl::OUStringToOString(oustr, osl_getThreadTextEncoding()); return std::string(ostr.getStr()); } //######################################## using namespace osl; using namespace rtl; /** print a UNI_CODE String. */ inline void printUString( const ::rtl::OUString & str ) { rtl::OString aString; t_print("#printUString_u# " ); aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ); t_print("%s\n", aString.getStr( ) ); } /** get binary Path. */ inline ::rtl::OUString getExecutablePath( void ) { ::rtl::OUString dirPath; osl::Module::getUrlFromAddress( ( void* ) &getExecutablePath, dirPath ); dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') ); dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1); dirPath += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bin")); return dirPath; } //rtl::OUString CWD = getExecutablePath(); //######################################## class Test_osl_joinProcess : public CppUnit::TestFixture { const OUString join_param_; const OUString wait_time_; OUString suCWD; OUString suExecutableFileURL; rtl_uString* parameters_[2]; int parameters_count_; public: Test_osl_joinProcess() : join_param_(OUString(RTL_CONSTASCII_USTRINGPARAM("-join"))), wait_time_(OUString(RTL_CONSTASCII_USTRINGPARAM("1"))), parameters_count_(2) { parameters_[0] = join_param_.pData; parameters_[1] = wait_time_.pData; suCWD = getExecutablePath(); suExecutableFileURL = suCWD; suExecutableFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); suExecutableFileURL += EXECUTABLE_NAME; } /*------------------------------------- Start a process and join with this process specify a timeout so that osl_joinProcessWithTimeout returns osl_Process_E_TimedOut -------------------------------------*/ void osl_joinProcessWithTimeout_timeout_failure() { oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, osl_getCurrentSecurity(), suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); TimeValue timeout; timeout.Seconds = 1; timeout.Nanosec = 0; osl_error = osl_joinProcessWithTimeout(process, &timeout); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcessWithTimeout returned without timeout failure", osl_Process_E_TimedOut == osl_error ); osl_error = osl_terminateProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_terminateProcess failed", osl_error == osl_Process_E_None ); osl_freeProcessHandle(process); } /*------------------------------------- Start a process and join with this process specify a timeout so that osl_joinProcessWithTimeout returns osl_Process_E_None -------------------------------------*/ void osl_joinProcessWithTimeout_without_timeout_failure() { oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, osl_getCurrentSecurity(), suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); TimeValue timeout; timeout.Seconds = 10; timeout.Nanosec = 0; osl_error = osl_joinProcessWithTimeout(process, &timeout); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcessWithTimeout returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); } /*------------------------------------- Start a process and join with this process specify an infinite timeout -------------------------------------*/ void osl_joinProcessWithTimeout_infinite() { oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, osl_getCurrentSecurity(), suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = osl_joinProcessWithTimeout(process, NULL); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcessWithTimeout returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); } /*------------------------------------- Start a process and join with this process using osl_joinProcess -------------------------------------*/ void osl_joinProcess() { oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, osl_getCurrentSecurity(), suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = ::osl_joinProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcess returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); } CPPUNIT_TEST_SUITE(Test_osl_joinProcess); CPPUNIT_TEST(osl_joinProcessWithTimeout_timeout_failure); CPPUNIT_TEST(osl_joinProcessWithTimeout_without_timeout_failure); CPPUNIT_TEST(osl_joinProcessWithTimeout_infinite); CPPUNIT_TEST(osl_joinProcess); CPPUNIT_TEST_SUITE_END(); }; //######################################################### typedef std::vector > string_container_t; typedef string_container_t::const_iterator string_container_const_iter_t; typedef string_container_t::iterator string_container_iter_t; //######################################################### class exclude : public std::unary_function { public: //------------------------------------------------ exclude(const string_container_t& exclude_list) { string_container_const_iter_t iter = exclude_list.begin(); string_container_const_iter_t iter_end = exclude_list.end(); for (/**/; iter != iter_end; ++iter) exclude_list_.push_back(env_var_name(*iter)); } //------------------------------------------------ bool operator() (const std::string& env_var) const { return (exclude_list_.end() != std::find( exclude_list_.begin(), exclude_list_.end(), env_var_name(env_var))); } private: //------------------------------------------------- // extract the name from an environment variable // that is given in the form "NAME=VALUE" std::string env_var_name(const std::string& env_var) const { std::string::size_type pos_equal_sign = env_var.find_first_of("="); if (std::string::npos != pos_equal_sign) return std::string(env_var, 0, pos_equal_sign); return std::string(); } private: string_container_t exclude_list_; }; #ifdef WNT void read_parent_environment(string_container_t* env_container) { LPTSTR env = reinterpret_cast(GetEnvironmentStrings()); LPTSTR p = env; while (size_t l = _tcslen(p)) { env_container->push_back(std::string(p)); p += l + 1; } FreeEnvironmentStrings(env); } #else void read_parent_environment(string_container_t* env_container) { for (int i = 0; NULL != environ[i]; i++) env_container->push_back(std::string(environ[i])); } #endif //######################################################### class Test_osl_executeProcess : public CppUnit::TestFixture { const OUString env_param_; OUString temp_file_url_; OUString temp_file_path_; rtl_uString* parameters_[2]; int parameters_count_; OUString suCWD; OUString suExecutableFileURL; public: //------------------------------------------------ // ctor Test_osl_executeProcess() : env_param_(OUString(RTL_CONSTASCII_USTRINGPARAM("-env"))), parameters_count_(2) { parameters_[0] = env_param_.pData; suCWD = getExecutablePath(); suExecutableFileURL = suCWD; suExecutableFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); suExecutableFileURL += EXECUTABLE_NAME; } //------------------------------------------------ virtual void setUp() { temp_file_path_ = create_temp_file(temp_file_url_); parameters_[1] = temp_file_path_.pData; } virtual void tearDown() { osl::File::remove(temp_file_url_); } //------------------------------------------------ OUString create_temp_file(OUString &temp_file_url) { FileBase::RC rc = FileBase::createTempFile(0, 0, &temp_file_url); CPPUNIT_ASSERT_MESSAGE("createTempFile failed", FileBase::E_None == rc); OUString temp_file_path; rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path); CPPUNIT_ASSERT_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None == rc); return temp_file_path; } //------------------------------------------------ void read_child_environment(string_container_t* env_container) { OString temp_file_name = OUStringToOString(OUString( parameters_[1]), osl_getThreadTextEncoding()); std::ifstream file(temp_file_name.getStr()); CPPUNIT_ASSERT_MESSAGE ( "I/O error, cannot open child environment file", file.is_open() ); std::string line; while (std::getline(file, line, '\0')) env_container->push_back(line); } //------------------------------------------------ // environment of the child process that was // started. The child process writes his // environment into a file bool compare_environments() { string_container_t parent_env; read_parent_environment(&parent_env); string_container_t child_env; read_child_environment(&child_env); return ((parent_env.size() == child_env.size()) && (std::equal(child_env.begin(), child_env.end(), parent_env.begin()))); } //------------------------------------------------ // compare the equal environment parts and the // different part of the child environment bool compare_merged_environments(const string_container_t& different_env_vars) { string_container_t parent_env; read_parent_environment(&parent_env); #if OSL_DEBUG_LEVEL > 1 for (string_container_t::const_iterator iter = parent_env.begin(), end = parent_env.end(); iter != end; ++iter) std::cerr << "initially parent env: " << *iter << std::endl; #endif //remove the environment variables that we have changed //in the child environment from the read parent environment parent_env.erase( std::remove_if(parent_env.begin(), parent_env.end(), exclude(different_env_vars)), parent_env.end()); #if OSL_DEBUG_LEVEL > 1 for (string_container_t::const_iterator iter = parent_env.begin(), end = parent_env.end(); iter != end; ++iter) std::cerr << "stripped parent env: " << *iter << std::endl; #endif //read the child environment and exclude the variables that //are different string_container_t child_env; read_child_environment(&child_env); #if OSL_DEBUG_LEVEL > 1 for (string_container_t::const_iterator iter = child_env.begin(), end = child_env.end(); iter != end; ++iter) std::cerr << "initial child env: " << *iter << std::endl; #endif //partition the child environment into the variables that //are different to the parent environment (they come first) //and the variables that should be equal between parent //and child environment string_container_iter_t iter_logical_end = std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars)); string_container_t different_child_env_vars(child_env.begin(), iter_logical_end); child_env.erase(child_env.begin(), iter_logical_end); #if OSL_DEBUG_LEVEL > 1 for (string_container_t::const_iterator iter = child_env.begin(), end = child_env.end(); iter != end; ++iter) std::cerr << "stripped child env: " << *iter << std::endl; #endif bool common_env_size_equals = (parent_env.size() == child_env.size()); bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin()); bool different_env_size_equals = (different_child_env_vars.size() == different_env_vars.size()); bool different_env_content_equals = std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin()); return (common_env_size_equals && common_env_content_equals && different_env_size_equals && different_env_content_equals); } //------------------------------------------------ // test that parent and child process have the // same environment when osl_executeProcess will // be called with out setting new environment // variables void osl_execProc_parent_equals_child_environment() { oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, NULL, suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = ::osl_joinProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcess returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); CPPUNIT_ASSERT_MESSAGE ( "Parent an child environment not equal", compare_environments() ); } //------------------------------------------------ #define ENV1 "PAT=a:\\" #define ENV2 "PATHb=b:\\" #define ENV3 "Patha=c:\\" #define ENV4 "Patha=d:\\" void osl_execProc_merged_child_environment() { rtl_uString* child_env[4]; OUString env1(RTL_CONSTASCII_USTRINGPARAM(ENV1)); OUString env2(RTL_CONSTASCII_USTRINGPARAM(ENV2)); OUString env3(RTL_CONSTASCII_USTRINGPARAM(ENV3)); OUString env4(RTL_CONSTASCII_USTRINGPARAM(ENV4)); child_env[0] = env1.pData; child_env[1] = env2.pData; child_env[2] = env3.pData; child_env[3] = env4.pData; oslProcess process; oslProcessError osl_error = osl_executeProcess( suExecutableFileURL.pData, parameters_, parameters_count_, osl_Process_NORMAL, NULL, suCWD.pData, child_env, SAL_N_ELEMENTS(child_env), &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = ::osl_joinProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcess returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); string_container_t different_child_env_vars; different_child_env_vars.push_back(ENV1); different_child_env_vars.push_back(ENV2); different_child_env_vars.push_back(ENV4); CPPUNIT_ASSERT_MESSAGE ( "osl_execProc_merged_child_environment", compare_merged_environments(different_child_env_vars) ); } void osl_execProc_test_batch() { oslProcess process; #if defined(WNT) || defined(OS2) rtl::OUString suBatch = suCWD + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("batch.bat")); #else rtl::OUString suBatch = suCWD + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("batch.sh")); #endif oslProcessError osl_error = osl_executeProcess( suBatch.pData, NULL, 0, osl_Process_NORMAL, NULL, suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = ::osl_joinProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcess returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); } void osl_execProc_exe_name_in_argument_list() { rtl_uString* params[3]; params[0] = suExecutableFileURL.pData; params[1] = env_param_.pData; params[2] = temp_file_path_.pData; oslProcess process; oslProcessError osl_error = osl_executeProcess( NULL, params, 3, osl_Process_NORMAL, NULL, suCWD.pData, NULL, 0, &process); CPPUNIT_ASSERT_MESSAGE ( "osl_createProcess failed", osl_error == osl_Process_E_None ); osl_error = ::osl_joinProcess(process); CPPUNIT_ASSERT_MESSAGE ( "osl_joinProcess returned with failure", osl_Process_E_None == osl_error ); osl_freeProcessHandle(process); } CPPUNIT_TEST_SUITE(Test_osl_executeProcess); //TODO: Repair these under windows. #ifndef WNT CPPUNIT_TEST(osl_execProc_parent_equals_child_environment); CPPUNIT_TEST(osl_execProc_merged_child_environment); #endif ///TODO: Repair makefile to get the batch.sh, batch.bat copied to $(BIN) for test execution // CPPUNIT_TEST(osl_execProc_test_batch); ///TODO: Repair test (or tested function ;-) - test fails. // CPPUNIT_TEST(osl_execProc_exe_name_in_argument_list); CPPUNIT_TEST_SUITE_END(); }; //##################################### // register test suites //CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_joinProcess, "Test_osl_joinProcess"); CPPUNIT_TEST_SUITE_REGISTRATION(Test_osl_executeProcess); CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */