g10: Add test for keydb as well as new testing infrastructure.
authorNeal H. Walfield <neal@g10code.com>
Wed, 2 Sep 2015 13:07:06 +0000 (15:07 +0200)
committerNeal H. Walfield <neal@g10code.com>
Wed, 2 Sep 2015 13:08:57 +0000 (15:08 +0200)
* g10/Makefile.am (EXTRA_DIST): Add test.c.
(AM_CPPFLAGS): Add -DSOURCE_DIR="\"$(srcdir)\"".
(module_tests): Add t-keydb.
(t_keydb_SOURCES): New variable.
(t_keydb_LDADD): Likewise.
* g10/t-keydb.c: New file.
* g10/t-keydb-keyring.kbx: New file.
* g10/test-stubs.c: New file.
* g10/test.c: New file.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
g10/Makefile.am
g10/t-keydb-keyring.kbx [new file with mode: 0644]
g10/t-keydb.c [new file with mode: 0644]
g10/test-stubs.c [new file with mode: 0644]
g10/test.c [new file with mode: 0644]

index 0c53eab..421870c 100644 (file)
@@ -19,9 +19,9 @@
 ## Process this file with automake to produce Makefile.in
 
 EXTRA_DIST = options.skel distsigkey.gpg ChangeLog-2011 gpg-w32info.rc \
-            gpg.w32-manifest.in
+            gpg.w32-manifest.in test.c
 
-AM_CPPFLAGS = -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/common -DSOURCE_DIR="\"$(srcdir)\""
 
 include $(top_srcdir)/am/cmacros.am
 
@@ -150,9 +150,12 @@ gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
 gpgv2_LDFLAGS = $(extra_bin_ldflags)
 
 t_common_ldadd =
-module_tests = t-rmd160
+module_tests = t-rmd160 t-keydb
 t_rmd160_SOURCES = t-rmd160.c rmd160.c
 t_rmd160_LDADD = $(t_common_ldadd)
+t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
+t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+             $(LIBICONV) $(t_common_ldadd)
 
 
 $(PROGRAMS): $(needed_libs) ../common/libgpgrl.a
diff --git a/g10/t-keydb-keyring.kbx b/g10/t-keydb-keyring.kbx
new file mode 100644 (file)
index 0000000..a1d3af0
Binary files /dev/null and b/g10/t-keydb-keyring.kbx differ
diff --git a/g10/t-keydb.c b/g10/t-keydb.c
new file mode 100644 (file)
index 0000000..0f17643
--- /dev/null
@@ -0,0 +1,87 @@
+/* t-keydb.c - Tests for keydb.c.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.c"
+
+#include "keydb.h"
+
+static void
+do_test (int argc, char *argv[])
+{
+  int rc;
+  KEYDB_HANDLE hd1, hd2;
+  KEYDB_SEARCH_DESC desc1, desc2;
+  KBNODE kb1, kb2;
+  char *uid1;
+  char *uid2;
+
+  (void) argc;
+  (void) argv;
+
+  rc = keydb_add_resource (SOURCE_DIR "/t-keydb-keyring.kbx", 0);
+  if (rc)
+    ABORT ("Failed to open keyring.");
+
+  hd1 = keydb_new ();
+  hd2 = keydb_new ();
+
+  rc = classify_user_id ("2689 5E25 E844 6D44 A26D  8FAF 2F79 98F3 DBFC 6AD9",
+                        &desc1, 0);
+  if (rc)
+    ABORT ("Failed to convert fingerprint for DBFC6AD9");
+
+  rc = keydb_search (hd1, &desc1, 1, NULL);
+  if (rc)
+    ABORT ("Failed to lookup key associated with DBFC6AD9");
+
+
+  classify_user_id ("8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367",
+                   &desc2, 0);
+  if (rc)
+    ABORT ("Failed to convert fingerprint for 1E42B367");
+
+  rc = keydb_search (hd2, &desc2, 1, NULL);
+  if (rc)
+    ABORT ("Failed to lookup key associated with 1E42B367");
+
+  rc = keydb_get_keyblock (hd2, &kb2);
+  if (rc)
+    ABORT ("Failed to get keyblock for 1E42B367");
+
+  rc = keydb_get_keyblock (hd1, &kb1);
+  if (rc)
+    ABORT ("Failed to get keyblock for DBFC6AD9");
+
+  while (kb1 && kb1->pkt->pkttype != PKT_USER_ID)
+    kb1 = kb1->next;
+  if (! kb1)
+    ABORT ("DBFC6AD9 has no user id packet");
+  uid1 = kb1->pkt->pkt.user_id->name;
+
+  while (kb2 && kb2->pkt->pkttype != PKT_USER_ID)
+    kb2 = kb2->next;
+  if (! kb2)
+    ABORT ("1E42B367 has no user id packet");
+  uid2 = kb2->pkt->pkt.user_id->name;
+
+  printf ("user id for DBFC6AD9: %s\n", uid1);
+  printf ("user id for 1E42B367: %s\n", uid2);
+
+  TEST_P ("cache consistency", strcmp (uid1, uid2) != 0);
+}
diff --git a/g10/test-stubs.c b/g10/test-stubs.c
new file mode 100644 (file)
index 0000000..c6f6d68
--- /dev/null
@@ -0,0 +1,413 @@
+/* test-stubs.c - The GnuPG signature verify utility
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006,
+ *               2008, 2009, 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#define INCLUDED_BY_MAIN_MODULE 1
+#include "gpg.h"
+#include "util.h"
+#include "packet.h"
+#include "iobuf.h"
+#include "main.h"
+#include "options.h"
+#include "keydb.h"
+#include "trustdb.h"
+#include "filter.h"
+#include "ttyio.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "status.h"
+#include "call-agent.h"
+
+int g10_errors_seen;
+
+
+void
+g10_exit( int rc )
+{
+  rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
+  exit(rc );
+}
+
+
+/* Stub:
+ * We have to override the trustcheck from pkclist.c becuase
+ * this utility assumes that all keys in the keyring are trustworthy
+ */
+int
+check_signatures_trust( PKT_signature *sig )
+{
+  (void)sig;
+  return 0;
+}
+
+void
+read_trust_options(byte *trust_model, ulong *created, ulong *nextcheck,
+                  byte *marginals, byte *completes, byte *cert_depth,
+                  byte *min_cert_level)
+{
+  (void)trust_model;
+  (void)created;
+  (void)nextcheck;
+  (void)marginals;
+  (void)completes;
+  (void)cert_depth;
+  (void)min_cert_level;
+}
+
+/* Stub:
+ * We don't have the trustdb , so we have to provide some stub functions
+ * instead
+ */
+
+int
+cache_disabled_value(PKT_public_key *pk)
+{
+  (void)pk;
+  return 0;
+}
+
+void
+check_trustdb_stale(void)
+{
+}
+
+int
+get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
+{
+  (void)pk;
+  (void)uid;
+  return '?';
+}
+
+unsigned int
+get_validity (PKT_public_key *pk, PKT_user_id *uid)
+{
+  (void)pk;
+  (void)uid;
+  return 0;
+}
+
+const char *
+trust_value_to_string (unsigned int value)
+{
+  (void)value;
+  return "err";
+}
+
+const char *
+uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
+{
+  (void)key;
+  (void)uid;
+  return "err";
+}
+
+int
+get_ownertrust_info (PKT_public_key *pk)
+{
+  (void)pk;
+  return '?';
+}
+
+unsigned int
+get_ownertrust (PKT_public_key *pk)
+{
+  (void)pk;
+  return TRUST_UNKNOWN;
+}
+
+
+/* Stubs:
+ * Because we only work with trusted keys, it does not make sense to
+ * get them from a keyserver
+ */
+
+struct keyserver_spec *
+keyserver_match (struct keyserver_spec *spec)
+{
+  (void)spec;
+  return NULL;
+}
+
+int
+keyserver_import_keyid (u32 *keyid, void *dummy)
+{
+  (void)keyid;
+  (void)dummy;
+  return -1;
+}
+
+int
+keyserver_import_cert (const char *name)
+{
+  (void)name;
+  return -1;
+}
+
+int
+keyserver_import_pka (const char *name,unsigned char *fpr)
+{
+  (void)name;
+  (void)fpr;
+  return -1;
+}
+
+int
+keyserver_import_name (const char *name,struct keyserver_spec *spec)
+{
+  (void)name;
+  (void)spec;
+  return -1;
+}
+
+int
+keyserver_import_ldap (const char *name)
+{
+  (void)name;
+  return -1;
+}
+
+/* Stub:
+ * No encryption here but mainproc links to these functions.
+ */
+gpg_error_t
+get_session_key (PKT_pubkey_enc *k, DEK *dek)
+{
+  (void)k;
+  (void)dek;
+  return GPG_ERR_GENERAL;
+}
+
+/* Stub: */
+gpg_error_t
+get_override_session_key (DEK *dek, const char *string)
+{
+  (void)dek;
+  (void)string;
+  return GPG_ERR_GENERAL;
+}
+
+/* Stub: */
+int
+decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
+{
+  (void)ctrl;
+  (void)procctx;
+  (void)ed;
+  (void)dek;
+  return GPG_ERR_GENERAL;
+}
+
+
+/* Stub:
+ * No interactive commands, so we don't need the helptexts
+ */
+void
+display_online_help (const char *keyword)
+{
+  (void)keyword;
+}
+
+/* Stub:
+ * We don't use secret keys, but getkey.c links to this
+ */
+int
+check_secret_key (PKT_public_key *pk, int n)
+{
+  (void)pk;
+  (void)n;
+  return GPG_ERR_GENERAL;
+}
+
+/* Stub:
+ * No secret key, so no passphrase needed
+ */
+DEK *
+passphrase_to_dek (u32 *keyid, int pubkey_algo,
+                   int cipher_algo, STRING2KEY *s2k, int mode,
+                   const char *tmp, int *canceled)
+{
+  (void)keyid;
+  (void)pubkey_algo;
+  (void)cipher_algo;
+  (void)s2k;
+  (void)mode;
+  (void)tmp;
+
+  if (canceled)
+    *canceled = 0;
+  return NULL;
+}
+
+void
+passphrase_clear_cache (u32 *keyid, const char *cacheid, int algo)
+{
+  (void)keyid;
+  (void)cacheid;
+  (void)algo;
+}
+
+struct keyserver_spec *
+parse_preferred_keyserver(PKT_signature *sig)
+{
+  (void)sig;
+  return NULL;
+}
+
+struct keyserver_spec *
+parse_keyserver_uri (const char *uri, int require_scheme,
+                     const char *configname, unsigned int configlineno)
+{
+  (void)uri;
+  (void)require_scheme;
+  (void)configname;
+  (void)configlineno;
+  return NULL;
+}
+
+void
+free_keyserver_spec (struct keyserver_spec *keyserver)
+{
+  (void)keyserver;
+}
+
+/* Stubs to avoid linking to photoid.c */
+void
+show_photos (const struct user_attribute *attrs, int count, PKT_public_key *pk)
+{
+  (void)attrs;
+  (void)count;
+  (void)pk;
+}
+
+int
+parse_image_header (const struct user_attribute *attr, byte *type, u32 *len)
+{
+  (void)attr;
+  (void)type;
+  (void)len;
+  return 0;
+}
+
+char *
+image_type_to_string (byte type, int string)
+{
+  (void)type;
+  (void)string;
+  return NULL;
+}
+
+#ifdef ENABLE_CARD_SUPPORT
+int
+agent_scd_getattr (const char *name, struct agent_card_info_s *info)
+{
+  (void)name;
+  (void)info;
+  return 0;
+}
+#endif /* ENABLE_CARD_SUPPORT */
+
+/* We do not do any locking, so use these stubs here */
+void
+dotlock_disable (void)
+{
+}
+
+dotlock_t
+dotlock_create (const char *file_to_lock, unsigned int flags)
+{
+  (void)file_to_lock;
+  (void)flags;
+  return NULL;
+}
+
+void
+dotlock_destroy (dotlock_t h)
+{
+  (void)h;
+}
+
+int
+dotlock_take (dotlock_t h, long timeout)
+{
+  (void)h;
+  (void)timeout;
+  return 0;
+}
+
+int
+dotlock_release (dotlock_t h)
+{
+  (void)h;
+  return 0;
+}
+
+void
+dotlock_remove_lockfiles (void)
+{
+}
+
+gpg_error_t
+agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
+{
+  (void)ctrl;
+  (void)pk;
+  return gpg_error (GPG_ERR_NO_SECKEY);
+}
+
+gpg_error_t
+agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
+{
+  (void)ctrl;
+  (void)keyblock;
+  return gpg_error (GPG_ERR_NO_SECKEY);
+}
+
+gpg_error_t
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+{
+  (void)ctrl;
+  (void)hexkeygrip;
+  *r_serialno = NULL;
+  return gpg_error (GPG_ERR_NO_SECKEY);
+}
+
+gpg_error_t
+gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
+                     unsigned char **r_fpr, size_t *r_fprlen,
+                     char **r_url)
+{
+  (void)ctrl;
+  (void)userid;
+  if (r_fpr)
+    *r_fpr = NULL;
+  if (r_fprlen)
+    *r_fprlen = 0;
+  if (r_url)
+    *r_url = NULL;
+  return gpg_error (GPG_ERR_NOT_FOUND);
+}
diff --git a/g10/test.c b/g10/test.c
new file mode 100644 (file)
index 0000000..6910f95
--- /dev/null
@@ -0,0 +1,141 @@
+/* test.c - Infrastructure for unit tests.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "gpg.h"
+
+/* A unit test consists of one or more tests.  Tests can be broken
+   into groups and each group can consist of one or more tests.  */
+
+/* The number of test groups.  */
+static int test_groups;
+/* The current test group.  */
+static char *test_group;
+
+/* Whether there was already a failure in the current test group.  */
+static int current_test_group_failed;
+/* The number of test groups with a failure.  */
+static int test_groups_failed;
+
+/* The total number of tests.  */
+static int tests;
+/* The total number of tests that failed.  */
+static int tests_failed;
+
+#define TEST_GROUP(description)             \
+  do {                              \
+    test_group = (description);             \
+    test_groups ++;                 \
+    current_test_group_failed = 0;   \
+  } while (0)
+
+#define STRINGIFY2(x) #x
+#define STRINGIFY(x) STRINGIFY2(x)
+
+/* Execute a test.  */
+#define TEST(description, test, expected)      \
+  do {                                         \
+    int test_result;                           \
+    int expected_result;                       \
+                                               \
+    tests ++;                                  \
+                                               \
+    printf ("%d. Checking %s...",              \
+           tests, (description) ?: "");        \
+    fflush (stdout);                           \
+                                               \
+    test_result = (test);                      \
+    expected_result = (expected);              \
+                                               \
+    if (test_result == expected_result)                \
+      {                                                \
+        printf (" ok.\n");                     \
+      }                                                \
+    else                                       \
+      {                                                \
+       printf (" failed.\n");                  \
+       printf ("  %s == %s failed.\n",         \
+               STRINGIFY(test),                \
+               STRINGIFY(expected));           \
+       tests_failed ++;                        \
+       if (! current_test_group_failed)        \
+         {                                     \
+           current_test_group_failed = 1;      \
+           test_groups_failed ++;              \
+         }                                     \
+      }                                                \
+  } while (0)
+
+/* Test that a condition evaluates to true.  */
+#define TEST_P(description, test)              \
+  TEST(description, !!(test), 1)
+
+/* Like CHECK, but if the test fails, abort the program.  */
+#define ASSERT(description, test, expected)            \
+  do {                                                 \
+    int tests_failed_pre = tests_failed;               \
+    CHECK(description, test, expected);                        \
+    if (tests_failed_pre != tests_failed)              \
+      exit (1);                                                \
+  } while (0)
+
+/* Call this if something went wrong.  */
+#define ABORT(message)                         \
+  do {                                         \
+    printf ("aborting...");                    \
+    if (message)                               \
+      printf (" %s\n", (message));             \
+                                               \
+    exit(1);                                   \
+  } while (0)
+
+/* You need to fill this function in.  */
+static void do_test (int argc, char *argv[]);
+
+static void
+print_results (void)
+{
+  if (tests_failed == 0)
+    {
+      printf ("All %d tests passed.\n", tests);
+      exit (0);
+    }
+  else
+    {
+      printf ("%d of %d tests failed",
+             tests_failed, tests);
+      if (test_groups > 1)
+       printf (" (%d of %d groups)",
+               test_groups_failed, test_groups);
+      printf ("\n");
+
+      exit (1);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  (void) test_group;
+
+  do_test (argc, argv);
+  atexit (print_results);
+
+  return tests_failed == 0;
+}