From 717ff3b75bca054a7f14de43a6ef6fc0535d3953 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sat, 23 May 2009 18:39:30 +1000 Subject: Expanding the test case to include the POC demo The POC demo does not actually do much testing yet, other than just working or not working - but it's in place now for future enhancements. --- unit-tests/Makefile | 33 +++++++ unit-tests/POCDemo.py | 12 +++ unit-tests/demo.c | 99 +++++++++++++++++++ unit-tests/demo.h | 14 +++ unit-tests/dmixml.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++ unit-tests/dmixml.h | 43 ++++++++ unit-tests/libxml2mod.so | Bin 0 -> 380000 bytes unit-tests/libxml_wrap.h | 249 +++++++++++++++++++++++++++++++++++++++++++++++ unit-tests/unit | 193 ++++++++++++++++++++++++++++++++++++ 9 files changed, 891 insertions(+) create mode 100644 unit-tests/Makefile create mode 100644 unit-tests/POCDemo.py create mode 100644 unit-tests/demo.c create mode 100644 unit-tests/demo.h create mode 100644 unit-tests/dmixml.c create mode 100644 unit-tests/dmixml.h create mode 100644 unit-tests/libxml2mod.so create mode 100644 unit-tests/libxml_wrap.h create mode 100755 unit-tests/unit (limited to 'unit-tests') diff --git a/unit-tests/Makefile b/unit-tests/Makefile new file mode 100644 index 0000000..24fbfa9 --- /dev/null +++ b/unit-tests/Makefile @@ -0,0 +1,33 @@ +## This one is important to get right ... +## We need to link in the libxml2mod.so file from here +PYLIBDIR := /usr/lib64/python2.5/site-packages +PYLIBDIR := /usr/lib/python-support/python-libxml2/python2.5 + +# Defaults, should be fine +CFLAGS=-I. $(shell xml2-config --cflags) -g -Wall $(shell python-config --cflags) + +LIBS=$(shell xml2-config --libs) -lxml2mod $(shell python-config --libs) +LIBDIR=-L $(PYLIBDIR) + +.SUFFIX=.c .o .so + +all : test + +demomodule.so : demo.o dmixml.o + @echo "Linking: $@" + @gcc -fPIC --shared -o $@ $^ $(LIBS) $(LIBDIR) + +.c.o : + @echo "Compiling $<" + @gcc -fPIC -c $< $(CFLAGS) + +test : demomodule.so + @echo "==========================================" + @echo " Running proof-of-concept code" + @echo "==========================================" + @echo "" + @python unit + +clean : + rm -f demomodule.so *.{py[oc],o} *~ + diff --git a/unit-tests/POCDemo.py b/unit-tests/POCDemo.py new file mode 100644 index 0000000..475a62b --- /dev/null +++ b/unit-tests/POCDemo.py @@ -0,0 +1,12 @@ +import libxml2 +import demomodule # This is our core module + +class POCDemo: + """Demo of a wrapper class to return proper python libxml2 objects""" + + def GetXMLdoc(self): + return libxml2.xmlDoc( _obj = demomodule.dump_doc() ) + + def GetXMLnode(self): + return libxml2.xmlNode( _obj = demomodule.dump_node() ) + diff --git a/unit-tests/demo.c b/unit-tests/demo.c new file mode 100644 index 0000000..265f3cb --- /dev/null +++ b/unit-tests/demo.c @@ -0,0 +1,99 @@ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +#include "demo.h" + +xmlNode *gen_nodes(const char *entry ) { + xmlNode *c_xmlNode_root = NULL; + xmlNode *c_xmlNode_tag = NULL; + + // Prepare a root node + c_xmlNode_root = xmlNewNode(NULL, (xmlChar *) "dmixml_demo"); + assert( c_xmlNode_root != NULL ); + + dmixml_AddAttribute(c_xmlNode_root, "entrypoint", "%s", entry); + + // Populate XML + dmixml_AddTextChild(c_xmlNode_root, "Test", "Yes, just testing"); + + c_xmlNode_tag = dmixml_AddTextChild(c_xmlNode_root, "tag1", "Another test"); + dmixml_AddAttribute(c_xmlNode_tag, "TestTagID", "%i", 1); + + c_xmlNode_tag = c_xmlNode_root; + int i; + for(i = 0; i <= 3; ++i) { + c_xmlNode_tag = xmlNewChild(c_xmlNode_tag, NULL, (xmlChar *) "subtag", NULL); + dmixml_AddAttribute(c_xmlNode_tag, "SubLevel", "%i", i); + } + dmixml_AddTextContent(c_xmlNode_tag, "%s - Adding data to the tag at sublevel %i", "TEST", i-1); + + return c_xmlNode_root; +} + + + + +PyObject* demo_dump_doc() { + PyObject *py_xmlDoc = NULL; + xmlDoc *c_xmlDoc = NULL; + + // Create an XML document + c_xmlDoc = xmlNewDoc((xmlChar *) "1.0"); + assert( c_xmlDoc != NULL ); + + // Generate XML nodes and assign the root node to the document + xmlDocSetRootElement( c_xmlDoc, gen_nodes("demo_dump_doc") ); + + py_xmlDoc = libxml_xmlDocPtrWrap((xmlDocPtr) c_xmlDoc); + Py_INCREF(py_xmlDoc); + + return py_xmlDoc; +} + +PyObject* demo_dump_node() { + PyObject *py_xmlNode = NULL; + xmlNode *nodes = NULL; + + nodes = gen_nodes("demo_dump_node"); + py_xmlNode = libxml_xmlNodePtrWrap((xmlNodePtr) nodes); + Py_INCREF(py_xmlNode); + + return py_xmlNode; +} + + + +static PyMethodDef DemoMethods[] = { + { "dump_doc", demo_dump_doc, METH_NOARGS, (char *)"Return an XML document" }, + { "dump_node", demo_dump_node, METH_NOARGS, (char *)"Retuen an XML node" }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initdemomodule(void) { + PyObject *module = + Py_InitModule3((char *)"demomodule", DemoMethods, + "LibXML2 DMIDecode Proof-of-Concept Python Module"); + + PyObject *version = PyString_FromString("0.10"); + Py_INCREF(version); + PyModule_AddObject(module, "version", version); +} diff --git a/unit-tests/demo.h b/unit-tests/demo.h new file mode 100644 index 0000000..21a5468 --- /dev/null +++ b/unit-tests/demo.h @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +#include +#include "libxml_wrap.h" + +#include "dmixml.h" + +extern PyObject* demo_dump(void); +PyMODINIT_FUNC initdemomodule(void); +PyObject* demo_dump_doc(void); +PyObject* demo_dump_node(void); diff --git a/unit-tests/dmixml.c b/unit-tests/dmixml.c new file mode 100644 index 0000000..dbca0c3 --- /dev/null +++ b/unit-tests/dmixml.c @@ -0,0 +1,248 @@ +/* Simplified XML API for dmidecode + * + * Copyright 2009 David Sommerseth + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +#include +#include +#include + +#include +#include +#include + +// Internal function for dmixml_* functions ... builds up a variable xmlChar* string +xmlChar *dmixml_buildstr(size_t len, const char *fmt, va_list ap) { + xmlChar *ret = NULL, *xmlfmt = NULL; + xmlChar *ptr = NULL; + + ret = (xmlChar *) malloc(len+2); + assert( ret != NULL ); + memset(ret, 0, len+2); + + xmlfmt = xmlCharStrdup(fmt); + assert( xmlfmt != NULL ); + + xmlStrVPrintf(ret, len, xmlfmt, ap); + free(xmlfmt); + + // Right trim the string + ptr = ret + xmlStrlen(ret)-1; + while( (ptr >= ret) && (*ptr == ' ') ) { + *ptr = 0; + ptr--; + } + return ret; +} + + +// Adds an XML property/attribute to the given XML node +// +// xmldata_n = ""; +// dmixml_AddAttribute(xmldata_n, "value", "1234"); +// gives: xmldata_n = "properties; aptr != NULL; aptr = aptr->next ) { + if( xmlStrcmp(aptr->name, key_s) == 0 ) { + free(key_s); key_s = NULL; + // FIXME: Should find better way how to return UTF-8 data + return (char *)(aptr->children != NULL ? aptr->children->content : NULL); + } + } + free(key_s); key_s = NULL; + return NULL; +} + +xmlNode *dmixml_FindNode(xmlNode *node, const char *key) { + xmlNode *ptr_n = NULL; + xmlChar *key_s = NULL; + + if( node->children == NULL ) { + return NULL; + } + + key_s = xmlCharStrdup(key); + assert( key_s != NULL ); + + for( ptr_n = node->children; ptr_n != NULL; ptr_n = ptr_n->next ) { + if( (ptr_n->type == XML_ELEMENT_NODE) + && (xmlStrcmp(ptr_n->name, key_s) == 0) ) { + free(key_s); key_s = NULL; + return ptr_n; + } + } + free(key_s); key_s = NULL; + return NULL; +} + +inline char *dmixml_GetContent(xmlNode *node) { + // FIXME: Should find better way how to return UTF-8 data + return (((node != NULL) && (node->children != NULL)) ? (char *) node->children->content : NULL); +} + +inline char *dmixml_GetNodeContent(xmlNode *node, const char *key) { + return dmixml_GetContent(dmixml_FindNode(node, key)); +} + +char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx) { + memset(buf, 0, buflen); + + if( xpo == NULL ) { + return NULL; + } + + switch( xpo->type ) { + case XPATH_STRING: + strncpy(buf, (char *)xpo->stringval, buflen-1); + break; + + case XPATH_NUMBER: + snprintf(buf, buflen-1, "%f", xpo->floatval); + break; + + case XPATH_NODESET: + if( (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr >= (idx+1)) ) { + char *str = dmixml_GetContent(xpo->nodesetval->nodeTab[idx]); + if( str != NULL ) { + strncpy(buf, str, buflen-1); + } else { + memset(buf, 0, buflen); + } + } + break; + + default: + fprintf(stderr, "dmixml_GetXPathContent(...):: " + "Do not know how to handle XPath type %i\n", + xpo->type); + return NULL; + } + return buf; +} + diff --git a/unit-tests/dmixml.h b/unit-tests/dmixml.h new file mode 100644 index 0000000..b1d86c6 --- /dev/null +++ b/unit-tests/dmixml.h @@ -0,0 +1,43 @@ +/* Simplified XML API for dmidecode + * + * Copyright 2009 David Sommerseth + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +#ifndef _XMLHELPER_H +#define _XMLHELPER_H + +#include +#include +#include + +xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt, ...); +xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt, ...); +xmlNode *dmixml_AddTextContent(xmlNode *node, const char *fmt, ...); + +char *dmixml_GetAttrValue(xmlNode *node, const char *key); +xmlNode *dmixml_FindNode(xmlNode *, const char *key); +inline char *dmixml_GetContent(xmlNode *node); +inline char *dmixml_GetNodeContent(xmlNode *node, const char *key); +char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx); + +#endif diff --git a/unit-tests/libxml2mod.so b/unit-tests/libxml2mod.so new file mode 100644 index 0000000..4043179 Binary files /dev/null and b/unit-tests/libxml2mod.so differ diff --git a/unit-tests/libxml_wrap.h b/unit-tests/libxml_wrap.h new file mode 100644 index 0000000..eaa5e96 --- /dev/null +++ b/unit-tests/libxml_wrap.h @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + * Repeated here since the definition is not available when + * compiled outside the libxml2 build tree. + */ +#ifdef __GNUC__ +#ifdef ATTRIBUTE_UNUSED +#undef ATTRIBUTE_UNUSED +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ +#else +#define ATTRIBUTE_UNUSED +#endif + +#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlNode_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlNodePtr obj; +} PyxmlNode_Object; + +#define PyxmlXPathContext_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlXPathContext_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlXPathContextPtr obj; +} PyxmlXPathContext_Object; + +#define PyxmlXPathParserContext_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlXPathParserContext_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlXPathParserContextPtr obj; +} PyxmlXPathParserContext_Object; + +#define PyparserCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PyparserCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlParserCtxtPtr obj; +} PyparserCtxt_Object; + +#define PyValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PyValidCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlValidCtxtPtr obj; +} PyValidCtxt_Object; + +#define Pycatalog_Get(v) (((v) == Py_None) ? NULL : \ + (((Pycatalog_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlCatalogPtr obj; +} Pycatalog_Object; + +#ifdef LIBXML_REGEXP_ENABLED +#define PyxmlReg_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlReg_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlRegexpPtr obj; +} PyxmlReg_Object; +#endif /* LIBXML_REGEXP_ENABLED */ + +#ifdef LIBXML_READER_ENABLED +#define PyxmlTextReader_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlTextReader_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlTextReaderPtr obj; +} PyxmlTextReader_Object; + +#define PyxmlTextReaderLocator_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlTextReaderLocator_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlTextReaderLocatorPtr obj; +} PyxmlTextReaderLocator_Object; +#endif + +#define PyURI_Get(v) (((v) == Py_None) ? NULL : \ + (((PyURI_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlErrorPtr obj; +} PyError_Object; + +#define PyError_Get(v) (((v) == Py_None) ? NULL : \ + (((PyError_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlOutputBufferPtr obj; +} PyoutputBuffer_Object; + +#define PyoutputBuffer_Get(v) (((v) == Py_None) ? NULL : \ + (((PyoutputBuffer_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlParserInputBufferPtr obj; +} PyinputBuffer_Object; + +#define PyinputBuffer_Get(v) (((v) == Py_None) ? NULL : \ + (((PyinputBuffer_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlURIPtr obj; +} PyURI_Object; + +/* FILE * have their own internal representation */ +#define PyFile_Get(v) (((v) == Py_None) ? NULL : \ + (PyFile_Check(v) ? (PyFile_AsFile(v)) : stdout)) + +#ifdef LIBXML_SCHEMAS_ENABLED +typedef struct { + PyObject_HEAD + xmlRelaxNGPtr obj; +} PyrelaxNgSchema_Object; + +#define PyrelaxNgSchema_Get(v) (((v) == Py_None) ? NULL : \ + (((PyrelaxNgSchema_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlRelaxNGParserCtxtPtr obj; +} PyrelaxNgParserCtxt_Object; + +#define PyrelaxNgParserCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PyrelaxNgParserCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlRelaxNGValidCtxtPtr obj; +} PyrelaxNgValidCtxt_Object; + +#define PyrelaxNgValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PyrelaxNgValidCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlSchemaPtr obj; +} PySchema_Object; + +#define PySchema_Get(v) (((v) == Py_None) ? NULL : \ + (((PySchema_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlSchemaParserCtxtPtr obj; +} PySchemaParserCtxt_Object; + +#define PySchemaParserCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PySchemaParserCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlSchemaValidCtxtPtr obj; +} PySchemaValidCtxt_Object; + +#define PySchemaValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PySchemaValidCtxt_Object *)(v))->obj)) + +#endif /* LIBXML_SCHEMAS_ENABLED */ + +PyObject * libxml_intWrap(int val); +PyObject * libxml_longWrap(long val); +PyObject * libxml_xmlCharPtrWrap(xmlChar *str); +PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str); +PyObject * libxml_charPtrWrap(char *str); +PyObject * libxml_constcharPtrWrap(const char *str); +PyObject * libxml_charPtrConstWrap(const char *str); +PyObject * libxml_xmlCharPtrConstWrap(const xmlChar *str); +PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc); +PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node); +PyObject * libxml_xmlAttrPtrWrap(xmlAttrPtr attr); +PyObject * libxml_xmlNsPtrWrap(xmlNsPtr ns); +PyObject * libxml_xmlAttributePtrWrap(xmlAttributePtr ns); +PyObject * libxml_xmlElementPtrWrap(xmlElementPtr ns); +PyObject * libxml_doubleWrap(double val); +PyObject * libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt); +PyObject * libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt); +PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt); +PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj); +PyObject * libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid); +PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj); +PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri); +PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer); +PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer); +#ifdef LIBXML_REGEXP_ENABLED +PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp); +#endif /* LIBXML_REGEXP_ENABLED */ +#ifdef LIBXML_READER_ENABLED +PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader); +PyObject * libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator); +#endif + +xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj); +#ifdef LIBXML_SCHEMAS_ENABLED +PyObject * libxml_xmlRelaxNGPtrWrap(xmlRelaxNGPtr ctxt); +PyObject * libxml_xmlRelaxNGParserCtxtPtrWrap(xmlRelaxNGParserCtxtPtr ctxt); +PyObject * libxml_xmlRelaxNGValidCtxtPtrWrap(xmlRelaxNGValidCtxtPtr valid); +PyObject * libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt); +PyObject * libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt); +PyObject * libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid); +#endif /* LIBXML_SCHEMAS_ENABLED */ +PyObject * libxml_xmlErrorPtrWrap(xmlErrorPtr error); +PyObject * libxml_xmlSchemaSetValidErrors(PyObject * self, PyObject * args); diff --git a/unit-tests/unit b/unit-tests/unit new file mode 100755 index 0000000..160641a --- /dev/null +++ b/unit-tests/unit @@ -0,0 +1,193 @@ +#!/usr/bin/env python +#.awk '$0 ~ /case [0-9]+: .. 3/ { sys.stdout.write($2 }' src/dmidecode.c|tr ':\n' ', ' + +from pprint import pprint +import os, sys, random, tempfile, time +import commands +import libxml2 +from POCDemo import POCDemo + +DUMPS_D = "private" + +def ascii(s, i): return "\033[%d;1m%s\033[0m"%(30+i, str(s)) +def black(s): return "\033[30;1m%s\033[0m"%(str(s)) +def red(s): return "\033[31;1m%s\033[0m"%(str(s)) +def green(s): return "\033[32;1m%s\033[0m"%(str(s)) +def yellow(s): return "\033[33;1m%s\033[0m"%(str(s)) +def blue(s): return "\033[34;1m%s\033[0m"%(str(s)) +def magenta(s): return "\033[35;1m%s\033[0m"%(str(s)) +def cyan(s): return "\033[36;1m%s\033[0m"%(str(s)) +def white(s): return "\033[37;1m%s\033[0m"%(str(s)) + +DISPATCH = { + 1 : red, + 2 : green, + 3 : yellow, + 4 : blue, + 5 : magenta, + 6 : cyan, + 7 : white, +} + +LINE = "%s\n"%(magenta("="*80)) + +score = { + "total" : 0, + "skipped" : 0, + "passed" : 0, + "failed" : 0, +} + +def passed(msg=None, indent=1): + global score + score["total"] += 1 + score["passed"] += 1 + sys.stdout.write("%s\n"%green("PASS")) + if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, green("P"), msg)) +def skipped(msg=None, indent=1): + global score + score["total"] += 1 + score["skipped"] += 1 + sys.stdout.write("%s\n"%yellow("SKIP")) + if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, yellow("S"), msg)) +def failed(msg=None, indent=1): + global score + score["total"] += 1 + score["failed"] += 1 + sys.stdout.write("%s\n"%red("FAIL")) + if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, red("F"), msg)) +def test(r, msg=None, indent=1): + if r: + passed(msg, indent) + return True + else: + failed(msg, indent) + return False + +sys.stdout.write(LINE) +sys.stdout.write(" * Testing for dmidecode (upstream)...") +d = True in [os.path.exists(os.path.join(_, "dmidecode")) for _ in os.getenv("PATH").split(':')] +test(d) + +sys.stdout.write(" * Creation of temporary files...") +try: + FH, DUMP = tempfile.mkstemp() + os.unlink(DUMP) + os.close(FH) + passed() +except: + failed() + +sys.stdout.write(LINE) +sys.stdout.write(" * Importing module...") +try: + import dmidecode + passed() + sys.stdout.write(" * Version: %s\n"%blue(dmidecode.version)) + sys.stdout.write(" * DMI Version String: %s\n"%blue(dmidecode.dmi)) + + sys.stdout.write(" * Testing that default device is /dev/mem...") + test(dmidecode.get_dev() == "/dev/mem") + + sys.stdout.write(" * Testing that write-lock will not break on dump()...") + test(not dmidecode.dump()) + + sys.stdout.write(" * Testing ability to change device to %s..."%DUMP) + test(dmidecode.set_dev(DUMP)) + + sys.stdout.write(" * Testing that device has changed to %s..."%DUMP) + test(dmidecode.get_dev() == DUMP) + + sys.stdout.write(" * Testing that write on new file is ok...") + test(dmidecode.dump()) + + sys.stdout.write(" * Testing that file was actually written...") + time.sleep(0.1) + if test(os.path.exists(DUMP)): + os.unlink(DUMP) + + types = range(0, 42)+range(126, 128) + bad_types = [-1, -1000, 256] + sections = ["bios", "system", "baseboard", "chassis", "processor", "memory", "cache", "connector", "slot"] + devices = [] + if os.path.exists(DUMPS_D): + devices.extend([os.path.join(DUMPS_D, _) for _ in os.listdir(DUMPS_D)]) + else: + sys.stdout.write(" * If you have memory dumps to test, create a directory called `%s' and drop them in there.\n"%(DUMPS_D)) + devices.append("/dev/mem") + random.shuffle(types) + random.shuffle(devices) + random.shuffle(sections) + + for dev in devices: + sys.stdout.write(LINE) + sys.stdout.write(" * Testing %s..."%yellow(dev)); sys.stdout.flush() + try: + fH = open(dev, 'r') + fH.close() + passed() + sys.stdout.write(" * Testing set_dev/get_dev on %s..."%(yellow(dev))); sys.stdout.flush() + if test(dmidecode.set_dev(dev) and dmidecode.get_dev() == dev): + i = 0 + for section in sections: + i += 1 + sys.stdout.write(" * Testing %s (%d/%d)..."%(cyan(section), i, len(sections))); sys.stdout.flush() + try: + output = getattr(dmidecode, section)() + test(output is not False) + if output: + sys.stdout.write(" * %s\n"%black(output.keys())) + except LookupError, e: + failed(e, 2) + + for i in bad_types: + sys.stdout.write(" * Testing bad type %s..."%red(i)); sys.stdout.flush() + try: + output = dmidecode.type(i) + test(output is False) + except SystemError: + failed() + + for i in types: + sys.stdout.write(" * Testing type %s..."%red(i)); sys.stdout.flush() + try: + output = dmidecode.type(i) + if dmidecode: + _output = commands.getoutput("dmidecode -t %d"%i).strip().split('\n') + test(len(_output) == 1 and len(output) == 0 or True) + else: + test(output is not False) + if output: + sys.stdout.write(" * %s\n"%output.keys()) + except IOError, e: + failed(e, 2) + except IOError: + skipped() + +except ImportError: + failed() + + + +test = POCDemo() +print "Please note the dmixml_demo/@entrypoint attribute in the root node" +print +print "-------- xmlDoc ---------------" +xmldoc = test.GetXMLdoc() +xmldoc.saveFormatFileEnc("-", "UTF-8", 1) + +print +print "-------- xmlNode ---------------" +xmldoc2 = libxml2.newDoc("1.0") +xmlnode = test.GetXMLnode() +xmldoc2.setRootElement(xmlnode) +xmldoc2.saveFormatFileEnc("-", "UTF-8", 1) + + + +sys.stdout.write(LINE) +sys.stdout.write("Devices : %s\n"%cyan(len(devices))) +sys.stdout.write("Total : %s\n"%blue(score["total"])) +sys.stdout.write("Skipped : %s\n"%yellow(score["skipped"])) +sys.stdout.write("Passed : %s\n"%green(score["passed"])) +sys.stdout.write("Failed : %s\n"%red(score["failed"])) -- cgit From af27ba4dd2ffdef8e4ee3abf187475c1b3303f71 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sun, 24 May 2009 00:26:23 +1000 Subject: Completed preliminary reimplementation of type() Updated test unit to match. Throw an exception instead of returning None/False in some functions. --- unit-tests/unit | 2 ++ 1 file changed, 2 insertions(+) (limited to 'unit-tests') diff --git a/unit-tests/unit b/unit-tests/unit index 160641a..61a194c 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -161,6 +161,8 @@ try: sys.stdout.write(" * %s\n"%output.keys()) except IOError, e: failed(e, 2) + except LookupError, e: + failed(e, 2) except IOError: skipped() -- cgit From 6ff73a634b11dacfd246ea8bdb6df3e51cda5118 Mon Sep 17 00:00:00 2001 From: Nima Talebi Date: Sun, 24 May 2009 04:09:43 +1000 Subject: Cleanup --- unit-tests/Makefile | 5 +++-- unit-tests/libxml2mod.so | Bin 380000 -> 0 bytes unit-tests/unit | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 unit-tests/libxml2mod.so (limited to 'unit-tests') diff --git a/unit-tests/Makefile b/unit-tests/Makefile index 24fbfa9..01706a3 100644 --- a/unit-tests/Makefile +++ b/unit-tests/Makefile @@ -21,7 +21,8 @@ demomodule.so : demo.o dmixml.o @echo "Compiling $<" @gcc -fPIC -c $< $(CFLAGS) -test : demomodule.so +#test : demomodule.so +test : @echo "==========================================" @echo " Running proof-of-concept code" @echo "==========================================" @@ -29,5 +30,5 @@ test : demomodule.so @python unit clean : - rm -f demomodule.so *.{py[oc],o} *~ + rm -f *.{py[oc],o,so} *~ diff --git a/unit-tests/libxml2mod.so b/unit-tests/libxml2mod.so deleted file mode 100644 index 4043179..0000000 Binary files a/unit-tests/libxml2mod.so and /dev/null differ diff --git a/unit-tests/unit b/unit-tests/unit index 61a194c..0f8a51b 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -4,8 +4,6 @@ from pprint import pprint import os, sys, random, tempfile, time import commands -import libxml2 -from POCDemo import POCDemo DUMPS_D = "private" @@ -170,6 +168,9 @@ except ImportError: failed() +""" +import libxml2 +from POCDemo import POCDemo test = POCDemo() print "Please note the dmixml_demo/@entrypoint attribute in the root node" @@ -184,6 +185,7 @@ xmldoc2 = libxml2.newDoc("1.0") xmlnode = test.GetXMLnode() xmldoc2.setRootElement(xmlnode) xmldoc2.saveFormatFileEnc("-", "UTF-8", 1) +""" -- cgit From e9ae400e4dc70966bfd940c27f9a8b91d5caffa4 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 10 Jun 2009 16:48:51 +0200 Subject: Updated unit-test to check the XML API --- unit-tests/unit | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'unit-tests') diff --git a/unit-tests/unit b/unit-tests/unit index 0f8a51b..b6018f9 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -79,7 +79,10 @@ except: sys.stdout.write(LINE) sys.stdout.write(" * Importing module...") try: + import libxml2 import dmidecode + import dmidecodeXML + passed() sys.stdout.write(" * Version: %s\n"%blue(dmidecode.version)) sys.stdout.write(" * DMI Version String: %s\n"%blue(dmidecode.dmi)) @@ -161,11 +164,79 @@ try: failed(e, 2) except LookupError, e: failed(e, 2) + + dmixml = dmidecodeXML.dmidecodeXML() + try: + sys.stdout.write(" * XML: Swapping result type dmidecodeXML::SetResultType('-')..."); + sys.stdout.flush() + test(not dmixml.SetResultType('-')) + except TypeError: + sys.stdout.write("Not working => ") + passed() + except: + sys.stdout.write("Accepted => ") + failed() + + try: + sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecodeXML.DMIXML_DOC)..."); + sys.stdout.flush() + test(dmixml.SetResultType(dmidecodeXML.DMIXML_DOC)) + sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecodeXML.DMIXML_NODE)..."); + sys.stdout.flush() + test(dmixml.SetResultType(dmidecodeXML.DMIXML_NODE)) + except: + failed() + + for i in bad_types: + sys.stdout.write(" * XML: Testing bad type - dmidecodeXML::QueryTypeId(%s)..." + % red(i)) + sys.stdout.flush() + try: + output_node = dmixml.QueryTypeId(i) + test(not isinstance(output_node, libxml2.xmlNode)) + except SystemError: + sys.stdout.write("Accepted => ") + failed() + except TypeError: + sys.stdout.write("Not working => ") + passed() + except ValueError: + sys.stdout.write("Not working => ") + passed() + + for i in types: + sys.stdout.write(" * XML: Testing dmidecodeXML::QueryTypeId(%s)..." + % red(i)) + sys.stdout.flush() + try: + output_node = dmixml.QueryTypeId(i) + test(isinstance(output_node, libxml2.xmlNode)) + except Exception, e: + failed(e, 2) + except: + failed() + + dmixml.SetResultType(dmidecodeXML.DMIXML_DOC) + i = 0 + for section in sections: + i += 1 + sys.stdout.write(" * XML: Testing dmidecodeXML::QuerySection('%s') (%d/%d)..." + % (cyan(section), i, len(sections))) + sys.stdout.flush() + try: + output_doc = dmixml.QuerySection(section) + test(isinstance(output_doc, libxml2.xmlDoc)) + except Exception, e: + failed(e, 2) + except: + failed() + except IOError: skipped() -except ImportError: +except ImportError, err: failed() + print err """ -- cgit From 65c9384ec9b6e265aba11227ffa37ae7a6a787d1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 10 Jun 2009 18:57:42 +0200 Subject: Fixed import issues with dmidecode As we now include libxml2 and the required libxml2mod (which is used to wrap xmlDoc and xmlNode data into Python objects), importing only dmidecode caused a failure. If adding import libxml2 first, everything would work out fine. To avoid this issue, due to backwards compatibility, a tiny dmidecode wrapper is implemted as well. The dmidecode.so module is now renamed to dmidecodemodule.so, and the wrapper is now called dmidecode.py. To simplify things, the dmidecodeXML module introduced in commit b25b2ca548508cd2beb26f465b7bc5a296592461 is not merged into the new dmidecode.py The constants mentioned are now called dmidecode.DMIXML_NODE and dmidecode.DMIXML_DOC and to instantiate the dmidecodeXML class, dmidecode.dmidecodeXML() is used. --- unit-tests/dmidecode.py | 1 + unit-tests/unit | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) create mode 120000 unit-tests/dmidecode.py (limited to 'unit-tests') diff --git a/unit-tests/dmidecode.py b/unit-tests/dmidecode.py new file mode 120000 index 0000000..4876cd6 --- /dev/null +++ b/unit-tests/dmidecode.py @@ -0,0 +1 @@ +../dmidecode.py \ No newline at end of file diff --git a/unit-tests/unit b/unit-tests/unit index b6018f9..8156945 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -64,8 +64,8 @@ def test(r, msg=None, indent=1): sys.stdout.write(LINE) sys.stdout.write(" * Testing for dmidecode (upstream)...") -d = True in [os.path.exists(os.path.join(_, "dmidecode")) for _ in os.getenv("PATH").split(':')] -test(d) +dmidecode_bin = True in [os.path.exists(os.path.join(_, "dmidecode")) for _ in os.getenv("PATH").split(':')] +test(dmidecode_bin) sys.stdout.write(" * Creation of temporary files...") try: @@ -77,13 +77,12 @@ except: failed() sys.stdout.write(LINE) -sys.stdout.write(" * Importing module...") try: + sys.stdout.write(" * Importing module...") import libxml2 import dmidecode - import dmidecodeXML - passed() + sys.stdout.write(" * Version: %s\n"%blue(dmidecode.version)) sys.stdout.write(" * DMI Version String: %s\n"%blue(dmidecode.dmi)) @@ -153,7 +152,7 @@ try: sys.stdout.write(" * Testing type %s..."%red(i)); sys.stdout.flush() try: output = dmidecode.type(i) - if dmidecode: + if dmidecode_bin: _output = commands.getoutput("dmidecode -t %d"%i).strip().split('\n') test(len(_output) == 1 and len(output) == 0 or True) else: @@ -165,7 +164,7 @@ try: except LookupError, e: failed(e, 2) - dmixml = dmidecodeXML.dmidecodeXML() + dmixml = dmidecode.dmidecodeXML() try: sys.stdout.write(" * XML: Swapping result type dmidecodeXML::SetResultType('-')..."); sys.stdout.flush() @@ -178,12 +177,12 @@ try: failed() try: - sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecodeXML.DMIXML_DOC)..."); + sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_DOC)..."); sys.stdout.flush() - test(dmixml.SetResultType(dmidecodeXML.DMIXML_DOC)) - sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecodeXML.DMIXML_NODE)..."); + test(dmixml.SetResultType(dmidecode.DMIXML_DOC)) + sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_NODE)..."); sys.stdout.flush() - test(dmixml.SetResultType(dmidecodeXML.DMIXML_NODE)) + test(dmixml.SetResultType(dmidecode.DMIXML_NODE)) except: failed() @@ -216,7 +215,7 @@ try: except: failed() - dmixml.SetResultType(dmidecodeXML.DMIXML_DOC) + dmixml.SetResultType(dmidecode.DMIXML_DOC) i = 0 for section in sections: i += 1 -- cgit From 541ee10989640f028d777c9341c63573aac4a55f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 10 Jun 2009 19:30:28 +0200 Subject: Discovered another issue with Python and imports The shard library got renamed to dmidecodemodule.so, and this was not clever. When you do 'import dmidecode' in Python, it will look for files in this order: dmidecode dmidecode.so dmidecodemodule.so dmidecode.py dmidecode.pyc This is of course a problem when the wrapper introduced in commit 65c9384ec9b6e265aba11227ffa37ae7a6a787d1 is called dmidecode.py, and Python attempts to load dmidecodemodule.so before dmidecode.py. To solve this, dmidecodemodule.so is now renamed to dmidecodemod.so. --- unit-tests/unit | 1 + 1 file changed, 1 insertion(+) (limited to 'unit-tests') diff --git a/unit-tests/unit b/unit-tests/unit index 8156945..ac3edab 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -80,6 +80,7 @@ sys.stdout.write(LINE) try: sys.stdout.write(" * Importing module...") import libxml2 +# from dmidecodemod import * import dmidecode passed() -- cgit From 070beb3f0bbaa288f8c8e5b723dd29afe137348c Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 10 Jun 2009 21:25:52 +0200 Subject: Removed no longer needed file --- unit-tests/dmidecode.py | 1 - 1 file changed, 1 deletion(-) delete mode 120000 unit-tests/dmidecode.py (limited to 'unit-tests') diff --git a/unit-tests/dmidecode.py b/unit-tests/dmidecode.py deleted file mode 120000 index 4876cd6..0000000 --- a/unit-tests/dmidecode.py +++ /dev/null @@ -1 +0,0 @@ -../dmidecode.py \ No newline at end of file -- cgit