source: trunk/libtransmission/libtransmission-test.c @ 14289

Last change on this file since 14289 was 14289, checked in by jordan, 8 years ago

add tr_makeMetaInfo() unit test for creating a single-file torrent

  • Property svn:keywords set to Date Rev Author Id
File size: 11.4 KB
Line 
1/*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: libtransmission-test.c 14289 2014-06-08 20:01:10Z jordan $
8 */
9
10#include <assert.h>
11#include <stdio.h>
12#include <stdlib.h> /* mkstemp() */
13
14#include <unistd.h>
15
16#include "transmission.h"
17#include "platform.h" /* TR_PATH_DELIMETER */
18#include "torrent.h"
19#include "trevent.h"
20#include "libtransmission-test.h"
21
22bool verbose = false;
23
24int current_test = 0;
25
26bool
27should_print (bool pass)
28{
29  if (!pass)
30    return true;
31
32  if (verbose)
33    return true;
34
35  return false;
36#ifdef VERBOSE
37  return true;
38#else
39  return false;
40#endif
41}
42
43bool
44check_condition_impl (const char * file, int line, bool condition)
45{
46  const bool pass = condition;
47
48  if (should_print (pass))
49    fprintf (stderr, "%s %s:%d\n", pass?"PASS":"FAIL", file, line);
50
51  return pass;
52}
53
54bool
55check_streq_impl (const char * file, int line, const char * expected, const char * actual)
56{
57  const bool pass = !tr_strcmp0 (expected, actual);
58
59  if (should_print (pass)) {
60    if (pass)
61      fprintf (stderr, "PASS %s:%d\n", file, line);
62    else
63      fprintf (stderr, "FAIL %s:%d, expected \"%s\", got \"%s\"\n", file, line, expected?expected:" (null)", actual?actual:" (null)");
64  }
65
66  return pass;
67}
68
69bool
70check_int_eq_impl (const char * file, int line, int64_t expected, int64_t actual)
71{
72  const bool pass = expected == actual;
73
74  if (should_print (pass)) {
75    if (pass)
76      fprintf (stderr, "PASS %s:%d\n", file, line);
77    else
78      fprintf (stderr, "FAIL %s:%d, expected \"%"PRId64"\", got \"%"PRId64"\"\n", file, line, expected, actual);
79  }
80
81  return pass;
82}
83
84bool
85check_ptr_eq_impl (const char * file, int line, const void * expected, const void * actual)
86{
87  const bool pass = expected == actual;
88
89  if (should_print (pass)) {
90    if (pass)
91      fprintf (stderr, "PASS %s:%d\n", file, line);
92    else
93      fprintf (stderr, "FAIL %s:%d, expected \"%p\", got \"%p\"\n", file, line, expected, actual);
94  }
95
96  return pass;
97}
98
99int
100runTests (const testFunc * const tests, int numTests)
101{
102  int i;
103  int ret;
104
105  (void) current_test; /* Use test even if we don't have any tests to run */
106
107  for (i=0; i<numTests; i++)
108    if ((ret = (*tests[i])()))
109      return ret;
110
111  return 0; /* All tests passed */
112}
113
114/***
115****
116***/
117
118#include <sys/types.h> /* stat(), opendir() */
119#include <sys/stat.h> /* stat() */
120#include <dirent.h> /* opendir() */
121#include <unistd.h> /* getcwd() */
122
123#include <errno.h>
124#include <string.h> /* strcmp() */
125
126#include "variant.h"
127
128/***
129****
130***/
131
132static char*
133tr_getcwd (void)
134{
135  char * result;
136  char buf[2048];
137
138#ifdef WIN32
139  result = _getcwd (buf, sizeof (buf));
140#else
141  result = getcwd (buf, sizeof (buf));
142#endif
143
144  if (result == NULL)
145    {
146      fprintf (stderr, "getcwd error: \"%s\"", tr_strerror (errno));
147      *buf = '\0';
148    }
149
150  return tr_strdup (buf);
151}
152
153char *
154libtest_sandbox_create (void)
155{
156  char * path = tr_getcwd ();
157  char * sandbox = tr_buildPath (path, "sandbox-XXXXXX", NULL);
158  tr_free (path);
159  tr_mkdtemp (sandbox);
160  return sandbox;
161}
162
163static void
164rm_rf (const char * killme)
165{
166  struct stat sb;
167
168  if (!stat (killme, &sb))
169    {
170      DIR * odir;
171
172      if (S_ISDIR (sb.st_mode) && ((odir = opendir (killme))))
173        {
174          struct dirent *d;
175          for (d = readdir(odir); d != NULL; d=readdir(odir))
176            {
177              if (d->d_name && strcmp(d->d_name,".") && strcmp(d->d_name,".."))
178                {
179                  char * tmp = tr_buildPath (killme, d->d_name, NULL);
180                  rm_rf (tmp);
181                  tr_free (tmp);
182                }
183            }
184          closedir (odir);
185        }
186
187      if (verbose)
188        fprintf (stderr, "cleanup: removing %s\n", killme);
189
190      tr_remove (killme);
191    }
192}
193
194void
195libtest_sandbox_destroy (const char * sandbox)
196{
197  rm_rf (sandbox);
198}
199
200/***
201****
202***/
203
204#define MEM_K 1024
205#define MEM_B_STR   "B"
206#define MEM_K_STR "KiB"
207#define MEM_M_STR "MiB"
208#define MEM_G_STR "GiB"
209#define MEM_T_STR "TiB"
210
211#define DISK_K 1000
212#define DISK_B_STR  "B"
213#define DISK_K_STR "kB"
214#define DISK_M_STR "MB"
215#define DISK_G_STR "GB"
216#define DISK_T_STR "TB"
217
218#define SPEED_K 1000
219#define SPEED_B_STR  "B/s"
220#define SPEED_K_STR "kB/s"
221#define SPEED_M_STR "MB/s"
222#define SPEED_G_STR "GB/s"
223#define SPEED_T_STR "TB/s"
224
225tr_session *
226libttest_session_init (tr_variant * settings)
227{
228  size_t len;
229  const char * str;
230  char * sandbox;
231  char * path;
232  tr_quark q;
233  static bool formatters_inited = false;
234  tr_session * session;
235  tr_variant local_settings;
236
237  tr_variantInitDict (&local_settings, 10);
238
239  if (settings == NULL)
240    settings = &local_settings;
241
242  sandbox = libtest_sandbox_create ();
243
244  if (!formatters_inited)
245    {
246      formatters_inited = true;
247      tr_formatter_mem_init (MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR);
248      tr_formatter_size_init (DISK_K,DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
249      tr_formatter_speed_init (SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
250    }
251
252  /* download dir */
253  q = TR_KEY_download_dir;
254  if (tr_variantDictFindStr (settings, q, &str, &len))
255    path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str);
256  else
257    path = tr_buildPath (sandbox, "Downloads", NULL);
258  tr_mkdirp (path, 0700);
259  tr_variantDictAddStr (settings, q, path);
260  tr_free (path);
261
262  /* incomplete dir */
263  q = TR_KEY_incomplete_dir;
264  if (tr_variantDictFindStr (settings, q, &str, &len))
265    path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str);
266  else
267    path = tr_buildPath (sandbox, "Incomplete", NULL);
268  tr_variantDictAddStr (settings, q, path);
269  tr_free (path);
270
271  path = tr_buildPath (sandbox, "blocklists", NULL);
272  tr_mkdirp (path, 0700);
273  tr_free (path);
274
275  q = TR_KEY_port_forwarding_enabled;
276  if (!tr_variantDictFind (settings, q))
277    tr_variantDictAddBool (settings, q, false);
278
279  q = TR_KEY_dht_enabled;
280  if (!tr_variantDictFind (settings, q))
281    tr_variantDictAddBool (settings, q, false);
282
283  q = TR_KEY_message_level;
284  if (!tr_variantDictFind (settings, q))
285    tr_variantDictAddInt (settings, q, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR);
286
287  session = tr_sessionInit ("libtransmission-test", sandbox, !verbose, settings);
288
289  tr_free (sandbox);
290  tr_variantFree (&local_settings);
291  return session;
292}
293
294void
295libttest_session_close (tr_session * session)
296{
297  char * sandbox;
298
299  sandbox = tr_strdup (tr_sessionGetConfigDir (session));
300  tr_sessionClose (session);
301  tr_logFreeQueue (tr_logGetQueue ());
302  session = NULL;
303
304  libtest_sandbox_destroy (sandbox);
305  tr_free (sandbox);
306}
307
308/***
309****
310***/
311
312tr_torrent *
313libttest_zero_torrent_init (tr_session * session)
314{
315  int err;
316  int metainfo_len;
317  char * metainfo;
318  const char * metainfo_base64;
319  tr_torrent * tor;
320  tr_ctor * ctor;
321
322  /*
323     1048576 files-filled-with-zeroes/1048576
324        4096 files-filled-with-zeroes/4096
325         512 files-filled-with-zeroes/512
326   */
327  metainfo_base64 =
328    "ZDg6YW5ub3VuY2UzMTpodHRwOi8vd3d3LmV4YW1wbGUuY29tL2Fubm91bmNlMTA6Y3JlYXRlZCBi"
329    "eTI1OlRyYW5zbWlzc2lvbi8yLjYxICgxMzQwNykxMzpjcmVhdGlvbiBkYXRlaTEzNTg3MDQwNzVl"
330    "ODplbmNvZGluZzU6VVRGLTg0OmluZm9kNTpmaWxlc2xkNjpsZW5ndGhpMTA0ODU3NmU0OnBhdGhs"
331    "NzoxMDQ4NTc2ZWVkNjpsZW5ndGhpNDA5NmU0OnBhdGhsNDo0MDk2ZWVkNjpsZW5ndGhpNTEyZTQ6"
332    "cGF0aGwzOjUxMmVlZTQ6bmFtZTI0OmZpbGVzLWZpbGxlZC13aXRoLXplcm9lczEyOnBpZWNlIGxl"
333    "bmd0aGkzMjc2OGU2OnBpZWNlczY2MDpRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj"
334    "/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv17"
335    "26aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGEx"
336    "Uv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJ"
337    "tGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GI"
338    "QxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZC"
339    "S1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8K"
340    "T9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9um"
341    "o/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9"
342    "e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRh"
343    "MVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMY"
344    "SbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLOlf5A+Tz30nMBVuNM2hpV3wg/103"
345    "OnByaXZhdGVpMGVlZQ==";
346
347  /* create the torrent ctor */
348  metainfo = tr_base64_decode (metainfo_base64, -1, &metainfo_len);
349  assert (metainfo != NULL);
350  assert (metainfo_len > 0);
351  assert (session != NULL);
352  ctor = tr_ctorNew (session);
353  tr_ctorSetMetainfo (ctor, (uint8_t*)metainfo, metainfo_len);
354  tr_ctorSetPaused (ctor, TR_FORCE, true);
355
356  /* create the torrent */
357  err = 0;
358  tor = tr_torrentNew (ctor, &err, NULL);
359  assert (!err);
360
361  /* cleanup */
362  tr_free (metainfo);
363  tr_ctorFree (ctor);
364  return tor;
365}
366
367void
368libttest_zero_torrent_populate (tr_torrent * tor, bool complete)
369{
370  tr_file_index_t i;
371
372  for (i=0; i<tor->info.fileCount; ++i)
373    {
374      int err;
375      uint64_t j;
376      FILE * fp;
377      char * path;
378      char * dirname;
379      const tr_file * file = &tor->info.files[i];
380      struct stat sb;
381
382      if (!complete && (i==0))
383        path = tr_strdup_printf ("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name);
384      else
385        path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name);
386      dirname = tr_dirname (path);
387      tr_mkdirp (dirname, 0700);
388      fp = fopen (path, "wb+");
389      for (j=0; j<file->length; ++j)
390        fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp);
391      fclose (fp);
392
393      tr_free (dirname);
394      tr_free (path);
395
396      path = tr_torrentFindFile (tor, i);
397      assert (path != NULL);
398      err = errno;
399      errno = 0;
400      stat (path, &sb);
401      assert (errno == 0);
402      errno = err; 
403      tr_free (path);
404    }
405
406  sync ();
407  libttest_blockingTorrentVerify (tor);
408
409  if (complete)
410    assert (tr_torrentStat(tor)->leftUntilDone == 0);
411  else
412    assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
413}
414
415/***
416****
417***/
418
419static void
420onVerifyDone (tr_torrent * tor UNUSED, bool aborted UNUSED, void * done)
421{
422  *(bool*)done = true;
423}
424
425void
426libttest_blockingTorrentVerify (tr_torrent * tor)
427{
428  bool done = false;
429
430  assert (tor->session != NULL);
431  assert (!tr_amInEventThread (tor->session));
432
433  tr_torrentVerify (tor, onVerifyDone, &done);
434  while (!done)
435    tr_wait_msec (10);
436}
437
438static void
439build_parent_dir (const char* path)
440{
441  char * dir;
442  const int tmperr = errno;
443
444  dir = tr_dirname (path);
445  errno = 0;
446  tr_mkdirp (dir, 0700);
447  assert (errno == 0);
448  tr_free (dir);
449
450  errno = tmperr;
451}
452
453void
454libtest_create_file_with_contents (const char* path, const void* payload, size_t n)
455{
456  FILE * fp;
457  const int tmperr = errno;
458
459  build_parent_dir (path);
460
461  tr_remove (path);
462  fp = fopen (path, "wb");
463  fwrite (payload, 1, n, fp);
464  fclose (fp);
465
466  sync ();
467
468  errno = tmperr;
469}
470
471void
472libtest_create_file_with_string_contents (const char * path, const char* str)
473{
474  libtest_create_file_with_contents (path, str, strlen(str));
475}
476
477void
478libtest_create_tmpfile_with_contents (char* tmpl, const void* payload, size_t n)
479{
480  int fd;
481  const int tmperr = errno;
482  size_t n_left = n;
483
484  build_parent_dir (tmpl);
485
486  fd = mkstemp (tmpl);
487  while (n_left > 0)
488    {
489      const ssize_t n = write (fd, payload, n_left);
490      if (n == -1)
491        {
492          fprintf (stderr, "Error writing '%s': %s", tmpl, tr_strerror(errno));
493          break;
494        }
495      n_left -= n;
496    }
497  close (fd);
498
499  sync ();
500
501  errno = tmperr;
502}
Note: See TracBrowser for help on using the repository browser.