blob: bc6669b3387a1257435837b518f3154cba01f27b [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
#include <testshl/simpleheader.hxx>
#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>
#if ( defined WNT ) // Windows
#include <tools/prewin.h>
# define WIN32_LEAN_AND_MEAN
// # include <windows.h>
# include <tchar.h>
#include <tools/postwin.h>
#endif
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#if defined(WNT) || defined(OS2)
const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child.exe");
#else
const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("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::createFromAscii("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::createFromAscii("-join")),
wait_time_(OUString::createFromAscii("1")),
parameters_count_(2)
{
parameters_[0] = join_param_.pData;
parameters_[1] = wait_time_.pData;
suCWD = getExecutablePath();
suExecutableFileURL = suCWD;
suExecutableFileURL += rtl::OUString::createFromAscii("/");
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> 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_;
};
#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);
}
#else
extern char** environ;
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_path_;
rtl_uString* parameters_[2];
int parameters_count_;
OUString suCWD;
OUString suExecutableFileURL;
public:
//------------------------------------------------
// ctor
Test_osl_executeProcess() :
env_param_(OUString::createFromAscii("-env")),
parameters_count_(2)
{
parameters_[0] = env_param_.pData;
suCWD = getExecutablePath();
suExecutableFileURL = suCWD;
suExecutableFileURL += rtl::OUString::createFromAscii("/");
suExecutableFileURL += EXECUTABLE_NAME;
}
//------------------------------------------------
virtual void setUp()
{
temp_file_path_ = create_temp_file();
parameters_[1] = temp_file_path_.pData;
}
//------------------------------------------------
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))
env_container->push_back(line);
}
//------------------------------------------------
void dump_env(const string_container_t& env, OUString file_name)
{
OString fname = OUStringToOString(file_name, osl_getThreadTextEncoding());
std::ofstream file(fname.getStr());
std::ostream_iterator<std::string> oi(file, "\n");
std::copy(env.begin(), env.end(), oi);
}
//------------------------------------------------
// 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);
//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());
//read the child environment and exclude the variables that
//are different
string_container_t child_env;
read_child_environment(&child_env);
//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);
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 = OUString::createFromAscii(ENV1);
OUString env2 = OUString::createFromAscii(ENV2);
OUString env3 = OUString::createFromAscii(ENV3);
OUString env4 = OUString::createFromAscii(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,
sizeof(child_env)/sizeof(child_env[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);
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;
rtl::OUString suBatch = suCWD + rtl::OUString::createFromAscii("/") + rtl::OUString::createFromAscii("batch.bat");
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);
CPPUNIT_TEST(osl_execProc_parent_equals_child_environment);
CPPUNIT_TEST(osl_execProc_merged_child_environment);
CPPUNIT_TEST(osl_execProc_test_batch);
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_NAMED_REGISTRATION(Test_osl_executeProcess, "Test_osl_executeProcess");
NOADDITIONAL;