xref: /aoo42x/main/sal/qa/osl/process/osl_process.cxx (revision 44e8df1f)
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