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