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