b5e210f4c49922840e83a3c378a4ebd8f7bf0d9b
[oweals/gnunet.git] / src / fs / test_fs_namespace.c
1 /*
2      This file is part of GNUnet.
3      (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/test_fs_namespace.c
23  * @brief Test for fs_namespace.c
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_fs_service.h"
30
31 #define VERBOSE GNUNET_YES
32
33 #define START_ARM GNUNET_YES
34
35 static struct PeerContext p1;
36
37 static GNUNET_HashCode nsid;
38
39 static struct GNUNET_FS_Uri *sks_expect_uri;
40
41 static struct GNUNET_FS_Uri *ksk_expect_uri;
42
43 static struct GNUNET_FS_Handle *fs;
44
45 static struct GNUNET_FS_SearchContext *sks_search;
46
47 static struct GNUNET_FS_SearchContext *ksk_search;
48
49 static GNUNET_SCHEDULER_TaskIdentifier kill_task;
50
51 static int update_started;
52
53 static int err;
54
55 struct PeerContext
56 {
57   struct GNUNET_CONFIGURATION_Handle *cfg;
58 #if START_ARM
59   struct GNUNET_OS_Process *arm_proc;
60 #endif
61 };
62
63
64 static void
65 setup_peer (struct PeerContext *p, const char *cfgname)
66 {
67   p->cfg = GNUNET_CONFIGURATION_create ();
68 #if START_ARM
69   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
70                                         "gnunet-service-arm",
71 #if VERBOSE
72                                         "-L", "DEBUG",
73 #endif
74                                         "-c", cfgname, NULL);
75 #endif
76   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
77 }
78
79
80 static void
81 stop_arm (struct PeerContext *p)
82 {
83 #if START_ARM
84   if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
85     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
86   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
87     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
88   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
89               "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc));
90   GNUNET_OS_process_close (p->arm_proc);
91   p->arm_proc = NULL;
92 #endif
93   if (GNUNET_SCHEDULER_NO_TASK  != kill_task)
94     GNUNET_SCHEDULER_cancel (kill_task);
95   GNUNET_CONFIGURATION_destroy (p->cfg);
96 }
97
98
99 static void
100 abort_ksk_search_task (void *cls,
101                        const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   if (ksk_search != NULL)
104     {
105       GNUNET_FS_search_stop (ksk_search);
106       ksk_search = NULL;
107       if (sks_search == NULL)
108         {
109           GNUNET_FS_stop (fs);
110         }
111     }
112 }
113
114
115 static void
116 abort_sks_search_task (void *cls,
117                        const struct GNUNET_SCHEDULER_TaskContext *tc)
118 {
119   struct GNUNET_FS_Namespace *ns;
120
121   if (sks_search == NULL)
122     return;
123   GNUNET_FS_search_stop (sks_search); 
124   sks_search = NULL;
125   ns = GNUNET_FS_namespace_create (fs,
126                                    "testNamespace");
127   GNUNET_assert (NULL != ns);
128   GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES));
129   if (ksk_search == NULL)
130     {
131       GNUNET_FS_stop (fs);
132     }    
133 }
134
135
136 static void
137 do_timeout (void *cls,
138             const struct GNUNET_SCHEDULER_TaskContext *tc)
139 {
140   fprintf (stderr,
141            "Operation timed out\n");
142   kill_task = GNUNET_SCHEDULER_NO_TASK;
143   abort_sks_search_task (NULL, tc);
144   abort_ksk_search_task (NULL, tc);
145 }
146
147
148
149 static void *
150 progress_cb (void *cls, 
151              const struct GNUNET_FS_ProgressInfo *event)
152 {
153   switch (event->status)
154     {
155     case GNUNET_FS_STATUS_SEARCH_RESULT:
156       if (sks_search == event->value.search.sc)
157         {
158           if (! GNUNET_FS_uri_test_equal (sks_expect_uri,
159                                           event->value.search.specifics.result.uri))
160             {
161               fprintf (stderr,
162                        "Wrong result for sks search!\n");
163               err = 1;
164             }
165           /* give system 1ms to initiate update search! */
166           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
167                                         &abort_sks_search_task,
168                                         NULL);
169         }
170       else if (ksk_search == event->value.search.sc)
171         {
172           if (! GNUNET_FS_uri_test_equal (ksk_expect_uri,
173                                           event->value.search.specifics.result.uri))
174             {
175               fprintf (stderr,
176                        "Wrong result for ksk search!\n");
177               err = 1;
178             }
179           GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task,
180                                              NULL,
181                                              GNUNET_SCHEDULER_REASON_PREREQ_DONE);
182         }
183       else 
184         {
185           fprintf (stderr,
186                    "Unexpected search result received!\n");
187           GNUNET_break (0);
188         }
189       break;
190     case GNUNET_FS_STATUS_SEARCH_ERROR:
191       fprintf (stderr,
192                "Error searching file: %s\n",
193                event->value.search.specifics.error.message);
194       if (sks_search == event->value.search.sc)
195         GNUNET_SCHEDULER_add_continuation (&abort_sks_search_task,
196                                            NULL,
197                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
198       else if (ksk_search == event->value.search.sc)
199         GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task,
200                                            NULL,
201                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
202       else
203         GNUNET_break (0);
204       break;
205     case GNUNET_FS_STATUS_SEARCH_START:
206       GNUNET_assert ( (NULL == event->value.search.cctx) ||
207                       (0 == strcmp ("sks_search", event->value.search.cctx)) ||
208                       (0 == strcmp ("ksk_search", event->value.search.cctx)));
209       if (NULL == event->value.search.cctx)
210         {
211           GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx));
212           update_started = GNUNET_YES;
213         }
214       GNUNET_assert (1 == event->value.search.anonymity);
215       break;
216     case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
217       return NULL;
218     case GNUNET_FS_STATUS_SEARCH_STOPPED:
219       return NULL;
220     default:
221       fprintf (stderr,
222                "Unexpected event: %d\n", 
223                event->status);
224       break;
225     }
226   return event->value.search.cctx;
227 }
228
229
230 static void
231 publish_cont (void *cls,
232               const struct GNUNET_FS_Uri *ksk_uri,
233               const char *emsg)
234 {
235   char *msg;
236   struct GNUNET_FS_Uri *sks_uri;
237   char sbuf[1024];
238   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
239   
240   if (NULL != emsg)
241     {
242       fprintf (stderr, "Error publishing: %s\n", emsg);
243       err = 1;
244       GNUNET_FS_stop (fs);
245       return;
246     }  
247   GNUNET_CRYPTO_hash_to_enc (&nsid,
248                              &enc);
249   GNUNET_snprintf (sbuf,
250                    sizeof (sbuf),
251                    "gnunet://fs/sks/%s/this",
252                    &enc);
253   sks_uri = GNUNET_FS_uri_parse (sbuf, &msg);
254   if (msg != NULL)
255     {
256       fprintf (stderr, "failed to parse URI `%s': %s\n",
257                sbuf,
258                msg);
259       err = 1;
260       GNUNET_FS_stop (fs);
261       GNUNET_free (msg);
262       return;
263     }
264   ksk_search = GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "ksk_search");
265   sks_search = GNUNET_FS_search_start (fs, sks_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "sks_search");
266   GNUNET_FS_uri_destroy (sks_uri);
267 }
268
269
270 static void
271 sks_cont (void *cls,
272           const struct GNUNET_FS_Uri *uri,
273           const char *emsg)
274 {
275   struct GNUNET_CONTAINER_MetaData *meta;
276   struct GNUNET_TIME_Absolute expiration;
277   struct GNUNET_FS_Uri *ksk_uri;
278   char * msg;
279
280   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
281   meta = GNUNET_CONTAINER_meta_data_create ();
282   msg = NULL;
283   ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg);
284   GNUNET_assert (NULL == msg);
285   ksk_expect_uri = GNUNET_FS_uri_dup (uri);
286   GNUNET_FS_publish_ksk (fs,
287                          ksk_uri,
288                          meta,
289                          uri,
290                          expiration,
291                          1, 1,
292                          GNUNET_FS_PUBLISH_OPTION_NONE,
293                          &publish_cont,
294                          NULL);
295   GNUNET_FS_uri_destroy (ksk_uri);
296   GNUNET_CONTAINER_meta_data_destroy (meta);
297 }
298
299
300 static void
301 adv_cont (void *cls,
302           const struct GNUNET_FS_Uri *uri,
303           const char *emsg)
304 {
305   struct GNUNET_CONTAINER_MetaData *meta;
306   struct GNUNET_FS_Namespace *ns;
307   struct GNUNET_TIME_Absolute expiration;
308
309   if (NULL != emsg)
310     {
311       fprintf (stderr, "Error publishing: %s\n", emsg);
312       err = 1;
313       GNUNET_FS_stop (fs);
314       return;
315     }
316   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
317   ns = GNUNET_FS_namespace_create (fs,
318                                    "testNamespace");
319   GNUNET_assert (NULL != ns);
320   meta = GNUNET_CONTAINER_meta_data_create ();
321   GNUNET_assert (NULL == emsg);
322   sks_expect_uri = GNUNET_FS_uri_dup (uri);
323   GNUNET_FS_publish_sks (fs,
324                          ns,
325                          "this",
326                          "next",
327                          meta,
328                          uri, /* FIXME: this is non-sense (use CHK URI!?) */
329                          expiration,
330                          1, 1,
331                          GNUNET_FS_PUBLISH_OPTION_NONE,
332                          &sks_cont,
333                          NULL);
334   GNUNET_CONTAINER_meta_data_destroy (meta);
335   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
336 }
337
338
339 static void
340 ns_iterator (void *cls,
341              const char *name,
342              const GNUNET_HashCode *id)
343 {
344   int *ok = cls;
345
346   if (0 != strcmp (name,
347                    "testNamespace"))
348     return;
349   *ok = GNUNET_YES;
350   nsid = *id;
351 }
352
353
354 static void
355 testNamespace ()
356 {
357   struct GNUNET_FS_Namespace *ns;
358   struct GNUNET_TIME_Absolute expiration;
359   struct GNUNET_CONTAINER_MetaData *meta;
360   struct GNUNET_FS_Uri *ksk_uri;
361   int ok;
362
363   ns = GNUNET_FS_namespace_create (fs,
364                                    "testNamespace");
365   GNUNET_assert (NULL != ns);
366   ok = GNUNET_NO;
367   GNUNET_FS_namespace_list (fs, &ns_iterator, &ok);
368   if (GNUNET_NO == ok)
369     {
370       fprintf (stderr, "namespace_list failed to find namespace!\n");
371       GNUNET_FS_namespace_delete (ns, GNUNET_YES);
372       GNUNET_FS_stop (fs);
373       err = 1;
374       return;
375     }
376   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
377   meta = GNUNET_CONTAINER_meta_data_create ();
378   ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL);
379   GNUNET_FS_namespace_advertise (fs,
380                                  ksk_uri,
381                                  ns,
382                                  meta,
383                                  1, 1,
384                                  expiration,                                       
385                                  "root",
386                                  &adv_cont, NULL);
387   kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
388                                             &do_timeout,
389                                             NULL);
390   GNUNET_FS_uri_destroy (ksk_uri);
391   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
392   GNUNET_CONTAINER_meta_data_destroy (meta);
393 }
394
395
396 static void
397 run (void *cls,
398      char *const *args,
399      const char *cfgfile,
400      const struct GNUNET_CONFIGURATION_Handle *cfg)
401 {
402   setup_peer (&p1, "test_fs_namespace_data.conf");
403   fs = GNUNET_FS_start (cfg,
404                         "test-fs-namespace",
405                         &progress_cb,
406                         NULL,
407                         GNUNET_FS_FLAGS_NONE,
408                         GNUNET_FS_OPTIONS_END);
409   testNamespace ();
410 }
411
412
413 int
414 main (int argc, char *argv[])
415 {
416   char *const argvx[] = { 
417     "test-fs-namespace",
418     "-c",
419     "test_fs_namespace_data.conf",
420 #if VERBOSE
421     "-L", "DEBUG",
422 #endif
423     NULL
424   };
425   struct GNUNET_GETOPT_CommandLineOption options[] = {
426     GNUNET_GETOPT_OPTION_END
427   };
428
429   GNUNET_log_setup ("test_fs_namespace", 
430 #if VERBOSE
431                     "DEBUG",
432 #else
433                     "WARNING",
434 #endif
435                     NULL);
436   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
437                       argvx, "test-fs-namespace",
438                       "nohelp", options, &run, NULL);
439   stop_arm (&p1);
440   if (GNUNET_YES != update_started)
441     {
442       fprintf (stderr,
443                "Update search never started!\n");
444       err = 1;
445     }
446   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/");
447   return err;
448 }
449
450
451 /* end of test_fs_namespace.c */