0a355af0f62986450474d8160f49ef77d767f206
[platform/upstream/nodejs.git] / deps / uv / test / test-spawn.c
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 #include "uv.h"
23 #include "task.h"
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifndef _WIN32
30 #include <unistd.h>
31 #endif
32
33
34 static int close_cb_called;
35 static int exit_cb_called;
36 static uv_process_t process;
37 static uv_timer_t timer;
38 static uv_process_options_t options;
39 static char exepath[1024];
40 static size_t exepath_size = 1024;
41 static char* args[3];
42 static int no_term_signal;
43
44 #define OUTPUT_SIZE 1024
45 static char output[OUTPUT_SIZE];
46 static int output_used;
47
48
49 static void close_cb(uv_handle_t* handle) {
50   printf("close_cb\n");
51   close_cb_called++;
52 }
53
54 static void exit_cb(uv_process_t* process,
55                     int64_t exit_status,
56                     int term_signal) {
57   printf("exit_cb\n");
58   exit_cb_called++;
59   ASSERT(exit_status == 1);
60   ASSERT(term_signal == 0);
61   uv_close((uv_handle_t*)process, close_cb);
62 }
63
64
65 static void fail_cb(uv_process_t* process,
66                     int64_t exit_status,
67                     int term_signal) {
68   ASSERT(0 && "fail_cb called");
69 }
70
71
72 static void kill_cb(uv_process_t* process,
73                     int64_t exit_status,
74                     int term_signal) {
75   int err;
76
77   printf("exit_cb\n");
78   exit_cb_called++;
79 #ifdef _WIN32
80   ASSERT(exit_status == 1);
81 #else
82   ASSERT(exit_status == 0);
83 #endif
84   ASSERT(no_term_signal || term_signal == 15);
85   uv_close((uv_handle_t*)process, close_cb);
86
87   /*
88    * Sending signum == 0 should check if the
89    * child process is still alive, not kill it.
90    * This process should be dead.
91    */
92   err = uv_kill(process->pid, 0);
93   ASSERT(err == UV_ESRCH);
94 }
95
96 static void detach_failure_cb(uv_process_t* process,
97                               int64_t exit_status,
98                               int term_signal) {
99   printf("detach_cb\n");
100   exit_cb_called++;
101 }
102
103 static void on_alloc(uv_handle_t* handle,
104                      size_t suggested_size,
105                      uv_buf_t* buf) {
106   buf->base = output + output_used;
107   buf->len = OUTPUT_SIZE - output_used;
108 }
109
110
111 static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
112   if (nread > 0) {
113     output_used += nread;
114   } else if (nread < 0) {
115     ASSERT(nread == UV_EOF);
116     uv_close((uv_handle_t*)tcp, close_cb);
117   }
118 }
119
120
121 static void write_cb(uv_write_t* req, int status) {
122   ASSERT(status == 0);
123   uv_close((uv_handle_t*)req->handle, close_cb);
124 }
125
126
127 static void init_process_options(char* test, uv_exit_cb exit_cb) {
128   /* Note spawn_helper1 defined in test/run-tests.c */
129   int r = uv_exepath(exepath, &exepath_size);
130   ASSERT(r == 0);
131   exepath[exepath_size] = '\0';
132   args[0] = exepath;
133   args[1] = test;
134   args[2] = NULL;
135   options.file = exepath;
136   options.args = args;
137   options.exit_cb = exit_cb;
138   options.flags = 0;
139 }
140
141
142 static void timer_cb(uv_timer_t* handle, int status) {
143   uv_process_kill(&process, /* SIGTERM */ 15);
144   uv_close((uv_handle_t*)handle, close_cb);
145 }
146
147
148 TEST_IMPL(spawn_fails) {
149   init_process_options("", fail_cb);
150   options.file = options.args[0] = "program-that-had-better-not-exist";
151
152   ASSERT(UV_ENOENT == uv_spawn(uv_default_loop(), &process, &options));
153   ASSERT(0 == uv_is_active((uv_handle_t*) &process));
154   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
155
156   MAKE_VALGRIND_HAPPY();
157   return 0;
158 }
159
160
161 TEST_IMPL(spawn_exit_code) {
162   int r;
163
164   init_process_options("spawn_helper1", exit_cb);
165
166   r = uv_spawn(uv_default_loop(), &process, &options);
167   ASSERT(r == 0);
168
169   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
170   ASSERT(r == 0);
171
172   ASSERT(exit_cb_called == 1);
173   ASSERT(close_cb_called == 1);
174
175   MAKE_VALGRIND_HAPPY();
176   return 0;
177 }
178
179
180 TEST_IMPL(spawn_stdout) {
181   int r;
182   uv_pipe_t out;
183   uv_stdio_container_t stdio[2];
184
185   init_process_options("spawn_helper2", exit_cb);
186
187   uv_pipe_init(uv_default_loop(), &out, 0);
188   options.stdio = stdio;
189   options.stdio[0].flags = UV_IGNORE;
190   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
191   options.stdio[1].data.stream = (uv_stream_t*)&out;
192   options.stdio_count = 2;
193
194   r = uv_spawn(uv_default_loop(), &process, &options);
195   ASSERT(r == 0);
196
197   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
198   ASSERT(r == 0);
199
200   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
201   ASSERT(r == 0);
202
203   ASSERT(exit_cb_called == 1);
204   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
205   printf("output is: %s", output);
206   ASSERT(strcmp("hello world\n", output) == 0);
207
208   MAKE_VALGRIND_HAPPY();
209   return 0;
210 }
211
212
213 TEST_IMPL(spawn_stdout_to_file) {
214   int r;
215   uv_file file;
216   uv_fs_t fs_req;
217   uv_stdio_container_t stdio[2];
218
219   /* Setup. */
220   unlink("stdout_file");
221
222   init_process_options("spawn_helper2", exit_cb);
223
224   r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
225       S_IRUSR | S_IWUSR, NULL);
226   ASSERT(r != -1);
227   uv_fs_req_cleanup(&fs_req);
228
229   file = r;
230
231   options.stdio = stdio;
232   options.stdio[0].flags = UV_IGNORE;
233   options.stdio[1].flags = UV_INHERIT_FD;
234   options.stdio[1].data.fd = file;
235   options.stdio_count = 2;
236
237   r = uv_spawn(uv_default_loop(), &process, &options);
238   ASSERT(r == 0);
239
240   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
241   ASSERT(r == 0);
242
243   ASSERT(exit_cb_called == 1);
244   ASSERT(close_cb_called == 1);
245
246   r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
247       0, NULL);
248   ASSERT(r == 12);
249   uv_fs_req_cleanup(&fs_req);
250
251   r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
252   ASSERT(r == 0);
253   uv_fs_req_cleanup(&fs_req);
254
255   printf("output is: %s", output);
256   ASSERT(strcmp("hello world\n", output) == 0);
257
258   /* Cleanup. */
259   unlink("stdout_file");
260
261   MAKE_VALGRIND_HAPPY();
262   return 0;
263 }
264
265
266 TEST_IMPL(spawn_stdin) {
267   int r;
268   uv_pipe_t out;
269   uv_pipe_t in;
270   uv_write_t write_req;
271   uv_buf_t buf;
272   uv_stdio_container_t stdio[2];
273   char buffer[] = "hello-from-spawn_stdin";
274
275   init_process_options("spawn_helper3", exit_cb);
276
277   uv_pipe_init(uv_default_loop(), &out, 0);
278   uv_pipe_init(uv_default_loop(), &in, 0);
279   options.stdio = stdio;
280   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
281   options.stdio[0].data.stream = (uv_stream_t*)&in;
282   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
283   options.stdio[1].data.stream = (uv_stream_t*)&out;
284   options.stdio_count = 2;
285
286   r = uv_spawn(uv_default_loop(), &process, &options);
287   ASSERT(r == 0);
288
289   buf.base = buffer;
290   buf.len = sizeof(buffer);
291   r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
292   ASSERT(r == 0);
293
294   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
295   ASSERT(r == 0);
296
297   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
298   ASSERT(r == 0);
299
300   ASSERT(exit_cb_called == 1);
301   ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
302   ASSERT(strcmp(buffer, output) == 0);
303
304   MAKE_VALGRIND_HAPPY();
305   return 0;
306 }
307
308
309 TEST_IMPL(spawn_stdio_greater_than_3) {
310   int r;
311   uv_pipe_t pipe;
312   uv_stdio_container_t stdio[4];
313
314   init_process_options("spawn_helper5", exit_cb);
315
316   uv_pipe_init(uv_default_loop(), &pipe, 0);
317   options.stdio = stdio;
318   options.stdio[0].flags = UV_IGNORE;
319   options.stdio[1].flags = UV_IGNORE;
320   options.stdio[2].flags = UV_IGNORE;
321   options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
322   options.stdio[3].data.stream = (uv_stream_t*)&pipe;
323   options.stdio_count = 4;
324
325   r = uv_spawn(uv_default_loop(), &process, &options);
326   ASSERT(r == 0);
327
328   r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
329   ASSERT(r == 0);
330
331   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
332   ASSERT(r == 0);
333
334   ASSERT(exit_cb_called == 1);
335   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
336   printf("output from stdio[3] is: %s", output);
337   ASSERT(strcmp("fourth stdio!\n", output) == 0);
338
339   MAKE_VALGRIND_HAPPY();
340   return 0;
341 }
342
343
344 TEST_IMPL(spawn_ignored_stdio) {
345   int r;
346
347   init_process_options("spawn_helper6", exit_cb);
348
349   options.stdio = NULL;
350   options.stdio_count = 0;
351
352   r = uv_spawn(uv_default_loop(), &process, &options);
353   ASSERT(r == 0);
354
355   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
356   ASSERT(r == 0);
357
358   ASSERT(exit_cb_called == 1);
359   ASSERT(close_cb_called == 1);
360
361   MAKE_VALGRIND_HAPPY();
362   return 0;
363 }
364
365
366 TEST_IMPL(spawn_and_kill) {
367   int r;
368
369   init_process_options("spawn_helper4", kill_cb);
370
371   r = uv_spawn(uv_default_loop(), &process, &options);
372   ASSERT(r == 0);
373
374   r = uv_timer_init(uv_default_loop(), &timer);
375   ASSERT(r == 0);
376
377   r = uv_timer_start(&timer, timer_cb, 500, 0);
378   ASSERT(r == 0);
379
380   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
381   ASSERT(r == 0);
382
383   ASSERT(exit_cb_called == 1);
384   ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
385
386   MAKE_VALGRIND_HAPPY();
387   return 0;
388 }
389
390
391 TEST_IMPL(spawn_preserve_env) {
392   int r;
393   uv_pipe_t out;
394   uv_stdio_container_t stdio[2];
395
396   init_process_options("spawn_helper7", exit_cb);
397
398   uv_pipe_init(uv_default_loop(), &out, 0);
399   options.stdio = stdio;
400   options.stdio[0].flags = UV_IGNORE;
401   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
402   options.stdio[1].data.stream = (uv_stream_t*) &out;
403   options.stdio_count = 2;
404
405   r = putenv("ENV_TEST=testval");
406   ASSERT(r == 0);
407
408   /* Explicitly set options.env to NULL to test for env clobbering. */
409   options.env = NULL;
410
411   r = uv_spawn(uv_default_loop(), &process, &options);
412   ASSERT(r == 0);
413
414   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
415   ASSERT(r == 0);
416
417   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
418   ASSERT(r == 0);
419
420   ASSERT(exit_cb_called == 1);
421   ASSERT(close_cb_called == 2);
422
423   printf("output is: %s", output);
424   ASSERT(strcmp("testval", output) == 0);
425
426   MAKE_VALGRIND_HAPPY();
427   return 0;
428 }
429
430
431 TEST_IMPL(spawn_detached) {
432   int r;
433
434   init_process_options("spawn_helper4", detach_failure_cb);
435
436   options.flags |= UV_PROCESS_DETACHED;
437
438   r = uv_spawn(uv_default_loop(), &process, &options);
439   ASSERT(r == 0);
440
441   uv_unref((uv_handle_t*)&process);
442
443   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
444   ASSERT(r == 0);
445
446   ASSERT(exit_cb_called == 0);
447
448   r = uv_kill(process.pid, 0);
449   ASSERT(r == 0);
450
451   r = uv_kill(process.pid, 15);
452   ASSERT(r == 0);
453
454   MAKE_VALGRIND_HAPPY();
455   return 0;
456 }
457
458 TEST_IMPL(spawn_and_kill_with_std) {
459   int r;
460   uv_pipe_t in, out, err;
461   uv_write_t write;
462   char message[] = "Nancy's joining me because the message this evening is "
463                    "not my message but ours.";
464   uv_buf_t buf;
465   uv_stdio_container_t stdio[3];
466
467   init_process_options("spawn_helper4", kill_cb);
468
469   r = uv_pipe_init(uv_default_loop(), &in, 0);
470   ASSERT(r == 0);
471
472   r = uv_pipe_init(uv_default_loop(), &out, 0);
473   ASSERT(r == 0);
474
475   r = uv_pipe_init(uv_default_loop(), &err, 0);
476   ASSERT(r == 0);
477
478   options.stdio = stdio;
479   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
480   options.stdio[0].data.stream = (uv_stream_t*)&in;
481   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
482   options.stdio[1].data.stream = (uv_stream_t*)&out;
483   options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
484   options.stdio[2].data.stream = (uv_stream_t*)&err;
485   options.stdio_count = 3;
486
487   r = uv_spawn(uv_default_loop(), &process, &options);
488   ASSERT(r == 0);
489
490   buf = uv_buf_init(message, sizeof message);
491   r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
492   ASSERT(r == 0);
493
494   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
495   ASSERT(r == 0);
496
497   r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
498   ASSERT(r == 0);
499
500   r = uv_timer_init(uv_default_loop(), &timer);
501   ASSERT(r == 0);
502
503   r = uv_timer_start(&timer, timer_cb, 500, 0);
504   ASSERT(r == 0);
505
506   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
507   ASSERT(r == 0);
508
509   ASSERT(exit_cb_called == 1);
510   ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
511
512   MAKE_VALGRIND_HAPPY();
513   return 0;
514 }
515
516
517 TEST_IMPL(spawn_and_ping) {
518   uv_write_t write_req;
519   uv_pipe_t in, out;
520   uv_buf_t buf;
521   uv_stdio_container_t stdio[2];
522   int r;
523
524   init_process_options("spawn_helper3", exit_cb);
525   buf = uv_buf_init("TEST", 4);
526
527   uv_pipe_init(uv_default_loop(), &out, 0);
528   uv_pipe_init(uv_default_loop(), &in, 0);
529   options.stdio = stdio;
530   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
531   options.stdio[0].data.stream = (uv_stream_t*)&in;
532   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
533   options.stdio[1].data.stream = (uv_stream_t*)&out;
534   options.stdio_count = 2;
535
536   r = uv_spawn(uv_default_loop(), &process, &options);
537   ASSERT(r == 0);
538
539   /* Sending signum == 0 should check if the
540    * child process is still alive, not kill it.
541    */
542   r = uv_process_kill(&process, 0);
543   ASSERT(r == 0);
544
545   r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
546   ASSERT(r == 0);
547
548   r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
549   ASSERT(r == 0);
550
551   ASSERT(exit_cb_called == 0);
552
553   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
554   ASSERT(r == 0);
555
556   ASSERT(exit_cb_called == 1);
557   ASSERT(strcmp(output, "TEST") == 0);
558
559   MAKE_VALGRIND_HAPPY();
560   return 0;
561 }
562
563
564 TEST_IMPL(kill) {
565   int r;
566
567 #ifdef _WIN32
568   no_term_signal = 1;
569 #endif
570
571   init_process_options("spawn_helper4", kill_cb);
572
573   r = uv_spawn(uv_default_loop(), &process, &options);
574   ASSERT(r == 0);
575
576   /* Sending signum == 0 should check if the
577    * child process is still alive, not kill it.
578    */
579   r = uv_kill(process.pid, 0);
580   ASSERT(r == 0);
581
582   /* Kill the process. */
583   r = uv_kill(process.pid, /* SIGTERM */ 15);
584   ASSERT(r == 0);
585
586   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
587   ASSERT(r == 0);
588
589   ASSERT(exit_cb_called == 1);
590   ASSERT(close_cb_called == 1);
591
592   MAKE_VALGRIND_HAPPY();
593   return 0;
594 }
595
596
597 #ifdef _WIN32
598 TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
599   int r;
600   uv_pipe_t out;
601   char name[64];
602   HANDLE pipe_handle;
603   uv_stdio_container_t stdio[2];
604
605   init_process_options("spawn_helper2", exit_cb);
606
607   uv_pipe_init(uv_default_loop(), &out, 0);
608   options.stdio = stdio;
609   options.stdio[0].flags = UV_IGNORE;
610   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
611   options.stdio[1].data.stream = (uv_stream_t*)&out;
612   options.stdio_count = 2;
613
614   /* Create a pipe that'll cause a collision. */
615   _snprintf(name,
616             sizeof(name),
617             "\\\\.\\pipe\\uv\\%p-%d",
618             &out,
619             GetCurrentProcessId());
620   pipe_handle = CreateNamedPipeA(name,
621                                 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
622                                 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
623                                 10,
624                                 65536,
625                                 65536,
626                                 0,
627                                 NULL);
628   ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
629
630   r = uv_spawn(uv_default_loop(), &process, &options);
631   ASSERT(r == 0);
632
633   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
634   ASSERT(r == 0);
635
636   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
637   ASSERT(r == 0);
638
639   ASSERT(exit_cb_called == 1);
640   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
641   printf("output is: %s", output);
642   ASSERT(strcmp("hello world\n", output) == 0);
643
644   MAKE_VALGRIND_HAPPY();
645   return 0;
646 }
647
648
649 int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
650 WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
651
652 TEST_IMPL(argument_escaping) {
653   const WCHAR* test_str[] = {
654     L"HelloWorld",
655     L"Hello World",
656     L"Hello\"World",
657     L"Hello World\\",
658     L"Hello\\\"World",
659     L"Hello\\World",
660     L"Hello\\\\World",
661     L"Hello World\\",
662     L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
663   };
664   const int count = sizeof(test_str) / sizeof(*test_str);
665   WCHAR** test_output;
666   WCHAR* command_line;
667   WCHAR** cracked;
668   size_t total_size = 0;
669   int i;
670   int num_args;
671   int result;
672
673   char* verbatim[] = {
674     "cmd.exe",
675     "/c",
676     "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
677     NULL
678   };
679   WCHAR* verbatim_output;
680   WCHAR* non_verbatim_output;
681
682   test_output = calloc(count, sizeof(WCHAR*));
683   for (i = 0; i < count; ++i) {
684     test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
685     quote_cmd_arg(test_str[i], test_output[i]);
686     wprintf(L"input : %s\n", test_str[i]);
687     wprintf(L"output: %s\n", test_output[i]);
688     total_size += wcslen(test_output[i]) + 1;
689   }
690   command_line = calloc(total_size + 1, sizeof(WCHAR));
691   for (i = 0; i < count; ++i) {
692     wcscat(command_line, test_output[i]);
693     wcscat(command_line, L" ");
694   }
695   command_line[total_size - 1] = L'\0';
696
697   wprintf(L"command_line: %s\n", command_line);
698
699   cracked = CommandLineToArgvW(command_line, &num_args);
700   for (i = 0; i < num_args; ++i) {
701     wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
702     ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
703   }
704
705   LocalFree(cracked);
706   for (i = 0; i < count; ++i) {
707     free(test_output[i]);
708   }
709
710   result = make_program_args(verbatim, 1, &verbatim_output);
711   ASSERT(result == 0);
712   result = make_program_args(verbatim, 0, &non_verbatim_output);
713   ASSERT(result == 0);
714
715   wprintf(L"    verbatim_output: %s\n", verbatim_output);
716   wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
717
718   ASSERT(wcscmp(verbatim_output,
719                 L"cmd.exe /c c:\\path\\to\\node.exe --eval "
720                 L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
721   ASSERT(wcscmp(non_verbatim_output,
722                 L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
723                 L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
724
725   free(verbatim_output);
726   free(non_verbatim_output);
727
728   return 0;
729 }
730
731 int make_program_env(char** env_block, WCHAR** dst_ptr);
732
733 TEST_IMPL(environment_creation) {
734   int i;
735   char* environment[] = {
736     "FOO=BAR",
737     "SYSTEM=ROOT", /* substring of a supplied var name */
738     "SYSTEMROOTED=OMG", /* supplied var name is a substring */
739     "TEMP=C:\\Temp",
740     "BAZ=QUX",
741     NULL
742   };
743
744   WCHAR expected[512];
745   WCHAR* ptr = expected;
746   int result;
747   WCHAR* str;
748   WCHAR* env;
749
750   for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) {
751     ptr += uv_utf8_to_utf16(environment[i],
752                             ptr,
753                             expected + sizeof(expected) - ptr);
754   }
755
756   memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT="));
757   ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1;
758   ptr += GetEnvironmentVariableW(L"SYSTEMROOT",
759                                  ptr,
760                                  expected + sizeof(expected) - ptr);
761   ++ptr;
762
763   memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE="));
764   ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1;
765   ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE",
766                                  ptr,
767                                  expected + sizeof(expected) - ptr);
768   ++ptr;
769   *ptr = '\0';
770
771   result = make_program_env(environment, &env);
772   ASSERT(result == 0);
773
774   for (str = env; *str; str += wcslen(str) + 1) {
775     wprintf(L"%s\n", str);
776   }
777
778   ASSERT(wcscmp(expected, env) == 0);
779
780   return 0;
781 }
782 #endif
783
784 #ifndef _WIN32
785 TEST_IMPL(spawn_setuid_setgid) {
786   int r;
787
788   /* if not root, then this will fail. */
789   uv_uid_t uid = getuid();
790   if (uid != 0) {
791     fprintf(stderr, "spawn_setuid_setgid skipped: not root\n");
792     return 0;
793   }
794
795   init_process_options("spawn_helper1", exit_cb);
796
797   /* become the "nobody" user. */
798   struct passwd* pw;
799   pw = getpwnam("nobody");
800   ASSERT(pw != NULL);
801   options.uid = pw->pw_uid;
802   options.gid = pw->pw_gid;
803   options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
804
805   r = uv_spawn(uv_default_loop(), &process, &options);
806   ASSERT(r == 0);
807
808   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
809   ASSERT(r == 0);
810
811   ASSERT(exit_cb_called == 1);
812   ASSERT(close_cb_called == 1);
813
814   MAKE_VALGRIND_HAPPY();
815   return 0;
816 }
817 #endif
818
819
820 #ifndef _WIN32
821 TEST_IMPL(spawn_setuid_fails) {
822   int r;
823
824   /* if root, become nobody. */
825   uv_uid_t uid = getuid();
826   if (uid == 0) {
827     struct passwd* pw;
828     pw = getpwnam("nobody");
829     ASSERT(pw != NULL);
830     ASSERT(0 == setgid(pw->pw_gid));
831     ASSERT(0 == setuid(pw->pw_uid));
832   }
833
834   init_process_options("spawn_helper1", fail_cb);
835
836   options.flags |= UV_PROCESS_SETUID;
837   options.uid = 0;
838
839   r = uv_spawn(uv_default_loop(), &process, &options);
840   ASSERT(r == UV_EPERM);
841
842   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
843   ASSERT(r == 0);
844
845   ASSERT(close_cb_called == 0);
846
847   MAKE_VALGRIND_HAPPY();
848   return 0;
849 }
850
851
852 TEST_IMPL(spawn_setgid_fails) {
853   int r;
854
855   /* if root, become nobody. */
856   uv_uid_t uid = getuid();
857   if (uid == 0) {
858     struct passwd* pw;
859     pw = getpwnam("nobody");
860     ASSERT(pw != NULL);
861     ASSERT(0 == setgid(pw->pw_gid));
862     ASSERT(0 == setuid(pw->pw_uid));
863   }
864
865   init_process_options("spawn_helper1", fail_cb);
866
867   options.flags |= UV_PROCESS_SETGID;
868   options.gid = 0;
869
870   r = uv_spawn(uv_default_loop(), &process, &options);
871   ASSERT(r == UV_EPERM);
872
873   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
874   ASSERT(r == 0);
875
876   ASSERT(close_cb_called == 0);
877
878   MAKE_VALGRIND_HAPPY();
879   return 0;
880 }
881 #endif
882
883
884 #ifdef _WIN32
885
886 static void exit_cb_unexpected(uv_process_t* process,
887                                int64_t exit_status,
888                                int term_signal) {
889   ASSERT(0 && "should not have been called");
890 }
891
892
893 TEST_IMPL(spawn_setuid_fails) {
894   int r;
895
896   init_process_options("spawn_helper1", exit_cb_unexpected);
897
898   options.flags |= UV_PROCESS_SETUID;
899   options.uid = (uv_uid_t) -42424242;
900
901   r = uv_spawn(uv_default_loop(), &process, &options);
902   ASSERT(r == UV_ENOTSUP);
903
904   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
905   ASSERT(r == 0);
906
907   ASSERT(close_cb_called == 0);
908
909   MAKE_VALGRIND_HAPPY();
910   return 0;
911 }
912
913
914 TEST_IMPL(spawn_setgid_fails) {
915   int r;
916
917   init_process_options("spawn_helper1", exit_cb_unexpected);
918
919   options.flags |= UV_PROCESS_SETGID;
920   options.gid = (uv_gid_t) -42424242;
921
922   r = uv_spawn(uv_default_loop(), &process, &options);
923   ASSERT(r == UV_ENOTSUP);
924
925   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
926   ASSERT(r == 0);
927
928   ASSERT(close_cb_called == 0);
929
930   MAKE_VALGRIND_HAPPY();
931   return 0;
932 }
933 #endif
934
935
936 TEST_IMPL(spawn_auto_unref) {
937   init_process_options("spawn_helper1", NULL);
938   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
939   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
940   ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
941   uv_close((uv_handle_t*) &process, NULL);
942   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
943   ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
944   MAKE_VALGRIND_HAPPY();
945   return 0;
946 }