Skip to content

Commit

Permalink
Fixes issue where compile_string would not compile a string that
Browse files Browse the repository at this point in the history
was an include file.  In particular, if the user creates a file that
is just a subset of the schema, this can be written to a disk file and
used to compile those classes, the qualifiers and the dependencies for
those classes (see issue # 1160 for known issue).  However if the same
definition is supplied as a string to compile_string the compile fails
because the compiler simply did not take into account that the input
include file could be a string as well as a file.  There are a couple
minor fixes and one real change when compiling a single pragma include
statement.

Adds 2 tests for MofCompiler to test for these partial schemas and
for what they are expected to compile.

1. test compile of parts of schema from a file.  Used to determine if the
search for missing mof references, etc. works.

2. Tests for compile of MOF string where the mof in the string is mof
set of pragma include statements that represent just a part of the
schema. The test then confirms that these classes and their dependencies
are actually compiled.
  • Loading branch information
KSchopmeyer committed Apr 2, 2018
1 parent 018a565 commit 5fc9b2a
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 9 deletions.
6 changes: 6 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ Incompatible changes
- The "fq" parameter of the filtering functions was renamed to "fs",
for consistency with the query functions.

* Fix issue where mof. compile_str could not compile mof that was
defined through a mof file containing #pragma include statements.
This precluded using a string to define the classes to include in
a mof compile in a string and required that the include be a file.
See issue 1138

Deprecations
^^^^^^^^^^^^

Expand Down
28 changes: 20 additions & 8 deletions pywbem/mof_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,9 @@ def p_compilerDirective(p):
param = p[5]
if directive == 'include':
fname = param
if os.path.dirname(p.parser.file):
fname = os.path.dirname(p.parser.file) + '/' + fname
if p.parser.file:
if os.path.dirname(p.parser.file):
fname = os.path.dirname(p.parser.file) + '/' + fname
p.parser.mofcomp.compile_file(fname, p.parser.handle.default_namespace)
elif directive == 'namespace':
p.parser.handle.default_namespace = param
Expand Down Expand Up @@ -2312,8 +2313,16 @@ def __init__(self, handle, search_paths=None, verbose=False,
not depend on existing CIM elements in the repository.
search_paths (:term:`py:iterable` of :term:`string`):
An iterable of path names of directories where MOF include files
should be looked up.
An iterable of path names of directories where compiler will search
for mof files to complete a compile operation. The compiler
searches these paths (including subdirectories) for
mof in a number of cases including: 1) find a superclass that
is not in repository while compiling a class 2) Finding a
qualifier that is not in the repository (it looks for filenames
'qualifiers' and 'qualifiers_optional', 3) finding a dependent
class reference property and the EmbeddedInstanceQualifier)
Currently this works for superclasses but not for embedded
instance qualifier and reference properties/parameters.
verbose (:class:`py:bool`):
Indicates whether to issue more detailed compiler messages.
Expand Down Expand Up @@ -2430,13 +2439,16 @@ def compile_file(self, filename, ns):
: Any exceptions that are raised by the repository connection class.
"""

if self.parser.verbose:
self.parser.log('Compiling file ' + filename)

f = open(filename, 'r')
mof = f.read()
f.close()
if not os.path.exists(filename):
filename = os.path.basename(filename)
filename = self.find_mof(filename[:-4].lower())
if filename is None:
raise ValueError('No such file: %s' % filename)
with open(filename, "r") as f:
mof = f.read()

return self.compile_string(mof, ns, filename=filename)

Expand Down
103 changes: 102 additions & 1 deletion testsuite/test_mof_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,14 @@ def moflog(msg):
verbose=False,
log_func=moflog)

self.partial_schema_file = None

def tearDown(self):
"""Close the log file."""
"""Close the log file and any partical schema file."""
self.logfile.close()
if self.partial_schema_file:
if os.path.exists(self.partial_schema_file):
os.remove(self.partial_schema_file)


class TestFlavors(MOFTest):
Expand Down Expand Up @@ -1627,5 +1632,101 @@ def test_mof_schema_roundtrip(self):
os.remove(mofout_filename)


class TestPartialSchema(MOFTest):
""" Test the compile of a full DMTF schema and also
the recreation of the mof using tomof and recompile of this new
mof file. Tests have numbers to control ordering.
"""
def define_partial_schema(self):
"""
Build a schema include file that has a subset of the files in
a complete DMTF schema.
"""
schema_mof = """
#pragma locale ("en_US")
#pragma include ("Interop/CIM_RegisteredProfile.mof")
#pragma include ("Interop/CIM_ObjectManager.mof")
#pragma include ("Interop/CIM_ElementConformsToProfile.mof")
#pragma include ("Interop/CIM_ReferencedProfile.mof")
#pragma include ("System/CIM_LocalFileSystem.mof")
"""
return schema_mof

def expected_classes(self):
"""The classes expected to be directly compiled from the schema_mof
above
"""
return('CIM_RegisteredProfile', 'CIM_ObjectManager',
'CIM_ElementConformsToProfile', 'CIM_ReferencedProfile',
'CIM_LocalFileSystem')

def expected_dependent_classes(self):
""" Return tuple of expected dependent classes from the compile"""
return('CIM_ManagedElement', 'CIM_WBEMService', 'CIM_Service',
'CIM_RegisteredSpecification')

def test_build_from_partial_schema(self):
"""
Build the schema qualifier and class objects in the repository.
This requires only that the leaf objects be defined in a mof
include file since the compiler finds the files for qualifiers
and dependent classes.
"""
schema_mof = self.define_partial_schema()

# write the schema to a file in the schema directory
self.partial_schema_file = 'test_partial_schema.mof'
test_schemafile = os.path.join(SCHEMA_MOF_DIR,
self.partial_schema_file)
with open(test_schemafile, "w") as sf:
sf.write(schema_mof)

self.mofcomp.compile_file(test_schemafile, NAME_SPACE)

repo = self.mofcomp.handle
qualrepo = repo.qualifiers[NAME_SPACE]
clsrepo = repo.classes[NAME_SPACE]
# Assert that at least some qualifiers exist
# The compiler automatically add qualifiers to the schema compile
self.assertTrue('Abstract' in qualrepo)
self.assertEqual(len(qualrepo), TOTAL_QUALIFIERS)

# assert compiled classes exist
for cln in self.expected_classes():
self.assertTrue(cln in clsrepo)

# assert superclasses not specifically defined in the schema file
# were included from the compile search algorithm
for cln in self.expected_dependent_classes():
self.assertTrue(cln in clsrepo)

# TODO add specific checks for other places search should occur

def test_build_from_schema_string(self):
"""
Build the schema qualifier and class objects in the repository from
a mof file defined as a string.
"""
schema_mof = self.define_partial_schema()

self.mofcomp.compile_string(schema_mof, NAME_SPACE)

repo = self.mofcomp.handle
qualrepo = repo.qualifiers[NAME_SPACE]
clsrepo = repo.classes[NAME_SPACE]
# assert that at least some qualifiers exist
self.assertTrue('Abstract' in qualrepo)
self.assertEqual(len(qualrepo), TOTAL_QUALIFIERS)

# assert compiled classes exist
for cln in self.expected_classes():
self.assertTrue(cln in clsrepo)

for cln in self.expected_dependent_classes():
self.assertTrue(cln in clsrepo)

# TODO add specific checks for other places search should occur


if __name__ == '__main__':
unittest.main()

0 comments on commit 5fc9b2a

Please sign in to comment.