minimal build
[platform/upstream/gcr.git] / gcr / tests / test-gnupg-process.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3    Copyright (C) 2011 Collabora Ltd
4
5    The Gnome Keyring Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The Gnome Keyring Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the Gnome Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19
20    Author: Stef Walter <stefw@collabora.co.uk>
21 */
22
23 #include "config.h"
24
25 #include "gcr/gcr-base.h"
26 #include "gcr/gcr-callback-output-stream.h"
27 #include "gcr/gcr-gnupg-process.h"
28
29 #include "egg/egg-testing.h"
30
31 #include <glib.h>
32
33 #include <errno.h>
34 #include <string.h>
35
36 #define WAIT 50000
37
38 typedef struct {
39         GcrGnupgProcess *process;
40         GAsyncResult *result;
41         GString *output_buf;
42         GString *error_buf;
43         GString *attribute_buf;
44         GcrRecord *record;
45 } Test;
46
47 static void
48 setup (Test *test, gconstpointer unused)
49 {
50         test->output_buf = g_string_new ("");
51         test->error_buf = g_string_new ("");
52         test->attribute_buf = g_string_new ("");
53 }
54
55 static void
56 teardown (Test *test, gconstpointer unused)
57 {
58         if (test->result)
59                 g_object_unref (test->result);
60         if (test->process)
61                 g_object_unref (test->process);
62
63         while (g_main_context_iteration (NULL, FALSE));
64
65         if (test->result)
66                 egg_assert_not_object (test->result);
67         if (test->process)
68                 egg_assert_not_object (test->process);
69
70         if (test->output_buf)
71                 g_string_free (test->output_buf, TRUE);
72         if (test->error_buf)
73                 g_string_free (test->error_buf, TRUE);
74         if (test->attribute_buf)
75                 g_string_free (test->attribute_buf, TRUE);
76         _gcr_record_free (test->record);
77 }
78
79 static void
80 test_create (Test *test, gconstpointer unused)
81 {
82         gchar *value;
83
84         test->process = _gcr_gnupg_process_new ("/the/directory", "/path/to/executable");
85
86         g_object_get (test->process, "directory", &value, NULL);
87         g_assert_cmpstr (value, ==, "/the/directory");
88         g_free (value);
89
90         g_object_get (test->process, "executable", &value, NULL);
91         g_assert_cmpstr (value, ==, "/path/to/executable");
92         g_free (value);
93 }
94
95 static void
96 on_async_ready (GObject *source, GAsyncResult *result, gpointer user_data)
97 {
98         Test *test = user_data;
99         GObject *result_source;
100
101         g_assert (G_OBJECT (test->process) == source);
102         g_assert (test->result == NULL);
103
104         result_source = g_async_result_get_source_object (result);
105         g_assert (result_source == source);
106         g_object_unref (result_source);
107
108         test->result = g_object_ref (result);
109         egg_test_wait_stop ();
110 }
111
112 static gchar*
113 build_script_path (const gchar *name)
114 {
115         gchar *path;
116
117         path = g_build_filename (SRCDIR, "files", "gnupg-mock", name, NULL);
118
119         return path;
120 }
121
122 static gssize
123 on_process_output_data (gconstpointer buffer,
124                         gsize count,
125                         GCancellable *cancellable,
126                         gpointer user_data,
127                         GError **error)
128 {
129         Test *test = user_data;
130         g_string_append_len (test->output_buf, buffer, count);
131         return count;
132 }
133
134 static gssize
135 on_process_attribute_data (gconstpointer buffer,
136                            gsize count,
137                            GCancellable *cancellable,
138                            gpointer user_data,
139                            GError **error)
140 {
141         Test *test = user_data;
142         g_string_append_len (test->attribute_buf, buffer, count);
143         return count;
144 }
145
146 static void
147 on_process_error_line (GcrGnupgProcess *process, const gchar *line, gpointer user_data)
148 {
149         Test *test = user_data;
150
151         g_assert (process == test->process);
152         g_assert (line);
153         g_assert (!strchr (line, '\n'));
154
155         g_string_append_printf (test->error_buf, "%s\n", line);
156 }
157
158 static void
159 on_process_status_record (GcrGnupgProcess *process, GcrRecord *record, gpointer user_data)
160 {
161         Test *test = user_data;
162
163         g_assert (process == test->process);
164         g_assert (record);
165
166         g_assert (!test->record);
167         test->record = _gcr_record_copy (record);
168 }
169
170 static void
171 test_run_simple_output (Test *test, gconstpointer unused)
172 {
173         const gchar *argv[] = { NULL };
174         GOutputStream *output;
175         GError *error = NULL;
176         gboolean ret;
177         gchar *script;
178
179         script = build_script_path ("mock-simple-output");
180         test->process = _gcr_gnupg_process_new (NULL, script);
181         g_free (script);
182
183         output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL);
184         _gcr_gnupg_process_set_output_stream (test->process, output);
185         g_object_unref (output);
186
187         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
188         egg_test_wait_until (WAIT);
189
190         g_assert (test->result);
191         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
192         g_assert_no_error (error);
193         g_assert (ret == TRUE);
194
195         g_assert_cmpstr ("simple-output\n", ==, test->output_buf->str);
196 }
197
198 static void
199 test_run_simple_error (Test *test, gconstpointer unused)
200 {
201         const gchar *argv[] = { NULL };
202         GError *error = NULL;
203         gchar *script;
204         gboolean ret;
205
206         script = build_script_path ("mock-simple-error");
207         test->process = _gcr_gnupg_process_new (NULL, script);
208         g_free (script);
209
210         g_signal_connect (test->process, "error-line", G_CALLBACK (on_process_error_line), test);
211
212         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
213         egg_test_wait_until (WAIT);
214
215         g_assert (test->result);
216         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
217         g_assert_no_error (error);
218         g_assert (ret == TRUE);
219
220         g_assert_cmpstr ("line 1: more line 1\nline 2\nline 3\n", ==, test->error_buf->str);
221 }
222
223 static void
224 test_run_status_and_output (Test *test, gconstpointer unused)
225 {
226         const gchar *argv[] = { NULL };
227         GOutputStream *output;
228         GError *error = NULL;
229         gchar *script;
230         gboolean ret;
231
232         script = build_script_path ("mock-status-and-output");
233         test->process = _gcr_gnupg_process_new (NULL, script);
234         g_free (script);
235
236         output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL);
237         _gcr_gnupg_process_set_output_stream (test->process, output);
238         g_object_unref (output);
239
240         g_signal_connect (test->process, "status-record", G_CALLBACK (on_process_status_record), test);
241
242         _gcr_gnupg_process_run_async (test->process, argv, NULL, GCR_GNUPG_PROCESS_WITH_STATUS,
243                                       NULL, on_async_ready, test);
244         egg_test_wait_until (WAIT);
245
246         g_assert (test->result);
247         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
248         g_assert_no_error (error);
249         g_assert (ret == TRUE);
250
251         g_assert (test->record);
252         g_assert_cmpstr (_gcr_record_get_raw (test->record, 0), ==, "SCHEMA");
253         g_assert_cmpstr (_gcr_record_get_raw (test->record, 1), ==, "one");
254         g_assert_cmpstr (_gcr_record_get_raw (test->record, 2), ==, "two");
255         g_assert_cmpstr (_gcr_record_get_raw (test->record, 3), ==, "three");
256         g_assert_cmpstr (_gcr_record_get_raw (test->record, 4), ==, "four");
257         g_assert_cmpstr (_gcr_record_get_raw (test->record, 5), ==, NULL);
258         g_assert_cmpstr ("Here's some output\nMore output\n", ==, test->output_buf->str);
259 }
260
261 static void
262 test_run_status_and_attribute (Test *test, gconstpointer unused)
263 {
264         const gchar *argv[] = { NULL };
265         GOutputStream *output;
266         GError *error = NULL;
267         gchar *script;
268         gboolean ret;
269
270         script = build_script_path ("mock-status-and-attribute");
271         test->process = _gcr_gnupg_process_new (NULL, script);
272         g_free (script);
273
274         output = _gcr_callback_output_stream_new (on_process_attribute_data, test, NULL);
275         _gcr_gnupg_process_set_attribute_stream (test->process, output);
276         g_object_unref (output);
277
278         g_signal_connect (test->process, "status-record", G_CALLBACK (on_process_status_record), test);
279
280         _gcr_gnupg_process_run_async (test->process, argv, NULL,
281                                       GCR_GNUPG_PROCESS_WITH_STATUS | GCR_GNUPG_PROCESS_WITH_ATTRIBUTES,
282                                       NULL, on_async_ready, test);
283         egg_test_wait_until (WAIT);
284
285         g_assert (test->result);
286         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
287         g_assert_no_error (error);
288         g_assert (ret == TRUE);
289
290         g_assert (test->record);
291         g_assert_cmpstr (_gcr_record_get_raw (test->record, 0), ==, "SCHEMA");
292         g_assert_cmpstr (_gcr_record_get_raw (test->record, 1), ==, "one");
293         g_assert_cmpstr (_gcr_record_get_raw (test->record, 2), ==, "two");
294         g_assert_cmpstr (_gcr_record_get_raw (test->record, 3), ==, "three");
295         g_assert_cmpstr (_gcr_record_get_raw (test->record, 4), ==, "four");
296         g_assert_cmpstr (_gcr_record_get_raw (test->record, 5), ==, NULL);
297         g_assert_cmpstr ("1lc923g4laoeurc23rc241lcg2r23c4gr3", ==, test->attribute_buf->str);
298 }
299
300
301 static void
302 test_run_arguments_and_environment (Test *test, gconstpointer unused)
303 {
304         GError *error = NULL;
305         GOutputStream *output;
306         gchar *script;
307         gboolean ret;
308
309         const gchar *argv[] = {
310                 "-1", "value1",
311                 "-2", "value2",
312                 NULL
313         };
314
315         const gchar *envp[] = {
316                 "ENVIRON1=VALUE1",
317                 "ENVIRON2=VALUE2",
318                 NULL
319         };
320
321         script = build_script_path ("mock-arguments-environ");
322         test->process = _gcr_gnupg_process_new (NULL, script);
323         g_free (script);
324
325         output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL);
326         _gcr_gnupg_process_set_output_stream (test->process, output);
327         g_object_unref (output);
328
329         g_signal_connect (test->process, "error-line", G_CALLBACK (on_process_error_line), test);
330
331         _gcr_gnupg_process_run_async (test->process, argv, envp, 0, NULL, on_async_ready, test);
332         egg_test_wait_until (WAIT);
333
334         g_assert (test->result);
335         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
336         if (error) {
337                 g_printerr ("%s\n", test->error_buf->str);
338                 g_assert_no_error (error);
339         }
340         g_assert (ret == TRUE);
341
342         g_assert_cmpstr ("value1\nvalue2\n", ==, test->output_buf->str);
343         g_assert_cmpstr ("VALUE1VALUE2\n", ==, test->error_buf->str);
344 }
345
346 static void
347 test_run_with_homedir (Test *test, gconstpointer unused)
348 {
349         const gchar *argv[] = { NULL };
350         GOutputStream *output;
351         GError *error = NULL;
352         gchar *script;
353         gchar *check;
354         gboolean ret;
355
356         script = build_script_path ("mock-with-homedir");
357         test->process = _gcr_gnupg_process_new (SRCDIR, script);
358         g_free (script);
359
360         output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL);
361         _gcr_gnupg_process_set_output_stream (test->process, output);
362         g_object_unref (output);
363
364         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
365         egg_test_wait_until (WAIT);
366
367         g_assert (test->result);
368         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
369         g_assert_no_error (error);
370         g_assert (ret == TRUE);
371
372         check = g_strdup_printf ("DIR: %s\n", SRCDIR);
373         g_assert_cmpstr (check, ==, test->output_buf->str);
374         g_free (check);
375 }
376
377 static void
378 test_run_with_input_and_output (Test *test,
379                                 gconstpointer unused)
380 {
381         const gchar *argv[] = { NULL };
382         const gchar *data = "one\ntwenty two\nthree\nfourty four\n";
383         GInputStream *input;
384         GOutputStream *output;
385         GError *error = NULL;
386         GString *string;
387         gchar *script;
388         gboolean ret;
389
390         script = build_script_path ("mock-echo");
391         test->process = _gcr_gnupg_process_new (SRCDIR, script);
392         g_free (script);
393
394         input = g_memory_input_stream_new_from_data ((gpointer)data, -1, NULL);
395         output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
396
397         _gcr_gnupg_process_set_input_stream (test->process, input);
398         _gcr_gnupg_process_set_output_stream (test->process, output);
399
400         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
401         egg_test_wait_until (WAIT);
402
403         g_assert (test->result);
404         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
405         g_assert_no_error (error);
406         g_assert (ret == TRUE);
407
408         string = g_string_new_len (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output)),
409                                    g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output)));
410         g_assert_cmpstr (data, ==, string->str);
411         g_string_free (string, TRUE);
412
413         g_clear_object (&input);
414         g_clear_object (&output);
415 }
416
417 static void
418 test_run_bad_executable (Test *test, gconstpointer unused)
419 {
420         GError *error = NULL;
421         gchar *script;
422         const gchar *argv[] = { NULL };
423         gboolean ret;
424
425         script = build_script_path ("mock-invalid");
426         test->process = _gcr_gnupg_process_new (NULL, script);
427         g_free (script);
428
429         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
430         egg_test_wait_until (WAIT);
431
432         g_assert (test->result);
433         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
434         g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
435         g_clear_error (&error);
436         g_assert (ret == FALSE);
437 }
438
439 static void
440 test_run_fail_exit (Test *test, gconstpointer unused)
441 {
442         GError *error = NULL;
443         gchar *script;
444         const gchar *argv[] = { "55", NULL };
445         gboolean ret;
446
447         script = build_script_path ("mock-fail-exit");
448         test->process = _gcr_gnupg_process_new (NULL, script);
449         g_free (script);
450
451         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
452         egg_test_wait_until (WAIT);
453
454         g_assert (test->result);
455         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
456         g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED);
457         g_assert_cmpstr (error->message, ==, "Gnupg process exited with code: 55");
458         g_clear_error (&error);
459         g_assert (ret == FALSE);
460 }
461
462 static void
463 test_run_fail_signal (Test *test, gconstpointer unused)
464 {
465         GError *error = NULL;
466         gchar *script;
467         const gchar *argv[] = { "15", NULL };
468         gboolean ret;
469
470         script = build_script_path ("mock-fail-signal");
471         test->process = _gcr_gnupg_process_new (NULL, script);
472         g_free (script);
473
474         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test);
475         egg_test_wait_until (WAIT);
476
477         g_assert (test->result);
478         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
479         g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED);
480         g_assert_cmpstr (error->message, ==, "Gnupg process was terminated with signal: 15");
481         g_clear_error (&error);
482         g_assert (ret == FALSE);
483 }
484
485 static void
486 test_run_and_cancel (Test *test, gconstpointer unused)
487 {
488         GError *error = NULL;
489         gchar *script;
490         const gchar *argv[] = { "15", NULL };
491         GCancellable *cancellable;
492         gboolean ret;
493
494         cancellable = g_cancellable_new ();
495
496         script = build_script_path ("mock-simple-output");
497         test->process = _gcr_gnupg_process_new (NULL, script);
498         g_free (script);
499
500         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, cancellable, on_async_ready, test);
501         g_cancellable_cancel (cancellable);
502         egg_test_wait_until (WAIT);
503
504         g_assert (test->result);
505         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
506         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
507         g_clear_error (&error);
508         g_assert (ret == FALSE);
509
510         g_object_unref (cancellable);
511 }
512
513 static gssize
514 on_process_output_cancel (gconstpointer buffer,
515                           gsize count,
516                           GCancellable *cancellable,
517                           gpointer user_data,
518                           GError **error)
519 {
520         g_cancellable_cancel (cancellable);
521         g_cancellable_set_error_if_cancelled (cancellable, error);
522         return -1;
523 }
524
525 static void
526 test_run_and_cancel_later (Test *test, gconstpointer unused)
527 {
528         GError *error = NULL;
529         GOutputStream *output;
530         gchar *script;
531         const gchar *argv[] = { "15", NULL };
532         GCancellable *cancellable;
533         gboolean ret;
534
535         cancellable = g_cancellable_new ();
536
537         script = build_script_path ("mock-simple-output");
538         test->process = _gcr_gnupg_process_new (NULL, script);
539         output = _gcr_callback_output_stream_new (on_process_output_cancel, NULL, NULL);
540         _gcr_gnupg_process_set_output_stream (test->process, output);
541         g_object_unref (output);
542         g_free (script);
543
544         _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, cancellable, on_async_ready, test);
545         egg_test_wait_until (WAIT);
546
547         g_assert (test->result);
548         ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error);
549         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
550         g_clear_error (&error);
551         g_assert (ret == FALSE);
552
553         g_object_unref (cancellable);
554 }
555
556 int
557 main (int argc, char **argv)
558 {
559 #if !GLIB_CHECK_VERSION(2,35,0)
560         g_type_init ();
561 #endif
562         g_test_init (&argc, &argv, NULL);
563         g_set_prgname ("test-gnupg-process");
564
565         g_test_add ("/gcr/gnupg-process/create", Test, NULL, setup, test_create, teardown);
566         g_test_add ("/gcr/gnupg-process/run_simple_output", Test, NULL, setup, test_run_simple_output, teardown);
567         g_test_add ("/gcr/gnupg-process/run_simple_error", Test, NULL, setup, test_run_simple_error, teardown);
568         g_test_add ("/gcr/gnupg-process/run_status_and_output", Test, NULL, setup, test_run_status_and_output, teardown);
569         g_test_add ("/gcr/gnupg-process/run_status_and_attribute", Test, NULL, setup, test_run_status_and_attribute, teardown);
570         g_test_add ("/gcr/gnupg-process/run_arguments_and_environment", Test, NULL, setup, test_run_arguments_and_environment, teardown);
571         g_test_add ("/gcr/gnupg-process/run_with_homedir", Test, NULL, setup, test_run_with_homedir, teardown);
572         g_test_add ("/gcr/gnupg-process/run_with_input_and_output", Test, NULL, setup, test_run_with_input_and_output, teardown);
573         g_test_add ("/gcr/gnupg-process/run_fail_exit", Test, NULL, setup, test_run_fail_exit, teardown);
574         g_test_add ("/gcr/gnupg-process/run_fail_signal", Test, NULL, setup, test_run_fail_signal, teardown);
575         g_test_add ("/gcr/gnupg-process/run_and_cancel", Test, NULL, setup, test_run_and_cancel, teardown);
576         g_test_add ("/gcr/gnupg-process/run_and_cancel_later", Test, NULL, setup, test_run_and_cancel_later, teardown);
577
578         /* Valgrind seems to have problems with g_spawn_async_xxx() failing */
579         if (!egg_testing_on_valgrind ())
580                 g_test_add ("/gcr/gnupg-process/run_bad_executable", Test, NULL, setup, test_run_bad_executable, teardown);
581
582         return egg_tests_run_with_loop ();
583 }