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