a7ccbeccf50955341c8e70f6f3f35cc330cc2e5e
[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 2, 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  * TODO:
27  * - add timeout task
28  */
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_arm_service.h"
32 #include "gnunet_fs_service.h"
33
34 #define VERBOSE GNUNET_YES
35
36 #define START_ARM GNUNET_YES
37
38 static struct GNUNET_SCHEDULER_Handle *sched;
39
40 static struct PeerContext p1;
41
42 static GNUNET_HashCode nsid;
43
44 static struct GNUNET_FS_Uri *sks_expect_uri;
45
46 static struct GNUNET_FS_Uri *ksk_expect_uri;
47
48 static struct GNUNET_FS_Handle *fs;
49
50 static struct GNUNET_FS_SearchContext *sks_search;
51
52 static struct GNUNET_FS_SearchContext *ksk_search;
53
54 static int update_started;
55
56 static int err;
57
58 struct PeerContext
59 {
60   struct GNUNET_CONFIGURATION_Handle *cfg;
61 #if START_ARM
62   pid_t arm_pid;
63 #endif
64 };
65
66
67 static void
68 setup_peer (struct PeerContext *p, const char *cfgname)
69 {
70   p->cfg = GNUNET_CONFIGURATION_create ();
71 #if START_ARM
72   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
73                                         "gnunet-service-arm",
74 #if VERBOSE
75                                         "-L", "DEBUG",
76 #endif
77                                         "-c", cfgname, NULL);
78 #endif
79   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
80   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
81 }
82
83
84 static void
85 stop_arm (struct PeerContext *p)
86 {
87 #if START_ARM
88   if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
89     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
90   if (GNUNET_OS_process_wait(p->arm_pid) != GNUNET_OK)
91     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
92   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93               "ARM process %u stopped\n", p->arm_pid);
94 #endif
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           fprintf (stderr, "initiating shutdown\n");
110           GNUNET_FS_stop (fs);
111         }
112     }
113 }
114
115
116 static void
117 abort_sks_search_task (void *cls,
118                        const struct GNUNET_SCHEDULER_TaskContext *tc)
119 {
120   struct GNUNET_FS_Namespace *ns;
121
122   if (sks_search == NULL)
123     return;
124   GNUNET_FS_search_stop (sks_search); 
125   sks_search = NULL;
126   ns = GNUNET_FS_namespace_create (fs,
127                                    "testNamespace");
128   GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES));
129   if (ksk_search == NULL)
130     {
131       fprintf (stderr, "initiating shutdown\n");
132       GNUNET_FS_stop (fs);
133     }    
134 }
135
136
137 static void *
138 progress_cb (void *cls, 
139              const struct GNUNET_FS_ProgressInfo *event)
140 {
141   switch (event->status)
142     {
143     case GNUNET_FS_STATUS_SEARCH_RESULT:
144       if (sks_search == event->value.search.sc)
145         {
146           fprintf (stderr,
147                    "Search result for sks received\n");
148           if (! GNUNET_FS_uri_test_equal (sks_expect_uri,
149                                           event->value.search.specifics.result.uri))
150             {
151               fprintf (stderr,
152                        "Wrong result for sks search!\n");
153               err = 1;
154             }
155           /* give system 1ms to initiate update search! */
156           GNUNET_SCHEDULER_add_delayed (sched,
157                                         GNUNET_TIME_UNIT_MILLISECONDS,
158                                         &abort_sks_search_task,
159                                         NULL);
160         }
161       else if (ksk_search == event->value.search.sc)
162         {
163           fprintf (stderr,
164                    "Search result for ksk received\n");
165           if (! GNUNET_FS_uri_test_equal (ksk_expect_uri,
166                                           event->value.search.specifics.result.uri))
167             {
168               fprintf (stderr,
169                        "Wrong result for ksk search!\n");
170               err = 1;
171             }
172           GNUNET_SCHEDULER_add_continuation (sched,
173                                              &abort_ksk_search_task,
174                                              NULL,
175                                              GNUNET_SCHEDULER_REASON_PREREQ_DONE);
176         }
177       else 
178         {
179           fprintf (stderr,
180                    "Search result received!?\n");
181           GNUNET_break (0);
182         }
183       break;
184     case GNUNET_FS_STATUS_SEARCH_ERROR:
185       fprintf (stderr,
186                "Error searching file: %s\n",
187                event->value.search.specifics.error.message);
188       if (sks_search == event->value.search.sc)
189         GNUNET_SCHEDULER_add_continuation (sched,
190                                            &abort_sks_search_task,
191                                            NULL,
192                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
193       else if (ksk_search == event->value.search.sc)
194         GNUNET_SCHEDULER_add_continuation (sched,
195                                            &abort_ksk_search_task,
196                                            NULL,
197                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
198       else
199         GNUNET_break (0);
200       break;
201     case GNUNET_FS_STATUS_SEARCH_START:
202       fprintf (stderr,
203                "Search start event for `%s' received\n",
204                (const char*) event->value.search.cctx);
205       GNUNET_assert ( (NULL == event->value.search.cctx) ||
206                       (0 == strcmp ("sks_search", event->value.search.cctx)) ||
207                       (0 == strcmp ("ksk_search", event->value.search.cctx)));
208       if (NULL == event->value.search.cctx)
209         {
210           GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx));
211           update_started = GNUNET_YES;
212         }
213       GNUNET_assert (1 == event->value.search.anonymity);
214       break;
215     case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
216       return NULL;
217     case GNUNET_FS_STATUS_SEARCH_STOPPED:
218       fprintf (stderr,
219                "Search stop event received\n");
220       return NULL;
221     default:
222       fprintf (stderr,
223                "Unexpected event: %d\n", 
224                event->status);
225       break;
226     }
227   return event->value.search.cctx;
228 }
229
230
231 static void
232 publish_cont (void *cls,
233               const struct GNUNET_FS_Uri *ksk_uri,
234               const char *emsg)
235 {
236   char *msg;
237   struct GNUNET_FS_Uri *sks_uri;
238   char sbuf[1024];
239   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
240   
241   if (NULL != emsg)
242     {
243       fprintf (stderr, "Error publishing: %s\n", emsg);
244       err = 1;
245       GNUNET_FS_stop (fs);
246       return;
247     }  
248   GNUNET_CRYPTO_hash_to_enc (&nsid,
249                              &enc);
250   GNUNET_snprintf (sbuf,
251                    sizeof (sbuf),
252                    "gnunet://fs/sks/%s/this",
253                    &enc);
254   sks_uri = GNUNET_FS_uri_parse (sbuf, &msg);
255   if (msg != NULL)
256     {
257       fprintf (stderr, "failed to parse URI `%s': %s\n",
258                sbuf,
259                msg);
260       err = 1;
261       GNUNET_FS_stop (fs);
262       return;
263     }
264   fprintf (stderr, "Starting keyword search...\n");
265   ksk_search = GNUNET_FS_search_start (fs, ksk_uri, 1, "ksk_search");
266   fprintf (stderr, "Starting namespace search...\n") ;
267   sks_search = GNUNET_FS_search_start (fs, sks_uri, 1, "sks_search");
268   GNUNET_FS_uri_destroy (sks_uri);
269 }
270
271
272 static void
273 sks_cont (void *cls,
274           const struct GNUNET_FS_Uri *uri,
275           const char *emsg)
276 {
277   struct GNUNET_CONTAINER_MetaData *meta;
278   struct GNUNET_TIME_Absolute expiration;
279   struct GNUNET_FS_Uri *ksk_uri;
280   char * msg;
281
282   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
283   meta = GNUNET_CONTAINER_meta_data_create ();
284   msg = NULL;
285   ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg);
286   GNUNET_assert (NULL == msg);
287   fprintf (stderr, "Advertising update 'this' namespace entry under keyword...\n");
288   ksk_expect_uri = GNUNET_FS_uri_dup (uri);
289   GNUNET_FS_publish_ksk (fs,
290                          ksk_uri,
291                          meta,
292                          uri,
293                          expiration,
294                          1, 1,
295                          GNUNET_FS_PUBLISH_OPTION_NONE,
296                          &publish_cont,
297                          NULL);
298   GNUNET_FS_uri_destroy (ksk_uri);
299   GNUNET_CONTAINER_meta_data_destroy (meta);
300 }
301
302
303 static void
304 adv_cont (void *cls,
305               const struct GNUNET_FS_Uri *uri,
306               const char *emsg)
307 {
308   struct GNUNET_CONTAINER_MetaData *meta;
309   struct GNUNET_FS_Namespace *ns;
310   struct GNUNET_TIME_Absolute expiration;
311
312   if (NULL != emsg)
313     {
314       fprintf (stderr, "Error publishing: %s\n", emsg);
315       err = 1;
316       GNUNET_FS_stop (fs);
317       return;
318     }
319   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
320   ns = GNUNET_FS_namespace_create (fs,
321                                    "testNamespace");
322   meta = GNUNET_CONTAINER_meta_data_create ();
323   GNUNET_assert (NULL == emsg);
324   fprintf (stderr, "Advertising update 'this->next' namespace update...\n");
325   sks_expect_uri = GNUNET_FS_uri_dup (uri);
326   GNUNET_FS_publish_sks (fs,
327                          ns,
328                          "this",
329                          "next",
330                          meta,
331                          uri, /* FIXME: this is non-sense (use CHK URI!?) */
332                          expiration,
333                          1, 1,
334                          GNUNET_FS_PUBLISH_OPTION_NONE,
335                          &sks_cont,
336                          NULL);
337   GNUNET_CONTAINER_meta_data_destroy (meta);
338   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
339 }
340
341
342 static void
343 ns_iterator (void *cls,
344              const char *name,
345              const GNUNET_HashCode *id)
346 {
347   int *ok = cls;
348
349   if (0 != strcmp (name,
350                    "testNamespace"))
351     return;
352   *ok = GNUNET_YES;
353   nsid = *id;
354 }
355
356
357 static void
358 testNamespace ()
359 {
360   struct GNUNET_FS_Namespace *ns;
361   struct GNUNET_TIME_Absolute expiration;
362   struct GNUNET_CONTAINER_MetaData *meta;
363   int ok;
364
365   ns = GNUNET_FS_namespace_create (fs,
366                                    "testNamespace");
367   ok = GNUNET_NO;
368   GNUNET_FS_namespace_list (fs, &ns_iterator, &ok);
369   if (GNUNET_NO == ok)
370     {
371       fprintf (stderr, "namespace_list failed to find namespace!\n");
372       GNUNET_FS_namespace_delete (ns, GNUNET_YES);
373       GNUNET_FS_stop (fs);
374       err = 1;
375       return;
376     }
377   fprintf (stderr, "Advertising namespace root...\n");
378   expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
379   meta = GNUNET_CONTAINER_meta_data_create ();
380   GNUNET_FS_namespace_advertise (fs,
381                                  ns,
382                                  meta,
383                                  1, 1,
384                                  expiration,                                       
385                                  "root",
386                                  &adv_cont, NULL);
387   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
388   GNUNET_CONTAINER_meta_data_destroy (meta);
389 }
390
391
392 static void
393 run (void *cls,
394      struct GNUNET_SCHEDULER_Handle *s,
395      char *const *args,
396      const char *cfgfile,
397      const struct GNUNET_CONFIGURATION_Handle *cfg)
398 {
399   sched = s;
400   setup_peer (&p1, "test_fs_namespace_data.conf");
401   fs = GNUNET_FS_start (sched,
402                         cfg,
403                         "test-fs-namespace",
404                         &progress_cb,
405                         NULL,
406                         GNUNET_FS_FLAGS_NONE,
407                         GNUNET_FS_OPTIONS_END);
408   testNamespace ();
409 }
410
411
412 int
413 main (int argc, char *argv[])
414 {
415   char *const argvx[] = { 
416     "test-fs-namespace",
417     "-c",
418     "test_fs_namespace_data.conf",
419 #if VERBOSE
420     "-L", "DEBUG",
421 #endif
422     NULL
423   };
424   struct GNUNET_GETOPT_CommandLineOption options[] = {
425     GNUNET_GETOPT_OPTION_END
426   };
427
428   GNUNET_log_setup ("test_fs_namespace", 
429 #if VERBOSE
430                     "DEBUG",
431 #else
432                     "WARNING",
433 #endif
434                     NULL);
435   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
436                       argvx, "test-fs-namespace",
437                       "nohelp", options, &run, NULL);
438   stop_arm (&p1);
439   if (GNUNET_YES != update_started)
440     {
441       fprintf (stderr,
442                "Update search never started!\n");
443       err = 1;
444     }
445   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/");
446   return err;
447 }
448
449
450 /* end of test_fs_namespace.c */