diff options
Diffstat (limited to 'sal/qa/osl/process/osl_process.cxx')
-rw-r--r-- | sal/qa/osl/process/osl_process.cxx | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/sal/qa/osl/process/osl_process.cxx b/sal/qa/osl/process/osl_process.cxx new file mode 100644 index 000000000000..1604a762c76f --- /dev/null +++ b/sal/qa/osl/process/osl_process.cxx @@ -0,0 +1,764 @@ +/* -*- 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#define t_print printf + +#include <osl/process.h> +#include <osl/file.hxx> +#include <osl/thread.h> +#include <rtl/ustring.hxx> +#include <unistd.h> +#include <signal.h> + +#include <stdio.h> +#include <stdlib.h> +#include <osl/module.hxx> +#include <sal/macros.h> + +#if ( defined WNT ) // Windows +# include <windows.h> +# include <tchar.h> +#endif + +#include "rtl/allocator.hxx" + +#include <iostream> +#include <fstream> +#include <vector> +#include <algorithm> +#include <iterator> +#include <string> + +#ifdef UNX +#if defined( MACOSX ) +# include <crt_externs.h> +# 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 ::rtl::OUString; +using ::rtl::OUStringToOString; +using ::rtl::OString; + +/** 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<std::string, rtl::Allocator<std::string> > 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<std::string, bool> +{ +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_; +}; + +namespace +{ + class starts_with + : public std::unary_function<const std::string&, bool> + { + private: + const std::string m_rString; + public: + starts_with(const char *pString) : m_rString(pString) {} + bool operator()(const std::string &rEntry) const + { + return rEntry.find(m_rString) == 0; + } + }; + + void tidy_container(string_container_t &env_container) + { + //sort them because there are no guarantees to ordering + std::sort(env_container.begin(), env_container.end()); + //remove LD_PRELOAD because valgrind injects that into the + //parent process + env_container.erase(std::remove_if(env_container.begin(), env_container.end(), + starts_with("LD_PRELOAD=")), env_container.end()); + } +} + +#ifdef WNT + void read_parent_environment(string_container_t* env_container) + { + LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings()); + LPTSTR p = env; + + while (size_t l = _tcslen(p)) + { + env_container->push_back(std::string(p)); + p += l + 1; + } + FreeEnvironmentStrings(env); + tidy_container(*env_container); + } +#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])); + tidy_container(*env_container); + } +#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); + tidy_container(*env_container); + } + + //------------------------------------------------ + // 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()); + +#if OSL_DEBUG_LEVEL > 1 + for (string_container_t::const_iterator iter = different_env_vars.begin(), end = different_env_vars.end(); iter != end; ++iter) + std::cerr << "different should be: " << *iter << std::endl; +#endif + + +#if OSL_DEBUG_LEVEL > 1 + for (string_container_t::const_iterator iter = different_child_env_vars.begin(), end = different_child_env_vars.end(); iter != end; ++iter) + std::cerr << "different are: " << *iter << std::endl; +#endif + + 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 and 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: */ |