From 68270f0f604eefdc89583950a7cfa02fe7a0cab5 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Julien Date: Thu, 17 Jul 2014 14:34:08 -0400 Subject: [PATCH] Mi test: Basic test structure Added two utils: an xml xpath extractor and xml xsd validator. Test for session command Signed-off-by: Jonathan Rajotte Julien --- configure.ac | 1 + tests/fast_regression | 1 + tests/regression/tools/Makefile.am | 2 +- tests/regression/tools/mi/Makefile.am | 27 +++ tests/regression/tools/mi/extract_xml.c | 227 ++++++++++++++++++++++ tests/regression/tools/mi/test_mi_version | 78 ++++++++ tests/regression/tools/mi/validate_xml.c | 201 +++++++++++++++++++ tests/regression/tools/mi/validate_xml.h | 0 tests/run.sh | 2 +- 9 files changed, 537 insertions(+), 2 deletions(-) create mode 100644 tests/regression/tools/mi/Makefile.am create mode 100644 tests/regression/tools/mi/extract_xml.c create mode 100755 tests/regression/tools/mi/test_mi_version create mode 100644 tests/regression/tools/mi/validate_xml.c create mode 100644 tests/regression/tools/mi/validate_xml.h diff --git a/configure.ac b/configure.ac index a6f5b0be9..7d8839543 100644 --- a/configure.ac +++ b/configure.ac @@ -420,6 +420,7 @@ AC_CONFIG_FILES([ tests/regression/tools/live/Makefile tests/regression/tools/exclusion/Makefile tests/regression/tools/save-load/Makefile + tests/regression/tools/mi/Makefile tests/regression/ust/Makefile tests/regression/ust/nprocesses/Makefile tests/regression/ust/high-throughput/Makefile diff --git a/tests/fast_regression b/tests/fast_regression index a3c2fe994..6fae89d03 100644 --- a/tests/fast_regression +++ b/tests/fast_regression @@ -13,6 +13,7 @@ regression/tools/snapshots/test_ust_fast regression/tools/snapshots/test_ust_streaming regression/tools/save-load/test_save regression/tools/save-load/test_load +regression/tools/mi/test_mi_version regression/ust/before-after/test_before_after regression/ust/buffers-pid/test_buffers_pid regression/ust/multi-session/test_multi_session diff --git a/tests/regression/tools/Makefile.am b/tests/regression/tools/Makefile.am index 84df80075..09f55b33a 100644 --- a/tests/regression/tools/Makefile.am +++ b/tests/regression/tools/Makefile.am @@ -1 +1 @@ -SUBDIRS = streaming filtering health tracefile-limits snapshots live exclusion save-load +SUBDIRS = streaming filtering health tracefile-limits snapshots live exclusion save-load mi diff --git a/tests/regression/tools/mi/Makefile.am b/tests/regression/tools/mi/Makefile.am new file mode 100644 index 000000000..7a54c3487 --- /dev/null +++ b/tests/regression/tools/mi/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = -I$(srcdir)/include + +noinst_PROGRAMS = validate_xml extract_xml +validate_xml_SOURCES = validate_xml.c +validate_xml_CPPFLAGS = $(XML_CPPFLAGS) $(AM_CPPFLAGS) +validate_xml_LDADD = $(XML_LIBS) + +extract_xml_SOURCES = extract_xml.c +extract_xml_CPPFLAGS = $(XML_CPPFLAGS) $(AM_CPPFLAGS) +extract_xml_LDADD = $(XML_LIBS) + +noinst_SCRIPTS = test_mi_version +EXTRA_DIST = + +all-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + cp -f $(srcdir)/$$script $(builddir); \ + done; \ + fi + +clean-local: + @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ + for script in $(EXTRA_DIST); do \ + rm -f $(builddir)/$$script; \ + done; \ + fi diff --git a/tests/regression/tools/mi/extract_xml.c b/tests/regression/tools/mi/extract_xml.c new file mode 100644 index 000000000..724e005f4 --- /dev/null +++ b/tests/regression/tools/mi/extract_xml.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2014 - Jonathan Rajotte + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program 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, write to the Free Software Foundation, Inc., 51 + */ + +/* + * Usage: extract_xml [-v] xml_path xpath_expression + * Evaluate XPath expression and prints result node set. + * args[1] path to the xml file + * args[2] xpath expression to extract + * If -v is set the name of the node will appear with his value delimited by + * a semicolon(;) + * Ex: + * Command:extract_xml ../file.xml /test/node/text() + * Output: + * a + * b + * c + * With -v + * node;a; + * node;b; + * node;c; + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(LIBXML_XPATH_ENABLED) + + +int opt_verbose; +/** + * print_xpath_nodes: + * nodes: the nodes set. + * output: the output file handle. + * + * Print the node content to the file + */ +static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output) +{ + int ret; + int size; + int i; + + xmlNodePtr cur; + xmlChar *node_child_value_string = NULL; + + assert(output); + size = (nodes) ? nodes->nodeNr : 0; + + for (i = 0; i < size; ++i) { + assert(nodes->nodeTab[i]); + + if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) { + fprintf(stderr, "ERR:%s\n", + "This executable does not support xml namespacing\n"); + ret = -1; + goto end; + } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { + cur = nodes->nodeTab[i]; + + if (xmlChildElementCount(cur) == 0) { + if (xmlNodeIsText(cur->children)) { + node_child_value_string = xmlNodeListGetString(doc, + cur->children, 1); + if (opt_verbose) { + fprintf(output, "%s;%s;\n", cur->name, + node_child_value_string); + } else { + fprintf(output, "%s\n", + node_child_value_string); + } + xmlFree(node_child_value_string); + } else { + /* We don't want to print non-final element */ + fprintf(stderr, "ERR:%s\n", + "Xpath expression return non-final xml element"); + ret = -1; + goto end; + } + } else { + /* We don't want to print non-final element */ + fprintf(stderr, "ERR:%s\n", + "Xpath expression return non-final xml element"); + ret = -1; + goto end; + } + + } else { + cur = nodes->nodeTab[i]; + if (opt_verbose) { + fprintf(output, "%s;%s;\n", cur->parent->name, cur->content); + } else { + fprintf(output, "%s\n", cur->content); + + } + } + } + /* Command Success */ + ret = 0; + +end: + return ret; +} + +/* + * Extract element corresponding to xpath + * xml_path The path to the xml file + * xpath: The xpath to evaluate. + * + * Evaluate an xpath expression onto an xml file. + * and print the result one by line. + * + * Returns 0 on success and a negative value otherwise. + */ +static int extract_xpath(const char *xml_path, const xmlChar *xpath) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr xpathCtx = NULL; + xmlXPathObjectPtr xpathObj = NULL; + + assert(xml_path); + assert(xpath); + + /* Parse the xml file */ + doc = xmlParseFile(xml_path); + if (!doc) { + fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path); + return -1; + } + + /* Initialize a xpath context */ + xpathCtx = xmlXPathNewContext(doc); + if (!xpathCtx) { + fprintf(stderr, "ERR: XPath context invalid\n"); + xmlFreeDoc(doc); + return -1; + } + + /* Evaluate xpath expression */ + xpathObj = xmlXPathEvalExpression(xpath, xpathCtx); + if (!xpathObj) { + fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + return -1; + } + + /* Print results */ + if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) { + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + return -1; + } + + /* Cleanup */ + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + + return 0; +} + +int main(int argc, char **argv) +{ + int opt; + + /* Parse command line and process file */ + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + opt_verbose = 1; + break; + default: + abort(); + } + } + + if (!(optind + 1 < argc)) { + fprintf(stderr, "ERR:%s\n", "Arguments missing"); + return -1; + } + + /* Init libxml */ + xmlInitParser(); + xmlKeepBlanksDefault(0); + if (access(argv[optind], F_OK)) { + fprintf(stderr, "ERR:%s\n", "Xml path not valid"); + return -1; + } + /* Do the main job */ + if (extract_xpath(argv[optind], (xmlChar *)argv[optind+1])) { + return -1; + } + + /* Shutdown libxml */ + xmlCleanupParser(); + + return 0; +} + +#else +int main(void) +{ + fprintf(stderr, "XPath support not compiled in\n"); + return -1; +} +#endif diff --git a/tests/regression/tools/mi/test_mi_version b/tests/regression/tools/mi/test_mi_version new file mode 100755 index 000000000..1d89453bb --- /dev/null +++ b/tests/regression/tools/mi/test_mi_version @@ -0,0 +1,78 @@ +#!/bin/bash +# +# Copyright (C) - 2014 Jonathan Rajotte +# +# This library 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; version 2.1 of the License. +# +# This library 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 library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +TEST_DESC="Mi test command version" + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/../../../ +XSD_PATH=$TESTDIR/../src/common/mi_lttng.xsd +SESSIOND_BIN="lttng-sessiond" +RELAYD_BIN="lttng-relayd" +LTTNG_BIN="lttng --mi xml" + +XML_VALIDATE="$CURDIR/validate_xml $XSD_PATH" + +LTTNG=$TESTDIR/../src/bin/lttng/$LTTNG_BIN + + +DIR=$(readlink -f $TESTDIR) + +NUM_TESTS=4 + +source $TESTDIR/utils/utils.sh + +# MUST set TESTDIR before calling those functions +plan_tests $NUM_TESTS + +print_test_banner "$TEST_DESC" + +function mi_print_version() +{ + local opt=$2 + local output_path=$1 + + $LTTNG version $opt > $output_path + ok $? "Machine Interface Lttng version" + +} + +function test_version_validation() +{ + mi_print_version version.xml + $XML_VALIDATE version.xml + ok $? "Machine Interface Version xsd validation" +} + +start_lttng_sessiond + +TESTS=( + test_version_validation +) + +for fct_test in ${TESTS[@]}; +do + TRACE_PATH=$(mktemp -d) + + ${fct_test} + if [ $? -ne 0 ]; then + break; + fi + # Only delete if successful + rm -rf $TRACE_PATH +done + +stop_lttng_sessiond diff --git a/tests/regression/tools/mi/validate_xml.c b/tests/regression/tools/mi/validate_xml.c new file mode 100644 index 000000000..e3c635090 --- /dev/null +++ b/tests/regression/tools/mi/validate_xml.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2014 Jonathan Rajotte + * + * This library 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; version 2.1 of + * the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + /* + * This script validate and xml from an xsd. + * argv[1] Path of the xsd + * argv[2] Path to the XML to be validated + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +struct validation_ctx { + xmlSchemaParserCtxtPtr parser_ctx; + xmlSchemaPtr schema; + xmlSchemaValidCtxtPtr schema_validation_ctx; +}; + +enum command_err_code { + CMD_SUCCESS = 0, + CMD_ERROR +}; + +static +void xml_error_handler(void *ctx, const char *format, ...) +{ + char *err_msg; + va_list args; + int ret; + + va_start(args, format); + ret = vasprintf(&err_msg, format, args); + va_end(args); + if (ret == -1) { + fprintf(stderr, "ERR: %s\n", + "String allocation failed in xml error handle"); + return; + } + + fprintf(stderr, "XML Error: %s\n", err_msg); + free(err_msg); +} + +static +void fini_validation_ctx( + struct validation_ctx *ctx) +{ + if (ctx->parser_ctx) { + xmlSchemaFreeParserCtxt(ctx->parser_ctx); + } + + if (ctx->schema) { + xmlSchemaFree(ctx->schema); + } + + if (ctx->schema_validation_ctx) { + xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx); + } + + memset(ctx, 0, sizeof(struct validation_ctx)); +} + +static +int init_validation_ctx( + struct validation_ctx *ctx, char *xsd_path) +{ + int ret; + + if (!xsd_path) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path); + if (!ctx->parser_ctx) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler, + xml_error_handler, NULL); + + ctx->schema = xmlSchemaParse(ctx->parser_ctx); + if (!ctx->schema) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema); + if (!ctx->schema_validation_ctx) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler, + xml_error_handler, NULL); + ret = 0; + +end: + if (ret) { + fini_validation_ctx(ctx); + } + return ret; +} + +static int validate_xml(const char *xml_file_path, struct validation_ctx *ctx) +{ + int ret; + xmlDocPtr doc = NULL; + + assert(xml_file_path); + assert(ctx); + + /* Open the document */ + doc = xmlParseFile(xml_file_path); + if (!doc) { + ret = LTTNG_ERR_MI_IO_FAIL; + goto end; + } + + /* Validate against the validation ctx (xsd) */ + ret = xmlSchemaValidateDoc(ctx->schema_validation_ctx, doc); + if (ret) { + fprintf(stderr, "ERR: %s\n", "XML is not valid againt provided XSD"); + ret = CMD_ERROR; + goto end; + } + + ret = CMD_SUCCESS; +end: + return ret; + + +} +int main(int argc, char **argv, char *env[]) +{ + int ret; + struct validation_ctx ctx; + + /* Check if we have all argument */ + if (argc < 3) { + fprintf(stderr, "ERR: %s\n", "Missing arguments"); + ret = CMD_ERROR; + goto end; + } + + /* Check if xsd file exist */ + ret = access(argv[1], F_OK); + if (ret < 0) { + fprintf(stderr, "ERR: %s\n", "Xsd path not valid"); + goto end; + } + + /* Check if xml to validate exist */ + ret = access(argv[2], F_OK); + if (ret < 0) { + fprintf(stderr, "ERR: %s\n", "XML path not valid"); + goto end; + } + + /* initialize the validation ctx */ + ret = init_validation_ctx(&ctx, argv[1]); + if (ret) { + goto end; + } + + ret = validate_xml(argv[2], &ctx); + + fini_validation_ctx(&ctx); + +end: + return ret; +} diff --git a/tests/regression/tools/mi/validate_xml.h b/tests/regression/tools/mi/validate_xml.h new file mode 100644 index 000000000..e69de29bb diff --git a/tests/run.sh b/tests/run.sh index c6c50fd9c..ce51639f7 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -19,4 +19,4 @@ [ -z "$1" ] && echo "Error: No testlist. Please specify a testlist to run." && exit 1 -prove --merge --exec '' - < $1 +prove $2 --merge --exec '' - < $1 -- 2.34.1