diff --git a/tests/json/Makefile.am b/tests/json/Makefile.am new file mode 100644 index 00000000..74c9c3e8 --- /dev/null +++ b/tests/json/Makefile.am @@ -0,0 +1,106 @@ +# Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik +# Software engineering by Intevation GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# GPGME 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 Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +## Process this file with automake to produce Makefile.in + +GPGME_JSON=$(abs_builddir)/../../src/gpgme-json +GPG = gpg + +GNUPGHOME=$(abs_builddir) +TESTS_ENVIRONMENT = GNUPGHOME=$(GNUPGHOME) LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) gpgme_json=$(GPGME_JSON) + +c_tests = t-json + +TESTS = initial.test $(c_tests) final.test + +CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ + gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \ + random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp \ + gpg-sample.stamp tofu.db *.conf.gpgconf.bak + +private_keys = \ + $(top_srcdir)/tests/gpg/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \ + $(top_srcdir)/tests/gpg/76F7E2B35832976B50A27A282D9B87E44577EB66 \ + $(top_srcdir)/tests/gpg/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \ + $(top_srcdir)/tests/gpg/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F \ + $(top_srcdir)/tests/gpg/7A030357C0F253A5BBCD282FFC4E521B37558F5C + + +EXTRA_DIST = t-chunking.in.json t-chunking.out.json \ + t-config.in.json t-config-opt.in.json \ + t-config-opt.out.json t-config.out.json \ + t-createkey.in.json t-createkey.out.json \ + t-decrypt.in.json t-decrypt.out.json \ + t-decrypt-verify.in.json t-decrypt-verify.out.json \ + t-delete.in.json t-delete.out.json \ + t-encrypt.in.json t-encrypt.out.json \ + t-encrypt-sign.in.json t-encrypt-sign.out.json \ + t-export.in.json t-export.out.json \ + t-export-secret-info.in.json t-export-secret-info.out.json \ + t-import.in.json t-import.out.json \ + t-keylist.in.json t-keylist.out.json \ + t-keylist-secret.in.json t-keylist-secret.out.json \ + t-sign.in.json t-sign.out.json \ + t-verify.in.json t-verify.out.json \ + t-version.in.json t-version.out.json + +BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \ + gpg-sample.stamp +t_json_SOURCES = t-json.c ../../src/cJSON.o +AM_LDFLAGS = -no-install +LDADD = ../../src/libgpgme.la +t_json_LDADD = ../../src/cJSON.o -lm ../../src/libgpgme.la @GPG_ERROR_LIBS@ + +AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ + +noinst_PROGRAMS = $(c_tests) + +clean-local: + -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop + -rm -fR private-keys-v1.d + +gpg-sample.stamp: $(private_keys) + -$(TESTS_ENVIRONMENT) gpgconf --kill all + $(MKDIR_P) ./private-keys-v1.d + for k in $(private_keys); do \ + cp $$k private-keys-v1.d/$$(basename $$k).key; \ + done + echo x > ./gpg-sample.stamp + +pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc gpg-sample.stamp + $(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \ + --import $(top_srcdir)/tests/gpg/pubdemo.asc + -$(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \ + --import $(top_srcdir)/tests/gpg/secdemo.asc + echo x > ./pubring-stamp + +gpg.conf: +# This is required for t-sig-notations. + echo no-force-v3-sigs > ./gpg.conf + +gpg-agent.conf: +# This is required for gpg2, which does not support command fd for the +# passphrase. disable-scdaemon is required so that we don't try using +# a key from a smartcard reader (error might be: Unusable secret key) + echo pinentry-program $(abs_srcdir)/../gpg/pinentry > ./gpg-agent.conf + echo disable-scdaemon >> ./gpg-agent.conf + + +# end-of-file diff --git a/tests/json/final.test b/tests/json/final.test new file mode 100755 index 00000000..5289396f --- /dev/null +++ b/tests/json/final.test @@ -0,0 +1,4 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --stop +exit 0 diff --git a/tests/json/initial.test b/tests/json/initial.test new file mode 100755 index 00000000..93c8621a --- /dev/null +++ b/tests/json/initial.test @@ -0,0 +1,4 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --start +exit 0 diff --git a/tests/json/t-chunking.in.json b/tests/json/t-chunking.in.json new file mode 100644 index 00000000..3ff655b5 --- /dev/null +++ b/tests/json/t-chunking.in.json @@ -0,0 +1,5 @@ +{ + "op": "keylist", + "keys": ["alpha@example.net", "bravo@example.net"], + "chunksize": 64 +} diff --git a/tests/json/t-chunking.out.json b/tests/json/t-chunking.out.json new file mode 100644 index 00000000..bdc2f0f2 --- /dev/null +++ b/tests/json/t-chunking.out.json @@ -0,0 +1,5 @@ +{ + "base64": true, + "more": true, + "response": "*" +} diff --git a/tests/json/t-json.c b/tests/json/t-json.c index 7a4d9065..98bd8622 100644 --- a/tests/json/t-json.c +++ b/tests/json/t-json.c @@ -1,393 +1,393 @@ /* t-json.c - Regression test. Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH This file is part of GPGME. GPGME is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. GPGME 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "../gpg/t-support.h" #include "../../src/cJSON.h" /* Register tests here */ static const char*tests[] = { "t-config", "t-version", "t-keylist", "t-keylist-secret", "t-decrypt", "t-config-opt", "t-encrypt", "t-encrypt-sign", "t-sign", "t-verify", "t-decrypt-verify", "t-export", "t-createkey", - "t-export-secret-info", + "t-export-secret-info", "t-chunking", /* For these two the order is important * as t-import imports the deleted key from t-delete */ "t-delete", "t-import", NULL }; static int verbose = 0; static char * get_file (const char *fname) { gpg_error_t err; gpgrt_stream_t fp; struct stat st; char *buf; size_t buflen; fp = gpgrt_fopen (fname, "r"); if (!fp) { err = gpg_error_from_syserror (); fprintf (stderr, "Error: can't open '%s': %s\n", fname, gpg_strerror (err)); return NULL; } if (fstat (gpgrt_fileno(fp), &st)) { err = gpg_error_from_syserror (); fprintf (stderr, "Error: can't stat '%s': %s\n", fname, gpg_strerror (err)); gpgrt_fclose (fp); return NULL; } buflen = st.st_size; buf = malloc (buflen+1); if (!buf) { fprintf (stderr, "Error: no mem\n"); gpgrt_fclose (fp); return NULL; } if (gpgrt_fread (buf, buflen, 1, fp) != 1) { err = gpg_error_from_syserror (); fprintf (stderr, "error reading '%s': %s\n", fname, gpg_strerror (err)); gpgrt_fclose (fp); free (buf); return NULL; } buf[buflen] = 0; gpgrt_fclose (fp); return buf; } /* Check that the element needle exists in hay. Returns 0 if the needle was found. */ int test_contains (cjson_t needle, cjson_t hay) { if (verbose == 2) fprintf (stderr, "%s: -------checking-------- " "\n%s\n -------against-------- \n%s\n", nonnull (needle->string), cJSON_Print (needle), cJSON_Print (hay)); /* Type check. This automatically checks bool vals and NULL */ if (needle->type != hay->type) { if (verbose) fprintf (stderr, "%s: type mismatch expected %i got %i\n", nonnull (needle->string), needle->type, hay->type); return 1; } /* First the simple types */ if (cjson_is_number (needle)) { if (needle->valueint != hay->valueint) { if (verbose) fprintf (stderr, "%s: value mismatch. Expected %i got %i\n", nonnull (needle->string), needle->valueint, hay->valueint); return 1; } } if (cjson_is_string (needle)) { if (strcmp (needle->valuestring, hay->valuestring) && /* Use * as a general don't care placeholder */ strcmp (needle->valuestring, "*")) { if (verbose) fprintf (stderr, "%s: string mismatch Expected '%s' got '%s'\n", needle->string, needle->valuestring, hay->valuestring); return 1; } } /* Now the complex types */ if (needle->child) { if (!hay->child) { fprintf (stderr, "Depth mismatch. Expected child for %s\n", nonnull (needle->string)); } if (test_contains (needle->child, hay->child)) { int found = 0; for (cjson_t hit = hay->child; hit; hit = hit->next) { found |= !test_contains (needle->child, hit); if (found) { break; } } if (!found) { return 1; } } } if (needle->prev) { return 0; } /* Walk elements of an array */ for (cjson_t it = needle->next; it; it = it->next) { int found = 0; if (!it->string && it->child) { /* Try out all other anonymous children on the same level */ cjson_t hit = hay; /* Return to the beginning */ while (hit->prev) { hit = hit->prev; } for (; hit && hit->child; hit = hit->next) { found |= !test_contains (it->child, hit->child); if (found) { break; } } if (!found) { return 1; } continue; } /* Try the children in the haystack */ for (cjson_t hit = hay; hit; hit = hit->next) { if (hit->string && it->string && !strcmp (hit->string, it->string)) { found = 1; if (test_contains (it, hit)) { return 1; } } } if (!found) { if (verbose) fprintf (stderr, "Failed to find '%s' in list\n", nonnull (it->string)); return 1; } } return 0; } int check_response (const char *response, const char *expected) { cjson_t hay; cjson_t needle; int rc; size_t erroff; hay = cJSON_Parse (response, &erroff); if (!hay) { fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff, response); return 1; } needle = cJSON_Parse (expected, &erroff); if (!needle) { fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff, expected); cJSON_Delete (hay); return 1; } rc = test_contains (needle, hay); cJSON_Delete (needle); cJSON_Delete (hay); return rc; } int run_test (const char *test, const char *gpgme_json) { gpgme_ctx_t ctx; gpgme_data_t json_stdin = NULL; gpgme_data_t json_stdout = NULL; gpgme_data_t json_stderr = NULL; char *test_in; char *test_out; const char *argv[3]; char *response; char *expected = NULL; size_t response_size; int rc = 0; const char *top_srcdir = getenv ("top_srcdir"); if (!top_srcdir) { fprintf (stderr, "Error top_srcdir environment variable not set\n"); exit(1); } gpgrt_asprintf (&test_in, "%s/tests/json/%s.in.json", top_srcdir, test); gpgrt_asprintf (&test_out, "%s/tests/json/%s.out.json", top_srcdir, test); printf ("Running %s...\n", test); fail_if_err (gpgme_new (&ctx)); gpgme_set_protocol (ctx, GPGME_PROTOCOL_SPAWN); fail_if_err (gpgme_data_new_from_file (&json_stdin, test_in, 1)); fail_if_err (gpgme_data_new (&json_stdout)); fail_if_err (gpgme_data_new (&json_stderr)); argv[0] = gpgme_json; argv[1] = "-s"; argv[2] = NULL; fail_if_err (gpgme_op_spawn (ctx, gpgme_json, argv, json_stdin, json_stdout, json_stderr, 0)); response = gpgme_data_release_and_get_mem (json_stdout, &response_size); if (response_size) { expected = get_file (test_out); test (expected); rc = check_response (response, expected); } else { rc = 1; } if (!rc) { printf (" success\n"); gpgme_data_release (json_stderr); } else { char *buf; size_t size; buf = gpgme_data_release_and_get_mem (json_stderr, &size); printf (" failed%s\n", response_size ? "" : ", no response from gpgme-json"); if (size) { printf ("gpgme-json stderr:\n%.*s\n", (int)size, buf); } free (buf); } free (test_out); free (test_in); free (response); free (expected); gpgme_data_release (json_stdin); gpgme_release (ctx); return rc; } int main (int argc, char *argv[]) { const char *gpgme_json = getenv ("gpgme_json"); int last_argc = -1; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } } if (!check_gpg_version ("2.2.0")) { /* Lets not break too much or have to test all combinations */ printf ("Testsuite skipped. Minimum GnuPG version (2.2.0) " "not found.\n"); exit(0); } init_gpgme (GPGME_PROTOCOL_SPAWN); for (const char **test = tests; *test; test++) { if (run_test (*test, gpgme_json)) { exit(1); } } return 0; }