b4d487ddc3c1dc80a2b671d482f0939531dc0c0c
[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_NO
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 (NULL != p->arm_proc)
85     {
86       if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
87         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
88       if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
89         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
90       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
91                   "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc));
92       GNUNET_OS_process_close (p->arm_proc);
93       p->arm_proc = NULL;
94     }
95 #endif
96   GNUNET_CONFIGURATION_destroy (p->cfg);
97 }
98
99
100 static void
101 abort_ksk_search_task (void *cls,
102                        const struct GNUNET_SCHEDULER_TaskContext *tc)
103 {
104   if (ksk_search != NULL)
105     {
106       GNUNET_FS_search_stop (ksk_search);
107       ksk_search = NULL;
108       if (sks_search == NULL)
109         {
110           GNUNET_FS_stop (fs);
111           if (GNUNET_SCHEDULER_NO_TASK  != kill_task)
112             GNUNET_SCHEDULER_cancel (kill_task);
113         }
114     }
115 }
116
117
118 static void
119 abort_sks_search_task (void *cls,
120                        const struct GNUNET_SCHEDULER_TaskContext *tc)
121 {
122   struct GNUNET_FS_Namespace *ns;
123
124   if (sks_search == NULL)
125     return;
126   GNUNET_FS_search_stop (sks_search); 
127   sks_search = NULL;
128   ns = GNUNET_FS_namespace_create (fs,
129                                    "testNamespace");
130   GNUNET_assert (NULL != ns);
131   GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES));
132   if (ksk_search == NULL)
133     {
134       GNUNET_FS_stop (fs);
135       if (GNUNET_SCHEDULER_NO_TASK  != kill_task)
136         GNUNET_SCHEDULER_cancel (kill_task);
137     }    
138 }
139
140
141 static void
142 do_timeout (void *cls,
143             const struct GNUNET_SCHEDULER_TaskContext *tc)
144 {
145   fprintf (stderr,
146            "Operation timed out\n");
147   kill_task = GNUNET_SCHEDULER_NO_TASK;
148   abort_sks_search_task (NULL, tc);
149   abort_ksk_search_task (NULL, tc);
150 }
151
152
153
154 static void *
155 progress_cb (void *cls, 
156              const struct GNUNET_FS_ProgressInfo *event)
157 {
158   switch (event->status)
159     {
160     case GNUNET_FS_STATUS_SEARCH_RESULT:
161       if (sks_search == event->value.search.sc)
162         {
163           if (! GNUNET_FS_uri_test_equal (sks_expect_uri,
164                                           event->value.search.specifics.result.uri))
165             {
166               fprintf (stderr,
167                        "Wrong result for sks search!\n");
168               err = 1;
169             }
170           /* give system 1ms to initiate update search! */
171           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
172                                         &abort_sks_search_task,
173                                         NULL);
174         }
175       else if (ksk_search == event->value.search.sc)
176         {
177           if (! GNUNET_FS_uri_test_equal (ksk_expect_uri,
178                                           event->value.search.specifics.result.uri))
179             {
180               fprintf (stderr,
181                        "Wrong result for ksk search!\n");
182               err = 1;
183             }
184           GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task,
185                                              NULL,
186                                              GNUNET_SCHEDULER_REASON_PREREQ_DONE);
187         }
188       else 
189         {
190           fprintf (stderr,
191                    "Unexpected search result received!\n");
192           GNUNET_break (0);
193         }
194       break;
195     case GNUNET_FS_STATUS_SEARCH_ERROR:
196       fprintf (stderr,
197                "Error searching file: %s\n",
198                event->value.search.specifics.error.message);
199       if (sks_search == event->value.search.sc)
200         GNUNET_SCHEDULER_add_continuation (&abort_sks_search_task,
201                                            NULL,
202                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
203       else if (ksk_search == event->value.search.sc)
204         GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task,
205                                            NULL,
206                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
207       else
208         GNUNET_break (0);
209       break;
210     case GNUNET_FS_STATUS_SEARCH_START:
211       GNUNET_assert ( (NULL == event->value.search.cctx) ||
212                       (0 == strcmp ("sks_search", event->value.search.cctx)) ||
213                       (0 == strcmp ("ksk_search", event->value.search.cctx)));
214       if (NULL == event->value.search.cctx)
215         {
216           GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx));
217           update_started = GNUNET_YES;
218         }
219       GNUNET_assert (1 == event->value.search.anonymity);
220       break;
221     case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
222       return NULL;
223     case GNUNET_FS_STATUS_SEARCH_STOPPED:
224       return NULL;
225     default:
226       fprintf (stderr,
227                "Unexpected event: %d\n", 
228                event->status);
229       break;
230     }
231   return event->value.search.cctx;
232 }
233
234
235 static void
236 publish_cont (void *cls,
237               const struct GNUNET_FS_Uri *ksk_uri,
238               const char *emsg)
239 {
240   char *msg;
241   struct GNUNET_FS_Uri *sks_uri;
242   char sbuf[1024];
243   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
244   
245   if (NULL != emsg)
246     {
247       fprintf (stderr, "Error publishing: %s\n", emsg);
248       err = 1;
249       GNUNET_FS_stop (fs);
250       return;
251     }  
252   GNUNET_CRYPTO_hash_to_enc (&nsid,
253                              &enc);
254   GNUNET_snprintf (sbuf,
255                    sizeof (sbuf),
256                    "gnunet://fs/sks/%s/this",
257                    &enc);
258   sks_uri = GNUNET_FS_uri_parse (sbuf, &msg);
259   if (msg != NULL)
260     {
261       fprintf (stderr, "failed to parse URI `%s': %s\n",
262                sbuf,
263                msg);
264       err = 1;
265       GNUNET_FS_stop (fs);
266       GNUNET_free (msg);
267       return;
268     }
269   ksk_search = GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "ksk_search");
270   sks_search = GNUNET_FS_search_start (fs, sks_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "sks_search");
271   GNUNET_FS_uri_destroy (sks_uri);
272 }
273
274
275 static void
276 sks_cont (void *cls,
277           const struct GNUNET_FS_Uri *uri,
278           const char *emsg)
279 {
280   struct GNUNET_CONTAINER_MetaData *meta;
281   struct GNUNET_FS_Uri *ksk_uri;
282   char * msg;
283   struct GNUNET_FS_BlockOptions bo;
284
285   meta = GNUNET_CONTAINER_meta_data_create ();
286   msg = NULL;
287   ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg);
288   GNUNET_assert (NULL == msg);
289   ksk_expect_uri = GNUNET_FS_uri_dup (uri);
290   bo.content_priority = 1;
291   bo.anonymity_level = 1;
292   bo.replication_level = 0;
293   bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
294   GNUNET_FS_publish_ksk (fs,
295                          ksk_uri,
296                          meta,
297                          uri,
298                          &bo,
299                          GNUNET_FS_PUBLISH_OPTION_NONE,
300                          &publish_cont,
301                          NULL);
302   GNUNET_FS_uri_destroy (ksk_uri);
303   GNUNET_CONTAINER_meta_data_destroy (meta);
304 }
305
306
307 static void
308 adv_cont (void *cls,
309           const struct GNUNET_FS_Uri *uri,
310           const char *emsg)
311 {
312   struct GNUNET_CONTAINER_MetaData *meta;
313   struct GNUNET_FS_Namespace *ns;
314   struct GNUNET_FS_BlockOptions bo;
315
316   if (NULL != emsg)
317     {
318       fprintf (stderr, "Error publishing: %s\n", emsg);
319       err = 1;
320       GNUNET_FS_stop (fs);
321       return;
322     }
323   ns = GNUNET_FS_namespace_create (fs,
324                                    "testNamespace");
325   GNUNET_assert (NULL != ns);
326   meta = GNUNET_CONTAINER_meta_data_create ();
327   GNUNET_assert (NULL == emsg);
328   sks_expect_uri = GNUNET_FS_uri_dup (uri);
329   bo.content_priority = 1;
330   bo.anonymity_level = 1;
331   bo.replication_level = 0;
332   bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
333   GNUNET_FS_publish_sks (fs,
334                          ns,
335                          "this",
336                          "next",
337                          meta,
338                          uri, /* FIXME: this is non-sense (use CHK URI!?) */
339                          &bo,
340                          GNUNET_FS_PUBLISH_OPTION_NONE,
341                          &sks_cont,
342                          NULL);
343   GNUNET_CONTAINER_meta_data_destroy (meta);
344   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
345 }
346
347
348 static void
349 ns_iterator (void *cls,
350              const char *name,
351              const GNUNET_HashCode *id)
352 {
353   int *ok = cls;
354
355   if (0 != strcmp (name,
356                    "testNamespace"))
357     return;
358   *ok = GNUNET_YES;
359   nsid = *id;
360 }
361
362
363 static void
364 testNamespace ()
365 {
366   struct GNUNET_FS_Namespace *ns;
367   struct GNUNET_FS_BlockOptions bo;
368   struct GNUNET_CONTAINER_MetaData *meta;
369   struct GNUNET_FS_Uri *ksk_uri;
370   int ok;
371
372   ns = GNUNET_FS_namespace_create (fs,
373                                    "testNamespace");
374   GNUNET_assert (NULL != ns);
375   ok = GNUNET_NO;
376   GNUNET_FS_namespace_list (fs, &ns_iterator, &ok);
377   if (GNUNET_NO == ok)
378     {
379       fprintf (stderr, "namespace_list failed to find namespace!\n");
380       GNUNET_FS_namespace_delete (ns, GNUNET_YES);
381       GNUNET_FS_stop (fs);
382       err = 1;
383       return;
384     }
385   meta = GNUNET_CONTAINER_meta_data_create ();
386   ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL);
387   bo.content_priority = 1;
388   bo.anonymity_level = 1;
389   bo.replication_level = 0;
390   bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
391   GNUNET_FS_namespace_advertise (fs,
392                                  ksk_uri,
393                                  ns,
394                                  meta,
395                                  &bo,
396                                  "root",
397                                  &adv_cont, NULL);
398   kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
399                                             &do_timeout,
400                                             NULL);
401   GNUNET_FS_uri_destroy (ksk_uri);
402   GNUNET_FS_namespace_delete (ns, GNUNET_NO);
403   GNUNET_CONTAINER_meta_data_destroy (meta);
404 }
405
406
407 static void
408 run (void *cls,
409      char *const *args,
410      const char *cfgfile,
411      const struct GNUNET_CONFIGURATION_Handle *cfg)
412 {
413   setup_peer (&p1, "test_fs_namespace_data.conf");
414   fs = GNUNET_FS_start (cfg,
415                         "test-fs-namespace",
416                         &progress_cb,
417                         NULL,
418                         GNUNET_FS_FLAGS_NONE,
419                         GNUNET_FS_OPTIONS_END);
420   testNamespace ();
421 }
422
423
424 int
425 main (int argc, char *argv[])
426 {
427   char *const argvx[] = { 
428     "test-fs-namespace",
429     "-c",
430     "test_fs_namespace_data.conf",
431 #if VERBOSE
432     "-L", "DEBUG",
433 #endif
434     NULL
435   };
436   struct GNUNET_GETOPT_CommandLineOption options[] = {
437     GNUNET_GETOPT_OPTION_END
438   };
439
440   GNUNET_log_setup ("test_fs_namespace", 
441 #if VERBOSE
442                     "DEBUG",
443 #else
444                     "WARNING",
445 #endif
446                     NULL);
447   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
448                       argvx, "test-fs-namespace",
449                       "nohelp", options, &run, NULL);
450   stop_arm (&p1);
451   if (GNUNET_YES != update_started)
452     {
453       fprintf (stderr,
454                "Update search never started!\n");
455       err = 1;
456     }
457   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/");
458   return err;
459 }
460
461
462 /* end of test_fs_namespace.c */