94405a8137bfe1847d92da5a735480ad5d3e08a9
[oweals/gnunet.git] / src / fs / test_fs_download_persistence.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file fs/test_fs_download_persistence.c
21  * @brief simple testcase for persistence of simple download operation
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_testing_lib.h"
27 #include "gnunet_fs_service.h"
28
29 /**
30  * File-size we use for testing.
31  */
32 #define FILESIZE (1024 * 1024 * 2)
33
34 /**
35  * How long until we give up on transmitting the message?
36  */
37 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
38
39 /**
40  * How long should our test-content live?
41  */
42 #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
43
44
45 static struct GNUNET_TIME_Absolute start;
46
47 static const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49 static struct GNUNET_FS_Handle *fs;
50
51 static struct GNUNET_FS_DownloadContext *download;
52
53 static struct GNUNET_FS_PublishContext *publish;
54
55 static struct GNUNET_SCHEDULER_Task * timeout_kill;
56
57 static char *fn;
58
59 static int err;
60
61
62 static void
63 timeout_kill_task (void *cls)
64 {
65   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n");
66   if (download != NULL)
67   {
68     GNUNET_FS_download_stop (download, GNUNET_YES);
69     download = NULL;
70   }
71   else if (publish != NULL)
72   {
73     GNUNET_FS_publish_stop (publish);
74     publish = NULL;
75   }
76   timeout_kill = NULL;
77   err = 1;
78 }
79
80
81 static void
82 abort_publish_task (void *cls)
83 {
84   if (publish != NULL)
85   {
86     GNUNET_FS_publish_stop (publish);
87     publish = NULL;
88   }
89 }
90
91
92 static void
93 abort_download_task (void *cls)
94 {
95   uint64_t size;
96
97   if (download != NULL)
98   {
99     GNUNET_FS_download_stop (download, GNUNET_YES);
100     download = NULL;
101   }
102   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, GNUNET_NO));
103   GNUNET_assert (size == FILESIZE);
104   GNUNET_DISK_directory_remove (fn);
105   GNUNET_free (fn);
106   fn = NULL;
107   GNUNET_SCHEDULER_cancel (timeout_kill);
108   timeout_kill = NULL;
109 }
110
111
112 static void *
113 progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event);
114
115
116 static void
117 restart_fs_task (void *cls)
118 {
119   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting FS.\n");
120   GNUNET_FS_stop (fs);
121   fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL,
122                         GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END);
123 }
124
125
126 /**
127  * Consider scheduling the restart-task.
128  * Only runs the restart task once per event
129  * category.
130  *
131  * @param ev type of the event to consider
132  */
133 static void
134 consider_restart (int ev)
135 {
136   static int prev[32];
137   static int off;
138   int i;
139
140   for (i = 0; i < off; i++)
141     if (prev[i] == ev)
142       return;
143   prev[off++] = ev;
144   GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT,
145                                       &restart_fs_task, NULL);
146 }
147
148
149 static void *
150 progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event)
151 {
152   switch (event->status)
153   {
154   case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
155     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156                 "Publish is progressing (%llu/%llu at level %u off %llu)...\n",
157                 (unsigned long long) event->value.publish.completed,
158                 (unsigned long long) event->value.publish.size,
159                 event->value.publish.specifics.progress.depth,
160                 (unsigned long long) event->value.publish.specifics.
161                 progress.offset);
162     break;
163   case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
164     break;
165   case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
166     printf ("Publishing complete, %llu kbps.\n",
167             (unsigned long long) (FILESIZE * 1000000LL /
168                                   (1 +
169                                    GNUNET_TIME_absolute_get_duration
170                                    (start).rel_value_us) / 1024LL));
171     fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst");
172     start = GNUNET_TIME_absolute_get ();
173     GNUNET_assert (download == NULL);
174     GNUNET_FS_download_start (fs,
175                               event->value.publish.specifics.completed.chk_uri,
176                               NULL, fn, NULL, 0, FILESIZE, 1,
177                               GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL);
178     break;
179   case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
180     printf ("Download complete,  %llu kbps.\n",
181             (unsigned long long) (FILESIZE * 1000000LL /
182                                   (1 +
183                                    GNUNET_TIME_absolute_get_duration
184                                    (start).rel_value_us) / 1024LL));
185     GNUNET_SCHEDULER_add_now (&abort_download_task, NULL);
186     break;
187   case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
188     consider_restart (event->status);
189     GNUNET_assert (download == event->value.download.dc);
190     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191                 "Download is progressing (%llu/%llu at level %u off %llu)...\n",
192                 (unsigned long long) event->value.download.completed,
193                 (unsigned long long) event->value.download.size,
194                 event->value.download.specifics.progress.depth,
195                 (unsigned long long) event->value.download.specifics.
196                 progress.offset);
197     break;
198   case GNUNET_FS_STATUS_PUBLISH_ERROR:
199     FPRINTF (stderr, "Error publishing file: %s\n",
200              event->value.publish.specifics.error.message);
201     GNUNET_break (0);
202     GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL);
203     break;
204   case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
205     FPRINTF (stderr, "Error downloading file: %s\n",
206              event->value.download.specifics.error.message);
207     GNUNET_SCHEDULER_add_now (&abort_download_task, NULL);
208     break;
209   case GNUNET_FS_STATUS_PUBLISH_SUSPEND:
210     GNUNET_assert (event->value.publish.pc == publish);
211     publish = NULL;
212     break;
213   case GNUNET_FS_STATUS_PUBLISH_RESUME:
214     GNUNET_assert (NULL == publish);
215     publish = event->value.publish.pc;
216     break;
217   case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
218     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download suspended.\n");
219     GNUNET_assert (event->value.download.dc == download);
220     download = NULL;
221     break;
222   case GNUNET_FS_STATUS_DOWNLOAD_RESUME:
223     GNUNET_assert (NULL == download);
224     download = event->value.download.dc;
225     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download resumed.\n");
226     break;
227   case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
228     consider_restart (event->status);
229     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download active.\n");
230     break;
231   case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
232     consider_restart (event->status);
233     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download inactive.\n");
234     break;
235   case GNUNET_FS_STATUS_PUBLISH_START:
236     GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx));
237     GNUNET_assert (NULL == event->value.publish.pctx);
238     GNUNET_assert (FILESIZE == event->value.publish.size);
239     GNUNET_assert (0 == event->value.publish.completed);
240     GNUNET_assert (1 == event->value.publish.anonymity);
241     break;
242   case GNUNET_FS_STATUS_PUBLISH_STOPPED:
243     GNUNET_assert (publish == event->value.publish.pc);
244     GNUNET_assert (FILESIZE == event->value.publish.size);
245     GNUNET_assert (1 == event->value.publish.anonymity);
246     GNUNET_FS_stop (fs);
247     fs = NULL;
248     break;
249   case GNUNET_FS_STATUS_DOWNLOAD_START:
250     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download started.\n");
251     consider_restart (event->status);
252     GNUNET_assert (download == NULL);
253     download = event->value.download.dc;
254     GNUNET_assert (0 == strcmp ("download", event->value.download.cctx));
255     GNUNET_assert (NULL == event->value.download.pctx);
256     GNUNET_assert (NULL != event->value.download.uri);
257     GNUNET_assert (0 == strcmp (fn, event->value.download.filename));
258     GNUNET_assert (FILESIZE == event->value.download.size);
259     GNUNET_assert (0 == event->value.download.completed);
260     GNUNET_assert (1 == event->value.download.anonymity);
261     break;
262   case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
263     GNUNET_assert (download == event->value.download.dc);
264     GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL);
265     download = NULL;
266     break;
267   default:
268     printf ("Unexpected event: %d\n", event->status);
269     break;
270   }
271   return NULL;
272 }
273
274
275 static void
276 run (void *cls,
277      const struct GNUNET_CONFIGURATION_Handle *c,
278      struct GNUNET_TESTING_Peer *peer)
279 {
280   const char *keywords[] = {
281     "down_foo",
282     "down_bar",
283   };
284   char *buf;
285   struct GNUNET_CONTAINER_MetaData *meta;
286   struct GNUNET_FS_Uri *kuri;
287   struct GNUNET_FS_FileInformation *fi;
288   size_t i;
289   struct GNUNET_FS_BlockOptions bo;
290
291   cfg = c;
292   fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL,
293                         GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END);
294   GNUNET_assert (NULL != fs);
295   buf = GNUNET_malloc (FILESIZE);
296   for (i = 0; i < FILESIZE; i++)
297     buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256);
298   meta = GNUNET_CONTAINER_meta_data_create ();
299   kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords);
300   bo.content_priority = 42;
301   bo.anonymity_level = 1;
302   bo.replication_level = 0;
303   bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME);
304   fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context",
305                                                     FILESIZE, buf, kuri, meta,
306                                                     GNUNET_NO, &bo);
307   GNUNET_FS_uri_destroy (kuri);
308   GNUNET_CONTAINER_meta_data_destroy (meta);
309   GNUNET_assert (NULL != fi);
310   timeout_kill =
311       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL);
312   start = GNUNET_TIME_absolute_get ();
313   publish =
314       GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL,
315                                GNUNET_FS_PUBLISH_OPTION_NONE);
316   GNUNET_assert (publish != NULL);
317 }
318
319
320 int
321 main (int argc, char *argv[])
322 {
323   if (0 != GNUNET_TESTING_peer_run ("test-fs-download-persistence",
324                                     "test_fs_download_data.conf",
325                                     &run, NULL))
326     return 1;
327   return err;
328 }
329
330 /* end of test_fs_download_persistence.c */