From: Jonathan Rajotte Date: Wed, 26 May 2021 20:39:12 +0000 (-0400) Subject: Move xml utils from mi subfolder to xml-utils folder X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=d11e3c3eeec8ba7db67f3b96c09fca4b7cabc9ad;p=lttng-tools.git Move xml utils from mi subfolder to xml-utils folder Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: I268dc544bf4f72f61a701ac3efd0b12488cc2f64 --- diff --git a/.gitignore b/.gitignore index aebc12bf8..d9ecbd3d3 100644 --- a/.gitignore +++ b/.gitignore @@ -102,8 +102,6 @@ compile_commands.json /tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns /tests/regression/tools/health/health_check /tests/regression/kernel/select_poll_epoll -/tests/regression/tools/mi/extract_xml -/tests/regression/tools/mi/validate_xml /tests/regression/tools/notification/base_client /tests/regression/tools/notification/notification /tests/regression/tools/rotation/schedule_api @@ -141,6 +139,8 @@ compile_commands.json /tests/utils/testapp/gen-ust-tracef/gen-ust-tracef /tests/utils/testapp/gen-syscall-events/gen-syscall-events /tests/utils/testapp/gen-kernel-test-events/gen-kernel-test-events +/tests/utils/xml-utils/extract_xml +/tests/utils/xml-utils/validate_xml /tests/regression/tools/live/live_test /tests/unit/ini_config/ini_config /tests/perf/find_event diff --git a/configure.ac b/configure.ac index 36fd14b48..932615150 100644 --- a/configure.ac +++ b/configure.ac @@ -1197,6 +1197,7 @@ AC_CONFIG_FILES([ tests/utils/testapp/userspace-probe-elf-binary/Makefile tests/utils/testapp/userspace-probe-elf-cxx-binary/Makefile tests/utils/testapp/userspace-probe-sdt-binary/Makefile + tests/utils/xml-utils/Makefile ]) # Inject variable into python test script. diff --git a/tests/regression/tools/mi/Makefile.am b/tests/regression/tools/mi/Makefile.am index c5bd827b1..bfa42bfc3 100644 --- a/tests/regression/tools/mi/Makefile.am +++ b/tests/regression/tools/mi/Makefile.am @@ -1,14 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -noinst_PROGRAMS = validate_xml extract_xml -validate_xml_SOURCES = validate_xml.c -validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS) -validate_xml_LDADD = $(libxml2_LIBS) - -extract_xml_SOURCES = extract_xml.c -extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS) -extract_xml_LDADD = $(libxml2_LIBS) - noinst_SCRIPTS = test_mi EXTRA_DIST = test_mi diff --git a/tests/regression/tools/mi/extract_xml.c b/tests/regression/tools/mi/extract_xml.c deleted file mode 100644 index 32c57e60a..000000000 --- a/tests/regression/tools/mi/extract_xml.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2014 Jonathan Rajotte - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -/* - * Usage: extract_xml [-v|-e] 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 -e look if node exist return "true" else nothing - * 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 -#include -#include - -#if defined(LIBXML_XPATH_ENABLED) - -static int opt_verbose; -static int node_exist; -static bool result = false; - -/** - * 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 = 0; - 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 (node_exist) { - result = true; - } else 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 */ - if (node_exist) { - result = true; - } else { - fprintf(stderr, "ERR:%s\n", - "Xpath expression return non-final xml element"); - ret = -1; - goto end; - } - } - } else { - if (node_exist) { - result = true; - } 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 (node_exist) { - result = true; - } else 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; -} - -static int register_lttng_namespace(xmlXPathContextPtr xpathCtx) -{ - int ret; - xmlChar *prefix; - xmlChar *ns = NULL; - - prefix = xmlCharStrdup("lttng"); - if (!prefix) { - ret = -1; - goto end; - } - - ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE); - if (!ns) { - ret = -1; - goto end; - } - - ret = xmlXPathRegisterNs(xpathCtx, prefix, ns); -end: - xmlFree(prefix); - xmlFree(ns); - 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) -{ - int ret; - 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; - } - - /* Register the LTTng MI namespace */ - ret = register_lttng_namespace(xpathCtx); - if (ret) { - fprintf(stderr, "ERR: Could not register lttng namespace\n"); - xmlXPathFreeContext(xpathCtx); - 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; - } - if (node_exist && result) { - fprintf(stdout, "true\n"); - } - - /* 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, "ve")) != -1) { - switch (opt) { - case 'v': - opt_verbose = 1; - break; - case 'e': - node_exist = 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 b/tests/regression/tools/mi/test_mi index db5dec50e..b3b637865 100755 --- a/tests/regression/tools/mi/test_mi +++ b/tests/regression/tools/mi/test_mi @@ -23,9 +23,10 @@ SESSIOND_LOAD_DIR=$(mktemp --tmpdir -d tmp.test_mi_sessiond_load_dir.XXXXXX) OUTPUT_FILE="default.xml" #Path to custom xml utilities -XML_VALIDATE="$CURDIR/validate_xml $XSD_PATH" -XML_EXTRACT="$CURDIR/extract_xml" -XML_NODE_CHECK="$CURDIR/extract_xml -e" +XML_UTILS_PATH="$TESTDIR/utils/xml-utils" +XML_VALIDATE="$XML_UTILS_PATH/validate_xml $XSD_PATH" +XML_EXTRACT="$XML_UTILS_PATH/extract_xml" +XML_NODE_CHECK="$XML_UTILS_PATH/extract_xml -e" XPATH_CMD_OUTPUT="//lttng:command/lttng:output" XPATH_COMMAND_SUCCESS="/lttng:command/lttng:success/text()" diff --git a/tests/regression/tools/mi/validate_xml.c b/tests/regression/tools/mi/validate_xml.c deleted file mode 100644 index eafe8b779..000000000 --- a/tests/regression/tools/mi/validate_xml.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2014 Jonathan Rajotte - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - - /* - * This script validate and xml from an xsd. - * argv[1] Path of the xsd - * argv[2] Path to the XML to be validated - */ - -#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 = { 0 }; - - /* 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 deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression/tools/relayd-grouping/test_ust b/tests/regression/tools/relayd-grouping/test_ust index 615741364..64fb90e34 100755 --- a/tests/regression/tools/relayd-grouping/test_ust +++ b/tests/regression/tools/relayd-grouping/test_ust @@ -18,8 +18,8 @@ CHANNEL_NAME="my_channel" XSD_PATH=$TESTDIR/../src/common/mi-lttng-4.0.xsd -XML_VALIDATE="$TESTDIR/regression/tools/mi/validate_xml $XSD_PATH" -XML_EXTRACT="$TESTDIR/regression/tools/mi/extract_xml" +XML_VALIDATE="$TESTDIR/utils/xml-utils/validate_xml $XSD_PATH" +XML_EXTRACT="$TESTDIR/utils/xml-utils/extract_xml" XPATH_CMD_OUTPUT="//lttng:command/lttng:output" XPATH_SESSION="$XPATH_CMD_OUTPUT/lttng:sessions/lttng:session" diff --git a/tests/regression/tools/rotation/test_save_load_mi b/tests/regression/tools/rotation/test_save_load_mi index fc3b24891..cb2050841 100755 --- a/tests/regression/tools/rotation/test_save_load_mi +++ b/tests/regression/tools/rotation/test_save_load_mi @@ -20,8 +20,8 @@ LTTNG_BIN="lttng --mi xml" XSD_PATH=$TESTDIR/../src/common/mi-lttng-4.0.xsd -XML_VALIDATE="$TESTDIR/regression/tools/mi/validate_xml $XSD_PATH" -XML_EXTRACT="$TESTDIR/regression/tools/mi/extract_xml" +XML_VALIDATE="$TESTDIR/utils/xml-utils/validate_xml $XSD_PATH" +XML_EXTRACT="$TESTDIR/utils/xml-utils/extract_xml" XPATH_CMD_OUTPUT="//lttng:command/lttng:output" XPATH_SESSION="$XPATH_CMD_OUTPUT/lttng:sessions/lttng:session" diff --git a/tests/regression/tools/save-load/test_load b/tests/regression/tools/save-load/test_load index 3cf0cc501..15901f4f0 100755 --- a/tests/regression/tools/save-load/test_load +++ b/tests/regression/tools/save-load/test_load @@ -19,6 +19,7 @@ DIR=$(readlink -f $TESTDIR) NUM_TESTS=75 source $TESTDIR/utils/utils.sh +XML_EXTRACT="$TESTDIR/utils/xml-utils/extract_xml" # MUST set TESTDIR before calling those functions plan_tests $NUM_TESTS @@ -63,21 +64,21 @@ function test_complex_load() break; fi $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list $sess -c chan2 > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain[lttng:type='UST']/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_disabled']/lttng:enabled/text()") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain[lttng:type='UST']/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_disabled']/lttng:enabled/text()") if [[ $mi_result = "false" ]]; then ok 0 "Disabled event is loaded in disabled state" else fail "Disabled event is loaded in disabled state" fi - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_disabled']/lttng:enabled/text()") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_disabled']/lttng:enabled/text()") test $mi_result = "false" ok $? "Disabled event is loaded in disabled state" # Check that uevent_same_name_diff_llevel with log level 6 (TRACE_INFO) is enabled # This ensure that the state of events with similar name but not same # descriptor tuple (exclusion,filter,loglevel) is restored correctly. - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_same_name_diff_llevel' and lttng:loglevel='TRACE_INFO']/lttng:enabled/text()") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:channels/lttng:channel[lttng:name='chan2']/lttng:events/lttng:event[lttng:name='uevent_same_name_diff_llevel' and lttng:loglevel='TRACE_INFO']/lttng:enabled/text()") test $mi_result = "true" ok $? "Enabled event with same name but different loglevel is in disabled state" @@ -132,21 +133,21 @@ function test_trackers() break; fi $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$SESSION_NAME-trackers" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vpid_process_attr_tracker/lttng:process_attr_values/lttng:vpid") + mi_result=$("$XML_EXTRACT" -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vpid_process_attr_tracker/lttng:process_attr_values/lttng:vpid") if [[ $mi_result = "true" ]]; then ok 0 "VPID target is present" else fail "VPID target missing" fi - mi_result=$($CURDIR/../mi/extract_xml -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vuid_process_attr_tracker/lttng:process_attr_values/lttng:vuid") + mi_result=$("$XML_EXTRACT" -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vuid_process_attr_tracker/lttng:process_attr_values/lttng:vuid") if [[ $mi_result = "true" ]]; then ok 0 "VUID target is present" else fail "VUID target missing" fi - mi_result=$($CURDIR/../mi/extract_xml -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vgid_process_attr_tracker/lttng:process_attr_values/lttng:vgid") + mi_result=$("$XML_EXTRACT" -e $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:process_attr_trackers/lttng:vgid_process_attr_tracker/lttng:process_attr_values/lttng:vgid") if [[ $mi_result = "true" ]]; then ok 0 "VGID target is present" else @@ -184,7 +185,7 @@ function test_override_url_normal() # Url of style file:// lttng_load_ok "-i $CURDIR/$SESSION_NAME.lttng --override-url=${local_url_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$SESSION_NAME" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") test $mi_result = "${local_path_compare_value}" ok $? "Path url file:// override [{$mi_result}, ${local_path_compare_value}]" @@ -193,7 +194,7 @@ function test_override_url_normal() # Url of style / lttng_load_ok "-i $CURDIR/$SESSION_NAME.lttng --override-url=${local_path_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$SESSION_NAME" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") test $mi_result = "${local_path_compare_value}" ok $? "Path url / override [{$mi_result}, ${local_path_compare_value}]" @@ -202,7 +203,7 @@ function test_override_url_normal() # Url of style net://ip:port:port lttng_load_ok "-i $CURDIR/$SESSION_NAME.lttng --override-url=${stream_url_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$SESSION_NAME" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") test "$mi_result" = "${stream_url_compare}" ok $? "Path url net://host:port:port override [${mi_result}, ${stream_url_compare}]" @@ -234,7 +235,7 @@ function test_override_url_snapshot() # Url of style file:// lttng_load_ok "-i $CONFIG_DIR/$local_session_name.lttng --override-url=${url_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML snapshot list-output -s "$local_session_name" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") test $mi_result = "${path_compare_value}" ok $? "Path url file:// override [{$mi_result}, ${path_compare_value}]" @@ -243,7 +244,7 @@ function test_override_url_snapshot() # Url of style / lttng_load_ok "-i $CONFIG_DIR/$local_session_name.lttng --override-url=${path_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML snapshot list-output -s "$local_session_name" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") test $mi_result = "${path_compare_value}" ok $? "Path url / override [{$mi_result}, ${path_compare_value}]" @@ -252,12 +253,12 @@ function test_override_url_snapshot() # Url of style net://ip:port:port lttng_load_ok "-i $CONFIG_DIR/$local_session_name.lttng --override-url=${stream_url_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML snapshot list-output -s "$local_session_name" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:ctrl_url") test "$mi_result" = "${stream_url_compare_ctrl}" ok $? "Path url ctrl net://host:port:port override [${mi_result}, ${stream_url_compare_ctrl}]" - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:data_url") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:snapshot_action/lttng:output/lttng:session/lttng:snapshots/lttng:snapshot/lttng:data_url") test "$mi_result" = "${stream_url_compare_data}" ok $? "Path url data net://host:port:port override [${mi_result}, ${stream_url_compare_data}]" @@ -300,7 +301,7 @@ function test_override_url_live() # Url of style net://ip:port:port lttng_load_ok "-i $CONFIG_DIR/$local_session_name.lttng --override-url=${stream_url_override}" $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$local_session_name" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") test "$mi_result" = "${stream_url_compare}" ok $? "Path url net://host:port:port override [${mi_result}, ${stream_url_compare}]" @@ -328,13 +329,13 @@ function test_override_session_name() fi ${TESTDIR}/../src/bin/lttng/${LTTNG_BIN} --mi XML list "${override_name}" > $mi_output_file - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:name") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:name") test "${mi_result}" = "${override_name}" ok $? "Override name successful [${SESSION_NAME} to ${override_name}]" # Make sure that the name override did not change something else - mi_result=$($CURDIR/../mi/extract_xml $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") + mi_result=$("$XML_EXTRACT" $mi_output_file "//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:path") test "${mi_result}" = "${output_path}" ok $? "Output path is not affected by name override" diff --git a/tests/utils/Makefile.am b/tests/utils/Makefile.am index c74d10c06..1c7c95326 100644 --- a/tests/utils/Makefile.am +++ b/tests/utils/Makefile.am @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -SUBDIRS = . tap testapp +SUBDIRS = . tap testapp xml-utils EXTRA_DIST = utils.sh test_utils.py babelstats.pl warn_processes.sh \ parse-callstack.py diff --git a/tests/utils/xml-utils/Makefile.am b/tests/utils/xml-utils/Makefile.am new file mode 100644 index 000000000..9b00f7027 --- /dev/null +++ b/tests/utils/xml-utils/Makefile.am @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only + +noinst_PROGRAMS = validate_xml extract_xml +validate_xml_SOURCES = validate_xml.c +validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS) +validate_xml_LDADD = $(libxml2_LIBS) + +extract_xml_SOURCES = extract_xml.c +extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS) +extract_xml_LDADD = $(libxml2_LIBS) + +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/utils/xml-utils/extract_xml.c b/tests/utils/xml-utils/extract_xml.c new file mode 100644 index 000000000..32c57e60a --- /dev/null +++ b/tests/utils/xml-utils/extract_xml.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2014 Jonathan Rajotte + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +/* + * Usage: extract_xml [-v|-e] 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 -e look if node exist return "true" else nothing + * 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 +#include +#include + +#if defined(LIBXML_XPATH_ENABLED) + +static int opt_verbose; +static int node_exist; +static bool result = false; + +/** + * 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 = 0; + 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 (node_exist) { + result = true; + } else 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 */ + if (node_exist) { + result = true; + } else { + fprintf(stderr, "ERR:%s\n", + "Xpath expression return non-final xml element"); + ret = -1; + goto end; + } + } + } else { + if (node_exist) { + result = true; + } 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 (node_exist) { + result = true; + } else 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; +} + +static int register_lttng_namespace(xmlXPathContextPtr xpathCtx) +{ + int ret; + xmlChar *prefix; + xmlChar *ns = NULL; + + prefix = xmlCharStrdup("lttng"); + if (!prefix) { + ret = -1; + goto end; + } + + ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE); + if (!ns) { + ret = -1; + goto end; + } + + ret = xmlXPathRegisterNs(xpathCtx, prefix, ns); +end: + xmlFree(prefix); + xmlFree(ns); + 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) +{ + int ret; + 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; + } + + /* Register the LTTng MI namespace */ + ret = register_lttng_namespace(xpathCtx); + if (ret) { + fprintf(stderr, "ERR: Could not register lttng namespace\n"); + xmlXPathFreeContext(xpathCtx); + 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; + } + if (node_exist && result) { + fprintf(stdout, "true\n"); + } + + /* 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, "ve")) != -1) { + switch (opt) { + case 'v': + opt_verbose = 1; + break; + case 'e': + node_exist = 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/utils/xml-utils/validate_xml.c b/tests/utils/xml-utils/validate_xml.c new file mode 100644 index 000000000..eafe8b779 --- /dev/null +++ b/tests/utils/xml-utils/validate_xml.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2014 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + + /* + * This script validate and xml from an xsd. + * argv[1] Path of the xsd + * argv[2] Path to the XML to be validated + */ + +#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 = { 0 }; + + /* 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; +}