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