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 //########################################
OUString_to_std_string(const rtl::OUString & oustr)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 */
printUString(const::rtl::OUString & str)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 */
getExecutablePath(void)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
Test_osl_joinProcess()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
TEST_F(Test_osl_joinProcess,osl_joinProcessWithTimeout_timeout_failure)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
TEST_F(Test_osl_joinProcess,osl_joinProcessWithTimeout_without_timeout_failure)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
TEST_F(Test_osl_joinProcess,osl_joinProcessWithTimeout_infinite)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
TEST_F(Test_osl_joinProcess,osl_joinProcess)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 //------------------------------------------------
exclude(const string_container_t & exclude_list)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 //------------------------------------------------
operator ()(const std::string & env_var) const271 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"
env_var_name(const std::string & env_var) const284 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
read_parent_environment(string_container_t * env_container)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;
read_parent_environment(string_container_t * env_container)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
Test_osl_executeProcess()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 //------------------------------------------------
SetUp()349 virtual void SetUp()
350 {
351 temp_file_path_ = create_temp_file();
352 parameters_[1] = temp_file_path_.pData;
353 }
354
355 //------------------------------------------------
create_temp_file()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 //------------------------------------------------
read_child_environment(string_container_t * env_container)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 //------------------------------------------------
dump_env(const string_container_t & env,OUString file_name)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
compare_environments()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
compare_merged_environments(const string_container_t & different_env_vars)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
TEST_F(Test_osl_executeProcess,osl_execProc_parent_equals_child_environment)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
TEST_F(Test_osl_executeProcess,osl_execProc_merged_child_environment)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
TEST_F(Test_osl_executeProcess,osl_execProc_test_batch)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
TEST_F(Test_osl_executeProcess,osl_execProc_exe_name_in_argument_list)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
main(int argc,char ** argv)578 int main(int argc, char **argv)
579 {
580 ::testing::InitGoogleTest(&argc, argv);
581 return RUN_ALL_TESTS();
582 }
583