Merge branch 'master' of git+ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / fs / fs_test_lib.c
index fb179e8a4da3be76292f7538a9895ece59390bd1..d03888021f70395aedb01db389822dd8a230367f 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2010, 2011, 2012 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file fs/fs_test_lib.c
 */
 
 /**
  * @file fs/fs_test_lib.c
- * @brief library routines for testing FS publishing and downloading
- *        with multiple peers; this code is limited to flat files
+ * @brief library routines for testing FS publishing and downloading;
+ *        this code is limited to flat files
  *        and no keywords (those functions can be tested with
  *        single-peer setups; this is for testing routing).
  * @author Christian Grothoff
  */
 #include "platform.h"
  *        and no keywords (those functions can be tested with
  *        single-peer setups; this is for testing routing).
  * @author Christian Grothoff
  */
 #include "platform.h"
+#include "fs_api.h"
 #include "fs_test_lib.h"
 #include "fs_test_lib.h"
-#include "gnunet_testing_lib.h"
+
+
+#define CONTENT_LIFETIME GNUNET_TIME_UNIT_HOURS
 
 
 /**
 
 
 /**
- * Handle for a daemon started for testing FS.
+ * Handle for a publishing operation started for testing FS.
  */
  */
-struct GNUNET_FS_TestDaemon
+struct TestPublishOperation
 {
 
 {
 
+  /**
+   * Handle for the operation to connect to the peer's 'fs' service.
+   */
+  struct GNUNET_TESTBED_Operation *fs_op;
+
   /**
    * Handle to the file sharing context using this daemon.
    */
   struct GNUNET_FS_Handle *fs;
 
   /**
   /**
    * Handle to the file sharing context using this daemon.
    */
   struct GNUNET_FS_Handle *fs;
 
   /**
-   * Handle to the daemon via testing.
+   * Function to call when upload is done.
    */
    */
-  struct GNUNET_TESTING_Daemon *daemon;
+  GNUNET_FS_TEST_UriContinuation publish_cont;
 
   /**
 
   /**
-   * Note that 'group' will be the same value for all of the
-   * daemons started jointly.
+   * Closure for publish_cont.
    */
    */
-  struct GNUNET_TESTING_PeerGroup *group;
+  void *publish_cont_cls;
 
   /**
 
   /**
-   * Configuration for accessing this peer.
+   * Task to abort publishing (timeout).
    */
    */
-  struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct GNUNET_SCHEDULER_Task * publish_timeout_task;
 
   /**
 
   /**
-   * ID of this peer.
+   * Seed for file generation.
    */
    */
-  struct GNUNET_PeerIdentity id;
+  uint32_t publish_seed;
 
   /**
 
   /**
-   * Scheduler to use (for publish_cont).
+   * Context for current publishing operation.
    */
    */
-  struct GNUNET_SCHEDULER_Handle *publish_sched;
+  struct GNUNET_FS_PublishContext *publish_context;
 
   /**
 
   /**
-   * Function to call when upload is done.
+   * Result URI.
    */
    */
-  GNUNET_FS_TEST_UriContinuation publish_cont;
-  
+  struct GNUNET_FS_Uri *publish_uri;
+
   /**
   /**
-   * Closure for publish_cont.
+   * Name of the temporary file used, or NULL for none.
    */
    */
-  void *publish_cont_cls;
+  char *publish_tmp_file;
 
   /**
 
   /**
-   * Task to abort publishing (timeout).
+   * Size of the file.
    */
    */
-  GNUNET_SCHEDULER_TaskIdentifier publish_timeout_task;
+  uint64_t size;
 
   /**
 
   /**
-   * Seed for file generation.
+   * Anonymity level used.
    */
    */
-  uint32_t publish_seed;
+  uint32_t anonymity;
 
   /**
 
   /**
-   * Context for current publishing operation.
+   * Verbosity level of the current operation.
    */
    */
-  struct GNUNET_FS_PublishContext *publish_context;
+  unsigned int verbose;
 
   /**
 
   /**
-   * Result URI.
+   * Are we testing indexing? (YES: index, NO: insert, SYSERR: simulate)
    */
    */
-  struct GNUNET_FS_Uri *publish_uri;
+  int do_index;
+};
+
+
+/**
+ * Handle for a download operation started for testing FS.
+ */
+struct TestDownloadOperation
+{
+
+  /**
+   * Handle for the operation to connect to the peer's 'fs' service.
+   */
+  struct GNUNET_TESTBED_Operation *fs_op;
+
+  /**
+   * Handle to the file sharing context using this daemon.
+   */
+  struct GNUNET_FS_Handle *fs;
 
   /**
 
   /**
-   * Scheduler to use (for download_cont).
+   * Handle to the daemon via testing.
    */
    */
-  struct GNUNET_SCHEDULER_Handle *download_sched;
+  struct GNUNET_TESTING_Daemon *daemon;
 
   /**
    * Function to call when download is done.
    */
 
   /**
    * Function to call when download is done.
    */
-  GNUNET_SCHEDULER_Task download_cont;
+  GNUNET_SCHEDULER_TaskCallback download_cont;
 
   /**
    * Closure for download_cont.
 
   /**
    * Closure for download_cont.
@@ -114,461 +139,476 @@ struct GNUNET_FS_TestDaemon
   void *download_cont_cls;
 
   /**
   void *download_cont_cls;
 
   /**
-   * Seed for download verification.
+   * URI to download.
    */
    */
-  uint32_t download_seed;
+  struct GNUNET_FS_Uri *uri;
 
   /**
    * Task to abort downloading (timeout).
    */
 
   /**
    * Task to abort downloading (timeout).
    */
-  GNUNET_SCHEDULER_TaskIdentifier download_timeout_task;
+  struct GNUNET_SCHEDULER_Task * download_timeout_task;
 
   /**
    * Context for current download operation.
 
   /**
    * Context for current download operation.
-   */  
+   */
   struct GNUNET_FS_DownloadContext *download_context;
 
   struct GNUNET_FS_DownloadContext *download_context;
 
+  /**
+   * Size of the file.
+   */
+  uint64_t size;
+
+  /**
+   * Anonymity level used.
+   */
+  uint32_t anonymity;
+
+  /**
+   * Seed for download verification.
+   */
+  uint32_t download_seed;
+
   /**
    * Verbosity level of the current operation.
    */
   /**
    * Verbosity level of the current operation.
    */
-  int verbose;
+  unsigned int verbose;
 
 
-               
 };
 
 
 };
 
 
+/**
+ * Task scheduled to report on the completion of our publish operation.
+ *
+ * @param cls the publish operation context
+ * @param tc scheduler context (unused)
+ */
 static void
 static void
-report_uri (void *cls,
-           const struct GNUNET_SCHEDULER_TaskContext *tc)
+report_uri (void *cls)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
-  GNUNET_FS_TEST_UriContinuation cont;
-  struct GNUNET_FS_Uri *uri;
-
-  GNUNET_FS_publish_stop (daemon->publish_context);
-  daemon->publish_context = NULL;
-  daemon->publish_sched = NULL;
-  cont = daemon->publish_cont;
-  daemon->publish_cont = NULL;
-  uri = daemon->publish_uri;
-  cont (daemon->publish_cont_cls,
-       uri);
-  GNUNET_FS_uri_destroy (uri);
-}           
+  struct TestPublishOperation *po = cls;
+
+  GNUNET_FS_publish_stop (po->publish_context);
+  GNUNET_TESTBED_operation_done (po->fs_op);
+  po->publish_cont (po->publish_cont_cls,
+                   po->publish_uri,
+                   (GNUNET_YES == po->do_index)
+                   ? po->publish_tmp_file
+                   : NULL);
+  GNUNET_FS_uri_destroy (po->publish_uri);
+  if ( (GNUNET_YES != po->do_index) &&
+       (NULL != po->publish_tmp_file) )
+    (void) GNUNET_DISK_directory_remove (po->publish_tmp_file);
+  GNUNET_free_non_null (po->publish_tmp_file);
+  GNUNET_free (po);
+}
 
 
 
 
+/**
+ * Task scheduled to run when publish operation times out.
+ *
+ * @param cls the publish operation context
+ */
 static void
 static void
-report_success (void *cls,
-               const struct GNUNET_SCHEDULER_TaskContext *tc)
+publish_timeout (void *cls)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
-
-  GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES);
-  daemon->download_context = NULL;
-  GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
-                                    daemon->download_cont,
-                                    daemon->download_cont_cls,
-                                    GNUNET_SCHEDULER_REASON_PREREQ_DONE);      
-  daemon->download_cont = NULL;
-  daemon->download_sched = NULL;
+  struct TestPublishOperation *po = cls;
+
+  po->publish_timeout_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Timeout while trying to publish data\n");
+  GNUNET_TESTBED_operation_done (po->fs_op);
+  GNUNET_FS_publish_stop (po->publish_context);
+  po->publish_cont (po->publish_cont_cls, NULL, NULL);
+  (void) GNUNET_DISK_directory_remove (po->publish_tmp_file);
+  GNUNET_free_non_null (po->publish_tmp_file);
+  GNUNET_free (po);
 }
 
 }
 
-static void*
-progress_cb (void *cls,
-            const struct GNUNET_FS_ProgressInfo *info)
+
+/**
+ * Progress callback for file-sharing events while publishing.
+ *
+ * @param cls the publish operation context
+ * @param info information about the event
+ */
+static void *
+publish_progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
+  struct TestPublishOperation *po = cls;
 
   switch (info->status)
 
   switch (info->status)
-    {
-    case GNUNET_FS_STATUS_PUBLISH_COMPLETED:      
-      GNUNET_SCHEDULER_cancel (daemon->publish_sched,
-                              daemon->publish_timeout_task);
-      daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK;
-      daemon->publish_uri = GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri);
-      GNUNET_SCHEDULER_add_continuation (daemon->publish_sched,
-                                        &report_uri,
-                                        daemon,
-                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
-      break;
-    case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
-      if (daemon->verbose)
-       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                   "Download at %llu/%llu bytes\n",
-                   (unsigned long long) info->value.download.completed,
-                   (unsigned long long) info->value.download.size);
-      break;
-    case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
-      GNUNET_SCHEDULER_cancel (daemon->download_sched,
-                              daemon->download_timeout_task);
-      daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK;
-      GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
-                                        &report_success,
-                                        daemon,
-                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
-      break;
-      /* FIXME: monitor data correctness during download progress */
-      /* FIXME: do performance reports given sufficient verbosity */
-      /* FIXME: advance timeout task to "immediate" on error */
-    default:
-      break;
-    }
+  {
+  case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
+    GNUNET_SCHEDULER_cancel (po->publish_timeout_task);
+    po->publish_timeout_task = NULL;
+    po->publish_uri =
+        GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri);
+    GNUNET_SCHEDULER_add_now (&report_uri,
+                              po);
+    break;
+  case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
+    if (po->verbose)
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Publishing at %llu/%llu bytes\n",
+                  (unsigned long long) info->value.publish.completed,
+                  (unsigned long long) info->value.publish.size);
+    break;
+  case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
+    break;
+  case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
+    if (po->verbose)
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Download at %llu/%llu bytes\n",
+                  (unsigned long long) info->value.download.completed,
+                  (unsigned long long) info->value.download.size);
+    break;
+  default:
+    break;
+  }
   return NULL;
 }
 
 
   return NULL;
 }
 
 
-
-struct StartContext
+/**
+ * Generate test data for publishing test.
+ *
+ * @param cls pointer to uint32_t with publishing seed
+ * @param offset offset to generate data for
+ * @param max maximum number of bytes to generate
+ * @param buf where to write generated data
+ * @param emsg where to store error message (unused)
+ * @return number of bytes written to buf
+ */
+static size_t
+file_generator (void *cls,
+               uint64_t offset,
+               size_t max,
+               void *buf,
+               char **emsg)
 {
 {
-  struct GNUNET_SCHEDULER_Handle *sched;
-  struct GNUNET_TIME_Relative timeout;
-  unsigned int total;
-  unsigned int have;
-  struct GNUNET_FS_TestDaemon **daemons;
-  GNUNET_SCHEDULER_Task cont;
-  void *cont_cls;
-  struct GNUNET_TESTING_PeerGroup *group;
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
-};
+  uint32_t *publish_seed = cls;
+  uint64_t pos;
+  uint8_t *cbuf = buf;
+  int mod;
+
+  if (emsg != NULL)
+    *emsg = NULL;
+  if (buf == NULL)
+    return 0;
+  for (pos = 0; pos < 8; pos++)
+    cbuf[pos] = (uint8_t) (offset >> pos * 8);
+  for (pos = 8; pos < max; pos++)
+  {
+    mod = (255 - (offset / 1024 / 32));
+    if (mod == 0)
+      mod = 1;
+    cbuf[pos] = (uint8_t) ((offset * (*publish_seed)) % mod);
+  }
+  return max;
+}
 
 
 
 
-static void 
-notify_running (void *cls,
-               const struct GNUNET_PeerIdentity *id,
-               const struct GNUNET_CONFIGURATION_Handle *cfg,
-               struct GNUNET_TESTING_Daemon *d,
-               const char *emsg)
+/**
+ * Connect adapter for publishing operation.
+ *
+ * @param cls the 'struct TestPublishOperation'
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+publish_connect_adapter (void *cls,
+                        const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-  struct StartContext *sctx = cls;
-  unsigned int i;
+  struct TestPublishOperation *po = cls;
 
 
-  if (emsg != NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to start daemon: %s\n"),
-                 emsg);
-      return;
-    }
-  GNUNET_assert (sctx->have < sctx->total);
-  sctx->daemons[sctx->have]->cfg = GNUNET_CONFIGURATION_dup (cfg);
-  sctx->daemons[sctx->have]->group = sctx->group;
-  sctx->daemons[sctx->have]->daemon = d;
-  sctx->daemons[sctx->have]->id = *id;
-  sctx->have++;
-  if (sctx->have == sctx->total)
-    {
-      GNUNET_SCHEDULER_add_continuation (sctx->sched,
-                                        sctx->cont,
-                                        sctx->cont_cls,
-                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
-      GNUNET_CONFIGURATION_destroy (sctx->cfg);
-      GNUNET_SCHEDULER_cancel (sctx->sched,
-                              sctx->timeout_task);
-      for (i=0;i<sctx->total;i++)
-       sctx->daemons[i]->fs = GNUNET_FS_start (sctx->sched,
-                                               sctx->daemons[i]->cfg,
-                                               "<tester>",
-                                               &progress_cb,
-                                               sctx->daemons[i],
-                                               GNUNET_FS_FLAGS_NONE,
-                                               GNUNET_FS_OPTIONS_END);
-      GNUNET_free (sctx);
-    }
+  return GNUNET_FS_start (cfg,
+                         "fs-test-publish",
+                         &publish_progress_cb, po,
+                         GNUNET_FS_FLAGS_NONE,
+                         GNUNET_FS_OPTIONS_END);
 }
 
 
 }
 
 
+/**
+ * Adapter function called to destroy connection to file-sharing service.
+ *
+ * @param cls the 'struct GNUNET_FS_Handle'
+ * @param op_result unused (different for publish/download!)
+ */
 static void
 static void
-start_timeout (void *cls,
-              const struct GNUNET_SCHEDULER_TaskContext *tc)
+fs_disconnect_adapter (void *cls,
+                      void *op_result)
 {
 {
-  struct StartContext *sctx = cls;
-  unsigned int i;
+  struct GNUNET_FS_Handle *fs = op_result;
 
 
-  GNUNET_TESTING_daemons_stop (sctx->group);
-  for (i=0;i<sctx->total;i++)
-    {
-      if (i < sctx->have)
-       GNUNET_CONFIGURATION_destroy (sctx->daemons[i]->cfg);
-      GNUNET_free (sctx->daemons[i]);
-    }
-  GNUNET_CONFIGURATION_destroy (sctx->cfg);
-  GNUNET_SCHEDULER_add_continuation (sctx->sched,
-                                    sctx->cont,
-                                    sctx->cont_cls,
-                                    GNUNET_SCHEDULER_REASON_TIMEOUT);
-  GNUNET_free (sctx);
+  GNUNET_FS_stop (fs);
 }
 
 
 /**
 }
 
 
 /**
- * Start daemons for testing.
+ * Callback to be called when testbed has connected to the fs service
  *
  *
- * @param sched scheduler to use
- * @param timeout if this operation cannot be completed within the
- *                given period, call the continuation with an error code
- * @param total number of daemons to start
- * @param daemons array of 'total' entries to be initialized
- *                (array must already be allocated, will be filled)
- * @param cont function to call when done
- * @param cont_cls closure for cont
+ * @param cls the 'struct TestPublishOperation'
+ * @param op the operation that has been finished
+ * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error)
+ * @param emsg error message in case the operation has failed; will be NULL if
+ *          operation has executed successfully.
  */
  */
-void
-GNUNET_FS_TEST_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
-                             struct GNUNET_TIME_Relative timeout,
-                             unsigned int total,
-                             struct GNUNET_FS_TestDaemon **daemons,
-                             GNUNET_SCHEDULER_Task cont,
-                             void *cont_cls)
+static void
+publish_fs_connect_complete_cb (void *cls,
+                               struct GNUNET_TESTBED_Operation *op,
+                               void *ca_result,
+                               const char *emsg)
 {
 {
-  struct StartContext *sctx;
-  unsigned int i;
-
-  GNUNET_assert (total > 0);
-  sctx = GNUNET_malloc (sizeof (struct StartContext));
-  sctx->sched = sched;
-  sctx->daemons = daemons;
-  sctx->total = total;
-  sctx->cont = cont;
-  sctx->cont_cls = cont_cls;
-  sctx->cfg = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_load (sctx->cfg,
-                                "fs_test_lib_data.conf"))
+  struct TestPublishOperation *po = cls;
+  struct GNUNET_FS_FileInformation *fi;
+  struct GNUNET_DISK_FileHandle *fh;
+  char *em;
+  uint64_t off;
+  char buf[DBLOCK_SIZE];
+  size_t bsize;
+  struct GNUNET_FS_BlockOptions bo;
+
+  if (NULL == ca_result)
     {
     {
-      GNUNET_break (0);
-      GNUNET_CONFIGURATION_destroy (sctx->cfg);
-      GNUNET_free (sctx);
-      GNUNET_SCHEDULER_add_continuation (sched,
-                                        cont,
-                                        cont_cls,
-                                        GNUNET_SCHEDULER_REASON_TIMEOUT);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to connect to FS for publishing: %s\n", emsg);
+      po->publish_cont (po->publish_cont_cls,
+                       NULL, NULL);
+      GNUNET_TESTBED_operation_done (po->fs_op);
+      GNUNET_free (po);
       return;
     }
       return;
     }
-  for (i=0;i<total;i++)
-    daemons[i] = GNUNET_malloc (sizeof (struct GNUNET_FS_TestDaemon));
-  sctx->group = GNUNET_TESTING_daemons_start (sched,
-                                             sctx->cfg,
-                                             total,
-                                             &notify_running,
-                                             sctx,
-                                             NULL, NULL,
-                                             NULL);
-  sctx->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                    timeout,
-                                                    &start_timeout,
-                                                    sctx);
-}
-
-
-struct ConnectContext
-{
-  struct GNUNET_SCHEDULER_Handle *sched;
-  GNUNET_SCHEDULER_Task cont;
-  void *cont_cls;
-};
-
-
-static void
-notify_connection (void *cls,
-                  const struct GNUNET_PeerIdentity *first,
-                  const struct GNUNET_PeerIdentity *second,
-                  const struct GNUNET_CONFIGURATION_Handle *first_cfg,
-                  const struct GNUNET_CONFIGURATION_Handle *second_cfg,
-                  struct GNUNET_TESTING_Daemon *first_daemon,
-                  struct GNUNET_TESTING_Daemon *second_daemon,
-                  const char *emsg)
-{
-  struct ConnectContext *cc = cls;
-  
-  if (emsg != NULL)
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-               _("Failed to connect peers: %s\n"),
-               emsg);
-  GNUNET_SCHEDULER_add_continuation (cc->sched,
-                                    cc->cont,
-                                    cc->cont_cls,
-                                    (emsg != NULL) 
-                                    ? GNUNET_SCHEDULER_REASON_TIMEOUT 
-                                    : GNUNET_SCHEDULER_REASON_PREREQ_DONE);
-  GNUNET_free (cc);
+  po->fs = ca_result;
+
+  bo.expiration_time = GNUNET_TIME_relative_to_absolute (CONTENT_LIFETIME);
+  bo.anonymity_level = po->anonymity;
+  bo.content_priority = 42;
+  bo.replication_level = 1;
+  if (GNUNET_YES == po->do_index)
+  {
+    po->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index");
+    GNUNET_assert (po->publish_tmp_file != NULL);
+    fh = GNUNET_DISK_file_open (po->publish_tmp_file,
+                                GNUNET_DISK_OPEN_WRITE |
+                                GNUNET_DISK_OPEN_CREATE,
+                                GNUNET_DISK_PERM_USER_READ |
+                                GNUNET_DISK_PERM_USER_WRITE);
+    GNUNET_assert (NULL != fh);
+    off = 0;
+    while (off < po->size)
+    {
+      bsize = GNUNET_MIN (sizeof (buf), po->size - off);
+      emsg = NULL;
+      GNUNET_assert (bsize == file_generator (&po->publish_seed, off, bsize, buf, &em));
+      GNUNET_assert (em == NULL);
+      GNUNET_assert (bsize == GNUNET_DISK_file_write (fh, buf, bsize));
+      off += bsize;
+    }
+    GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
+    fi = GNUNET_FS_file_information_create_from_file (po->fs, po,
+                                                      po->publish_tmp_file,
+                                                      NULL, NULL, po->do_index,
+                                                      &bo);
+    GNUNET_assert (NULL != fi);
+  }
+  else
+  {
+    fi = GNUNET_FS_file_information_create_from_reader (po->fs, po,
+                                                        po->size,
+                                                       &file_generator, &po->publish_seed,
+                                                       NULL, NULL,
+                                                        po->do_index, &bo);
+    GNUNET_assert (NULL != fi);
+  }
+  po->publish_context =
+    GNUNET_FS_publish_start (po->fs, fi, NULL, NULL, NULL,
+                            GNUNET_FS_PUBLISH_OPTION_NONE);
 }
 
 
 /**
 }
 
 
 /**
- * Connect two daemons for testing.
+ * Publish a file at the given peer.
  *
  *
- * @param sched scheduler to use
- * @param daemon1 first daemon to connect
- * @param daemon2 second first daemon to connect
+ * @param peer where to publish
  * @param timeout if this operation cannot be completed within the
  *                given period, call the continuation with an error code
  * @param timeout if this operation cannot be completed within the
  *                given period, call the continuation with an error code
+ * @param anonymity option for publication
+ * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
+ *                GNUNET_SYSERR for simulation
+ * @param size size of the file to publish
+ * @param seed seed to use for file generation
+ * @param verbose how verbose to be in reporting
  * @param cont function to call when done
  * @param cont_cls closure for cont
  */
 void
  * @param cont function to call when done
  * @param cont_cls closure for cont
  */
 void
-GNUNET_FS_TEST_daemons_connect (struct GNUNET_SCHEDULER_Handle *sched,
-                               struct GNUNET_FS_TestDaemon *daemon1,
-                               struct GNUNET_FS_TestDaemon *daemon2,
-                               struct GNUNET_TIME_Relative timeout,
-                               GNUNET_SCHEDULER_Task cont,
-                               void *cont_cls)
+GNUNET_FS_TEST_publish (struct GNUNET_TESTBED_Peer *peer,
+                        struct GNUNET_TIME_Relative timeout, uint32_t anonymity,
+                        int do_index, uint64_t size, uint32_t seed,
+                        unsigned int verbose,
+                        GNUNET_FS_TEST_UriContinuation cont, void *cont_cls)
 {
 {
-  struct ConnectContext *ncc;
-
-  ncc = GNUNET_malloc (sizeof (struct ConnectContext));
-  ncc->sched = sched;
-  ncc->cont = cont;
-  ncc->cont_cls = cont_cls;
-  GNUNET_TESTING_daemons_connect (daemon1->daemon,
-                                 daemon2->daemon,
-                                 timeout,
-                                 &notify_connection,
-                                 ncc);
+  struct TestPublishOperation *po;
+
+  po = GNUNET_new (struct TestPublishOperation);
+  po->publish_cont = cont;
+  po->publish_cont_cls = cont_cls;
+  po->publish_seed = seed;
+  po->anonymity = anonymity;
+  po->size = size;
+  po->verbose = verbose;
+  po->do_index = do_index;
+  po->fs_op = GNUNET_TESTBED_service_connect (po,
+                                             peer,
+                                             "fs",
+                                             &publish_fs_connect_complete_cb,
+                                             po,
+                                             &publish_connect_adapter,
+                                             &fs_disconnect_adapter,
+                                             po);
+  po->publish_timeout_task =
+      GNUNET_SCHEDULER_add_delayed (timeout, &publish_timeout, po);
 }
 
 
 }
 
 
+/* ************************** download ************************ */
+
+
 /**
 /**
- * Stop daemons used for testing.
+ * Task scheduled to run when download operation times out.
  *
  *
- * @param sched scheduler to use
- * @param total number of daemons to stop
- * @param daemons array with the daemons (values will be clobbered)
+ * @param cls the download operation context
  */
  */
-void
-GNUNET_FS_TEST_daemons_stop (struct GNUNET_SCHEDULER_Handle *sched,
-                            unsigned int total,
-                            struct GNUNET_FS_TestDaemon **daemons)
+static void
+download_timeout (void *cls)
 {
 {
-  unsigned int i;
-
-  GNUNET_assert (total > 0);
-  GNUNET_TESTING_daemons_stop (daemons[0]->group);
-  for (i=0;i<total;i++)
-    {
-      GNUNET_FS_stop (daemons[i]->fs);
-      GNUNET_CONFIGURATION_destroy (daemons[i]->cfg);
-      GNUNET_free (daemons[i]);
-      daemons[i] = NULL;
-    }  
+  struct TestDownloadOperation *dop = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Timeout while trying to download file\n");
+  dop->download_timeout_task = NULL;
+  GNUNET_FS_download_stop (dop->download_context,
+                           GNUNET_YES);
+  GNUNET_SCHEDULER_add_now (dop->download_cont,
+                            dop->download_cont_cls);
+  GNUNET_TESTBED_operation_done (dop->fs_op);
+  GNUNET_FS_uri_destroy (dop->uri);
+  GNUNET_free (dop);
 }
 
 
 }
 
 
+/**
+ * Task scheduled to report on the completion of our download operation.
+ *
+ * @param cls the download operation context
+ */
 static void
 static void
-publish_timeout (void *cls,
-                const struct GNUNET_SCHEDULER_TaskContext *tc)
+report_success (void *cls)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
-  GNUNET_FS_TEST_UriContinuation cont;
-  
-  cont = daemon->publish_cont;
-  daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  daemon->publish_cont = NULL;
-  GNUNET_FS_publish_stop (daemon->publish_context);
-  daemon->publish_context = NULL;
-  cont (daemon->publish_cont_cls,
-       NULL);
+  struct TestDownloadOperation *dop = cls;
+
+  GNUNET_FS_download_stop (dop->download_context,
+                           GNUNET_YES);
+  GNUNET_SCHEDULER_add_now (dop->download_cont,
+                            dop->download_cont_cls);
+  GNUNET_TESTBED_operation_done (dop->fs_op);
+  GNUNET_FS_uri_destroy (dop->uri);
+  GNUNET_free (dop);
 }
 
 
 }
 
 
-static size_t
-file_generator (void *cls, 
-               uint64_t offset,
-               size_t max, 
-               void *buf,
-               char **emsg)
+/**
+ * Progress callback for file-sharing events while downloading.
+ *
+ * @param cls the download operation context
+ * @param info information about the event
+ */
+static void *
+download_progress_cb (void *cls,
+                      const struct GNUNET_FS_ProgressInfo *info)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
-  uint64_t pos;
-  uint8_t *cbuf = buf;
+  struct TestDownloadOperation *dop = cls;
 
 
-  for (pos=0;pos<max;pos++)
-    cbuf[pos] = (uint8_t) ((offset * daemon->publish_seed) % (255 - (offset / 1024 / 32)));  
-  return max;
+  switch (info->status)
+  {
+  case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
+    if (dop->verbose)
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Download at %llu/%llu bytes\n",
+                  (unsigned long long) info->value.download.completed,
+                  (unsigned long long) info->value.download.size);
+    break;
+  case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
+    GNUNET_SCHEDULER_cancel (dop->download_timeout_task);
+    dop->download_timeout_task = NULL;
+    GNUNET_SCHEDULER_add_now (&report_success, dop);
+    break;
+  case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
+  case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
+    break;
+    /* FIXME: monitor data correctness during download progress */
+    /* FIXME: do performance reports given sufficient verbosity */
+    /* FIXME: advance timeout task to "immediate" on error */
+  default:
+    break;
+  }
+  return NULL;
 }
 
 
 }
 
 
-
 /**
 /**
- * Publish a file at the given daemon.
+ * Connect adapter for download operation.
  *
  *
- * @param sched scheduler to use
- * @param daemon where to publish
- * @param timeout if this operation cannot be completed within the
- *                given period, call the continuation with an error code
- * @param anonymity option for publication
- * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
- *                GNUNET_SYSERR for simulation
- * @param size size of the file to publish
- * @param seed seed to use for file generation
- * @param verbose how verbose to be in reporting
- * @param cont function to call when done
- * @param cont_cls closure for cont
+ * @param cls the 'struct TestDownloadOperation'
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
  */
  */
-void
-GNUNET_FS_TEST_publish (struct GNUNET_SCHEDULER_Handle *sched,
-                       struct GNUNET_FS_TestDaemon *daemon,
-                       struct GNUNET_TIME_Relative timeout,
-                       uint32_t anonymity,
-                       int do_index,
-                       uint64_t size,
-                       uint32_t seed,
-                       unsigned int verbose,
-                       GNUNET_FS_TEST_UriContinuation cont,
-                       void *cont_cls)
+static void *
+download_connect_adapter (void *cls,
+                        const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-  GNUNET_assert (daemon->publish_cont == NULL);
-  struct GNUNET_FS_FileInformation *fi;
+  struct TestPublishOperation *po = cls;
 
 
-  daemon->publish_cont = cont;
-  daemon->publish_cont_cls = cont_cls;
-  daemon->publish_seed = seed;
-  daemon->verbose = verbose;
-  daemon->publish_sched = sched;
-  fi = GNUNET_FS_file_information_create_from_reader (daemon,
-                                                     size,
-                                                     &file_generator,
-                                                     daemon,
-                                                     NULL,
-                                                     NULL,
-                                                     do_index,
-                                                     anonymity,
-                                                     42 /* priority */,
-                                                     GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS));
-  daemon->publish_context = GNUNET_FS_publish_start (daemon->fs,
-                                                    fi,
-                                                    NULL, NULL, NULL,
-                                                    GNUNET_FS_PUBLISH_OPTION_NONE);
-  daemon->publish_timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                              timeout,
-                                                              &publish_timeout,
-                                                              daemon);
+  return GNUNET_FS_start (cfg,
+                         "fs-test-download",
+                         &download_progress_cb, po,
+                         GNUNET_FS_FLAGS_NONE,
+                         GNUNET_FS_OPTIONS_END);
 }
 
 
 }
 
 
+/**
+ * Callback to be called when testbed has connected to the fs service
+ *
+ * @param cls the 'struct TestPublishOperation'
+ * @param op the operation that has been finished
+ * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error)
+ * @param emsg error message in case the operation has failed; will be NULL if
+ *          operation has executed successfully.
+ */
 static void
 static void
-download_timeout (void *cls,
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+download_fs_connect_complete_cb (void *cls,
+                                struct GNUNET_TESTBED_Operation *op,
+                                void *ca_result,
+                                const char *emsg)
 {
 {
-  struct GNUNET_FS_TestDaemon *daemon = cls;
-
-  daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES);
-  daemon->download_context = NULL;
-  GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
-                                    daemon->download_cont,
-                                    daemon->download_cont_cls,
-                                    GNUNET_SCHEDULER_REASON_TIMEOUT);
-  daemon->download_cont = NULL;
-  daemon->download_sched = NULL;
+  struct TestDownloadOperation *dop = cls;
+
+  dop->fs = ca_result;
+  GNUNET_assert (NULL != dop->fs);
+  dop->download_context =
+    GNUNET_FS_download_start (dop->fs, dop->uri, NULL, NULL, NULL, 0, dop->size,
+                             dop->anonymity, GNUNET_FS_DOWNLOAD_OPTION_NONE,
+                             NULL, NULL);
 }
 
 
 /**
  * Perform test download.
  *
 }
 
 
 /**
  * Perform test download.
  *
- * @param sched scheduler to use
- * @param daemon which peer to download from
+ * @param peer which peer to download from
  * @param timeout if this operation cannot be completed within the
  *                given period, call the continuation with an error code
  * @param anonymity option for download
  * @param timeout if this operation cannot be completed within the
  *                given period, call the continuation with an error code
  * @param anonymity option for download
@@ -579,39 +619,34 @@ download_timeout (void *cls,
  * @param cont_cls closure for cont
  */
 void
  * @param cont_cls closure for cont
  */
 void
-GNUNET_FS_TEST_download (struct GNUNET_SCHEDULER_Handle *sched,
-                        struct GNUNET_FS_TestDaemon *daemon,
-                        struct GNUNET_TIME_Relative timeout,
-                        uint32_t anonymity,
-                        uint32_t seed,
-                        const struct GNUNET_FS_Uri *uri,
-                        unsigned int verbose,
-                        GNUNET_SCHEDULER_Task cont,
-                        void *cont_cls)
+GNUNET_FS_TEST_download (struct GNUNET_TESTBED_Peer *peer,
+                         struct GNUNET_TIME_Relative timeout,
+                         uint32_t anonymity, uint32_t seed,
+                         const struct GNUNET_FS_Uri *uri, unsigned int verbose,
+                         GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
 {
 {
-  uint64_t size;
-  GNUNET_assert (daemon->download_cont == NULL);
-  size = GNUNET_FS_uri_chk_get_file_size (uri);
-  daemon->verbose = verbose;
-  daemon->download_sched = sched;
-  daemon->download_cont = cont;
-  daemon->download_cont_cls = cont_cls;
-  daemon->download_seed = seed;  
-  daemon->download_context = GNUNET_FS_download_start (daemon->fs,
-                                                      uri,
-                                                      NULL,
-                                                      NULL,
-                                                      0,
-                                                      size,
-                                                      anonymity,
-                                                      GNUNET_FS_DOWNLOAD_OPTION_NONE,
-                                                      NULL,
-                                                      NULL);
-  daemon->download_timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                               timeout,
-                                                               &download_timeout,
-                                                               daemon);
+  struct TestDownloadOperation *dop;
+
+  dop = GNUNET_new (struct TestDownloadOperation);
+  dop->uri = GNUNET_FS_uri_dup (uri);
+  dop->size = GNUNET_FS_uri_chk_get_file_size (uri);
+  dop->verbose = verbose;
+  dop->anonymity = anonymity;
+  dop->download_cont = cont;
+  dop->download_cont_cls = cont_cls;
+  dop->download_seed = seed;
+
+  dop->fs_op = GNUNET_TESTBED_service_connect (dop,
+                                              peer,
+                                              "fs",
+                                              &download_fs_connect_complete_cb,
+                                              dop,
+                                              &download_connect_adapter,
+                                              &fs_disconnect_adapter,
+                                              dop);
+  dop->download_timeout_task =
+      GNUNET_SCHEDULER_add_delayed (timeout, &download_timeout, dop);
 }
 
 }
 
-/* end of test_fs_lib.c */
+
+/* end of fs_test_lib.c */