示例#1
0
def navigateJsonFragment(decoded, URILink):
    traverseLogger = rst.getLogger()
    if '#' in URILink:
        URIfragless, frag = tuple(URILink.rsplit('#', 1))
        fragNavigate = frag.split('/')
        for item in fragNavigate:
            if item == '':
                continue
            if isinstance(decoded, dict):
                decoded = decoded.get(item)
            elif isinstance(decoded, list):
                if not item.isdigit():
                    traverseLogger.error(
                        "This URI ({}) is accessing an array, but this is not an index: {}"
                        .format(URILink, item))
                    return None
                if int(item) >= len(decoded):
                    traverseLogger.error(
                        "This URI ({}) is accessing an array, but the index is too large for an array of size {}: {}"
                        .format(URILink, len(decoded), item))
                    return None
                decoded = decoded[int(item)]
            else:
                traverseLogger.error(
                    "This URI ({}) has resolved to an invalid object that is neither an array or dictionary"
                    .format(URILink))
                return None
    return decoded
def navigateJsonFragment(decoded, URILink):
    traverseLogger = rst.getLogger()
    if '#' in URILink:
        URILink, frag = tuple(URILink.rsplit('#', 1))
        fragNavigate = frag.split('/')
        for item in fragNavigate:
            if item == '':
                continue
            if isinstance(decoded, dict):
                decoded = decoded.get(item)
            elif isinstance(decoded, list):
                if not item.isdigit():
                    traverseLogger.error("This is an Array, but this is not an index, aborting: {} {}".format(URILink, item))
                    return None
                decoded = decoded[int(item)] if int(item) < len(decoded) else None
        if not isinstance(decoded, dict):
            traverseLogger.error(
                "Decoded object no longer a dictionary {}".format(URILink))
            return None
    return decoded
示例#3
0
def renderHtml(results, tool_version, startTick, nowTick, service, printCSV):
    # Render html
    config = service.config
    config_str = ', '.join(sorted(list(config.keys() - set(['systeminfo', 'targetip', 'password', 'description']))))
    sysDescription, ConfigURI = (config['systeminfo'], config['targetip'])
    rsvLogger = rst.getLogger()
    logpath = config['logpath']
    error_lines, finalCounts = count_errors(results)
    if service.metadata is not None:
        finalCounts.update(service.metadata.get_counter())

    # wrap html
    htmlPage = ''
    htmlStrTop = '<head><title>Conformance Test Summary</title>\
            <style>\
            .pass {background-color:#99EE99}\
            .column {\
                float: left;\
                width: 45%;\
            }\
            .fail {background-color:#EE9999}\
            .warn {background-color:#EEEE99}\
            .bluebg {background-color:#BDD6EE}\
            .button {padding: 12px; display: inline-block}\
            .center {text-align:center;}\
            .log {text-align:left; white-space:pre-wrap; word-wrap:break-word; font-size:smaller; padding: 6px}\
            .title {background-color:#DDDDDD; border: 1pt solid; font-height: 30px; padding: 8px}\
            .titlesub {padding: 8px}\
            .titlerow {border: 2pt solid}\
            .results {transition: visibility 0s, opacity 0.5s linear; display: none; opacity: 0}\
            .resultsShow {display: block; opacity: 1}\
            body {background-color:lightgrey; border: 1pt solid; text-align:center; margin-left:auto; margin-right:auto}\
            th {text-align:center; background-color:beige; border: 1pt solid}\
            td {text-align:left; background-color:white; border: 1pt solid; word-wrap:break-word; overflow:hidden;}\
            table {width:90%; margin: 0px auto; table-layout:fixed;}\
            .titletable {width:100%}\
            </style>\
            </head>'
    htmlStrBodyHeader = ''
    # Logo and logname
    infos = [wrapTag('##### Redfish Conformance Test Report #####', 'h2')]
    infos.append(wrapTag('<img align="center" alt="DMTF Redfish Logo" height="203" width="288"'
                         'src="data:image/gif;base64,' + logo.logo + '">', 'h4'))
    infos.append('<h4><a href="https://github.com/DMTF/Redfish-Service-Validator">'
                 'https://github.com/DMTF/Redfish-Service-Validator</a></h4>')
    infos.append('Tool Version: {}'.format(tool_version))
    infos.append(startTick.strftime('%c'))
    infos.append('(Run time: {})'.format(
        str(nowTick - startTick).rsplit('.', 1)[0]))
    infos.append('<h4>This tool is provided and maintained by the DMTF. '
                 'For feedback, please open issues<br>in the tool\'s Github repository: '
                 '<a href="https://github.com/DMTF/Redfish-Service-Validator/issues">'
                 'https://github.com/DMTF/Redfish-Service-Validator/issues</a></h4>')

    htmlStrBodyHeader += tag.tr(tag.th(infoBlock(infos)))

    infos = {x: config[x] for x in config if x not in ['systeminfo', 'targetip', 'password', 'description']}
    infos_left, infos_right = dict(), dict()
    for key in sorted(infos.keys()):
        if len(infos_left) <= len(infos_right):
            infos_left[key] = infos[key]
        else:
            infos_right[key] = infos[key]

    block = tag.td(tag.div(infoBlock(infos_left), 'class=\'column log\'') \
            + tag.div(infoBlock(infos_right), 'class=\'column log\''), 'id=\'resNumConfig\' class=\'results resultsShow\'')

    htmlButtons = '<div class="button warn" onClick="arr = document.getElementsByClassName(\'results\'); for (var i = 0; i < arr.length; i++){arr[i].classList.add(\'resultsShow\')};">Expand All</div>'
    htmlButtons += '<div class="button fail" onClick="arr = document.getElementsByClassName(\'results\'); for (var i = 0; i < arr.length; i++){arr[i].classList.remove(\'resultsShow\')};">Collapse All</div>'
    htmlButtons += tag.div('Toggle Config', attr='class="button pass" onClick="document.getElementById(\'resNumConfig\').classList.toggle(\'resultsShow\');"')

    htmlStrBodyHeader += tag.tr(tag.th(htmlButtons))
    htmlStrBodyHeader += tag.tr(tag.th('Test Summary'))

    infos = {'System': ConfigURI, 'Description': sysDescription}
    htmlStrBodyHeader += tag.tr(tag.th(infoBlock(infos)))

    errors = error_lines
    if len(errors) == 0:
        errors = ['No errors located.']
    errorTags = tag.td(infoBlock(errors), 'class="log"')

    infos_left, infos_right = dict(), dict()
    for key in sorted(finalCounts.keys()):
        if finalCounts.get(key) == 0:
            continue
        if len(infos_left) <= len(infos_right):
            infos_left[key] = finalCounts[key]
        else:
            infos_right[key] = finalCounts[key]

    htmlStrCounts = (tag.div(infoBlock(infos_left), 'class=\'column log\'') + tag.div(infoBlock(infos_right), 'class=\'column log\''))

    htmlStrBodyHeader += tag.tr(tag.td(htmlStrCounts))

    htmlStrBodyHeader += tag.tr(errorTags)

    htmlStrBodyHeader += tag.tr(block)


    if service.metadata is not None:
        htmlPage = service.metadata.to_html()
    for cnt, item in enumerate(results):
        entry = []
        val = results[item]
        rtime = '(response time: {})'.format(val['rtime'])
        rcode = '({})'.format(val['rcode'])
        payload = val.get('payload', {})

        # uri block
        prop_type = val['fulltype']
        if prop_type is not None:
            namespace = getNamespace(prop_type)
            type_name = getType(prop_type)

        infos = [str(val.get(x)) for x in ['uri', 'samplemapped'] if val.get(x) not in ['',None]]
        infos.append(rtime)
        infos.append(type_name)
        uriTag = tag.tr(tag.th(infoBlock(infos, '&ensp;'), 'class="titlerow bluebg"'))
        entry.append(uriTag)

        # info block
        infos = [str(val.get(x)) for x in ['uri'] if val.get(x) not in ['',None]]
        infos.append(rtime)
        infos.append(tag.div('Show Results', attr='class="button warn"\
                onClick="document.getElementById(\'payload{}\').classList.remove(\'resultsShow\');\
                document.getElementById(\'resNum{}\').classList.toggle(\'resultsShow\');"'.format(cnt, cnt)))
        infos.append(tag.div('Show Payload', attr='class="button pass"\
                onClick="document.getElementById(\'payload{}\').classList.toggle(\'resultsShow\');\
                document.getElementById(\'resNum{}\').classList.add(\'resultsShow\');"'.format(cnt, cnt)))
        buttonTag = tag.td(infoBlock(infos), 'class="title" style="width:30%"')

        infos = [str(val.get(x)) for x in ['context', 'origin', 'fulltype']]
        infos = {y: x for x, y in zip(infos, ['Context', 'File Origin', 'Resource Type'])}
        infosTag = tag.td(infoBlock(infos), 'class="titlesub log" style="width:40%"')

        success = val['success']
        if success:
            getTag = tag.td('GET Success HTTP Code {}'.format(rcode), 'class="pass"')
        else:
            getTag = tag.td('GET Failure HTTP Code {}'.format(rcode), 'class="fail"')

        countsTag = tag.td(infoBlock(val['counts'], split='', ffunc=applyInfoSuccessColor), 'class="log"')

        rhead = ''.join([buttonTag, infosTag, getTag, countsTag])
        for x in [('tr',), ('table', 'class=titletable'), ('td', 'class=titlerow'), ('tr')]:
            rhead = wrapTag(''.join(rhead), *x)
        entry.append(rhead)

        # actual table
        rows = [[str(m)] + list([str(x) for x in val['messages'][m]]) for m in val['messages']]
        titles = ['Property Name', 'Value', 'Type', 'Exists', 'Result']
        widths = ['15', '30', '30', '10', '15']
        tableHeader = tableBlock(rows, titles, widths, ffunc=applySuccessColor)

        #    lets wrap table and errors and warns into one single column table
        tableHeader = tag.tr(tag.td((tableHeader)))

        infos_a = [str(val.get(x)) for x in ['uri'] if val.get(x) not in ['',None]]
        infos_a.append(rtime)

        if(printCSV):
            rsvLogger.info(','.join(infos_a))
            rsvLogger.info(','.join(infos))
            rsvLogger.info(','.join(titles))
            rsvLogger.info('\n'.join([','.join(x) for x in rows]))
            rsvLogger.info(',')

        # warns and errors
        errors = val['errors']
        if len(errors) == 0:
            errors = 'No errors'
        infos = errors.split('\n')
        errorTags = tag.tr(tag.td(infoBlock(infos), 'class="fail log"'))

        warns = val['warns']
        if len(warns) == 0:
            warns = 'No warns'
        infos = warns.split('\n')
        warnTags = tag.tr(tag.td(infoBlock(infos), 'class="warn log"'))

        payloadTag = tag.td(json.dumps(payload, indent=4, sort_keys=True), 'id=\'payload{}\' class=\'results log\''.format(cnt))

        tableHeader += errorTags
        tableHeader += warnTags
        tableHeader += payloadTag
        tableHeader = tag.table(tableHeader)
        tableHeader = tag.td(tableHeader, 'class="results" id=\'resNum{}\''.format(cnt))

        entry.append(tableHeader)



        # append
        htmlPage += ''.join([tag.tr(x) for x in entry])

    return wrapTag(wrapTag(htmlStrTop + wrapTag(htmlStrBodyHeader + htmlPage, 'table'), 'body'), 'html')
示例#4
0
# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/Redfish-Service-Validator/blob/master/LICENSE.md
#
# Unit tests for RedfishServiceValidator.py
#

from unittest import TestCase
from unittest import mock
import datetime

import sys
sys.path.append('../')

import simpletypes as st
import traverseService as rst

rsvLogger = rst.getLogger()
rsvLogger.disabled = True


class ValidatorTest(TestCase):

    """
    Tests for functions setup_operation() and run_systems_operation()
    """

    def test_no_test(self):
        self.assertTrue(True, 'Huh?')

    def test_validate_number(self):
        empty = (None, None)
        numbers = [0, 10000, 20, 20, 23e-1, 23.0, 14.0, 999.0]
示例#5
0
def renderHtml(results, finalCounts, tool_version, startTick, nowTick,
               printCSV):
    # Render html
    config = rst.config
    config_str = ', '.join(
        sorted(
            list(config.keys() -
                 set(['systeminfo', 'targetip', 'password', 'description']))))
    rsvLogger = rst.getLogger()
    sysDescription, ConfigURI = (config['systeminfo'], config['targetip'])
    logpath = config['logpath']

    # wrap html
    htmlPage = ''
    htmlStrTop = '<head><title>Conformance Test Summary</title>\
            <style>\
            .pass {background-color:#99EE99}\
            .fail {background-color:#EE9999}\
            .warn {background-color:#EEEE99}\
            .bluebg {background-color:#BDD6EE}\
            .button {padding: 12px; display: inline-block}\
            .center {text-align:center;}\
            .log {text-align:left; white-space:pre-wrap; word-wrap:break-word; font-size:smaller}\
            .title {background-color:#DDDDDD; border: 1pt solid; font-height: 30px; padding: 8px}\
            .titlesub {padding: 8px}\
            .titlerow {border: 2pt solid}\
            .results {transition: visibility 0s, opacity 0.5s linear; display: none; opacity: 0}\
            .resultsShow {display: block; opacity: 1}\
            body {background-color:lightgrey; border: 1pt solid; text-align:center; margin-left:auto; margin-right:auto}\
            th {text-align:center; background-color:beige; border: 1pt solid}\
            td {text-align:left; background-color:white; border: 1pt solid; word-wrap:break-word;}\
            table {width:90%; margin: 0px auto; table-layout:fixed;}\
            .titletable {width:100%}\
            </style>\
            </head>'

    htmlStrBodyHeader = ''
    # Logo and logname
    infos = [wrapTag('##### Redfish Conformance Test Report #####', 'h2')]
    infos.append(
        wrapTag(
            '<img align="center" alt="DMTF Redfish Logo" height="203" width="288"'
            'src="data:image/gif;base64,' + logo.logo + '">', 'h4'))
    infos.append(
        '<h4><a href="https://github.com/DMTF/Redfish-Interop-Validator">'
        'https://github.com/DMTF/Redfish-Interop-Validator</a></h4>')
    infos.append('Tool Version: {}'.format(tool_version))
    infos.append(startTick.strftime('%c'))
    infos.append('(Run time: {})'.format(
        str(nowTick - startTick).rsplit('.', 1)[0]))
    infos.append(
        '<h4>This tool is provided and maintained by the DMTF. '
        'For feedback, please open issues<br>in the tool\'s Github repository: '
        '<a href="https://github.com/DMTF/Redfish-Interop-Validator/issues">'
        'https://github.com/DMTF/Redfish-Interop-Validator/issues</a></h4>')

    htmlStrBodyHeader += tr(th(infoBlock(infos)))

    infos = {'System': ConfigURI, 'Description': sysDescription}
    htmlStrBodyHeader += tr(th(infoBlock(infos)))

    infos = {'Profile': config['profile'], 'Schema': config['schema']}
    htmlStrBodyHeader += tr(th(infoBlock(infos)))

    infos = {
        x: config[x]
        for x in config if x not in [
            'systeminfo', 'targetip', 'password', 'description', 'profile',
            'schema'
        ]
    }
    block = tr(th(infoBlock(infos, '|||')))
    for num, block in enumerate(block.split('|||'), 1):
        sep = '<br/>' if num % 4 == 0 else ',&ensp;'
        sep = '' if num == len(infos) else sep
        htmlStrBodyHeader += block + sep

    htmlStrTotal = '<div>Final counts: '
    for countType in sorted(finalCounts.keys()):
        if finalCounts.get(countType) == 0:
            continue
        htmlStrTotal += '{p}: {q},   '.format(p=countType,
                                              q=finalCounts.get(countType, 0))
    htmlStrTotal += '</div><div class="button warn" onClick="arr = document.getElementsByClassName(\'results\'); for (var i = 0; i < arr.length; i++){arr[i].className = \'results resultsShow\'};">Expand All</div>'
    htmlStrTotal += '</div><div class="button fail" onClick="arr = document.getElementsByClassName(\'results\'); for (var i = 0; i < arr.length; i++){arr[i].className = \'results\'};">Collapse All</div>'

    htmlStrBodyHeader += tr(td(htmlStrTotal))

    htmlPage = rst.currentService.metadata.to_html()
    for cnt, item in enumerate(results):
        entry = []
        val = results[item]
        rtime = '(response time: {})'.format(val['rtime'])

        if len(val['messages']) == 0 and len(val['errors']) == 0:
            continue

        # uri block
        prop_type = val['fulltype']
        if prop_type is not None:
            namespace = getNamespace(prop_type)
            type_name = getType(prop_type)

        infos_a = [
            str(val.get(x)) for x in ['uri', 'samplemapped']
            if val.get(x) not in ['', None]
        ]
        infos_a.append(rtime)
        infos_a.append(type_name)
        uriTag = tr(th(infoBlock(infos_a, '&ensp;'),
                       'class="titlerow bluebg"'))
        entry.append(uriTag)

        # info block
        infos_b = [
            str(val.get(x)) for x in ['uri'] if val.get(x) not in ['', None]
        ]
        infos_b.append(rtime)
        infos_b.append(
            div('Show Results',
                attr=
                'class="button warn" onClick="document.getElementById(\'resNum{}\').classList.toggle(\'resultsShow\');"'
                .format(cnt)))
        buttonTag = td(infoBlock(infos_b), 'class="title" style="width:30%"')

        infos_content = [
            str(val.get(x)) for x in ['context', 'origin', 'fulltype']
        ]
        infos_c = {
            y: x
            for x, y in zip(infos_content,
                            ['Context', 'File Origin', 'Resource Type'])
        }
        infosTag = td(infoBlock(infos_c),
                      'class="titlesub log" style="width:40%"')

        success = val['success']
        if success:
            getTag = td('GET Success', 'class="pass"')
        else:
            getTag = td('GET Failure', 'class="fail"')

        countsTag = td(
            infoBlock(val['counts'], split='', ffunc=applyInfoSuccessColor),
            'class="log"')

        rhead = ''.join([buttonTag, infosTag, getTag, countsTag])
        for x in [('tr', ), ('table', 'class=titletable'),
                  ('td', 'class=titlerow'), ('tr')]:
            rhead = wrapTag(''.join(rhead), *x)
        entry.append(rhead)

        # actual table
        rows = [(str(i.name), str(i.entry), str(i.expected), str(i.actual),
                 str(i.success.value)) for i in val['messages']]
        titles = ['Property Name', 'Value', 'Expected', 'Actual', 'Result']
        widths = ['15', '30', '30', '10', '15']
        tableHeader = tableBlock(rows, titles, widths, ffunc=applySuccessColor)

        #    lets wrap table and errors and warns into one single column table
        tableHeader = tr(td((tableHeader)))

        if (printCSV):
            rsvLogger.info(','.join(infos_a))
            rsvLogger.info(','.join(infos_content))
            rsvLogger.info(','.join(titles))
            rsvLogger.info('\n'.join([','.join(x) for x in rows]))
            rsvLogger.info(',')

        # warns and errors
        errors = val['errors']
        if len(errors) == 0:
            errors = 'No errors'
        infos = errors.split('\n')
        errorTags = tr(td(infoBlock(infos), 'class="fail log"'))

        warns = val['warns']
        if len(warns) == 0:
            warns = 'No warns'
        infos = warns.split('\n')
        warnTags = tr(td(infoBlock(infos), 'class="warn log"'))

        tableHeader += errorTags
        tableHeader += warnTags
        tableHeader = table(tableHeader)
        tableHeader = td(tableHeader,
                         'class="results" id=\'resNum{}\''.format(cnt))

        entry.append(tableHeader)

        # append
        htmlPage += ''.join([tr(x) for x in entry])

    return wrapTag(
        wrapTag(htmlStrTop + wrapTag(htmlStrBodyHeader + htmlPage, 'table'),
                'body'), 'html')
示例#6
0
def validateURITree(URI,
                    uriName,
                    profile,
                    expectedType=None,
                    expectedSchema=None,
                    expectedJson=None):
    """
    Validates a Tree of URIs, traversing from the first given
    """
    traverseLogger = rst.getLogger()

    allLinks = set()
    allLinks.add(URI)
    refLinks = list()

    # Resource level validation
    rcounts = Counter()
    rerror = StringIO()
    rmessages = []
    r_exists = {}

    resource_info = dict(profile.get('Resources'))

    # Validate top URI
    validateSuccess, counts, results, links, thisobj = \
        validateSingleURI(URI, profile, uriName, expectedType,
                          expectedSchema, expectedJson)

    # parent first, then child execution
    # do top level root first, then do each child root, then their children...
    # hold refs for last (less recursion)
    if validateSuccess:
        serviceVersion = profile.get("Protocol")
        if serviceVersion is not None:
            serviceVersion = serviceVersion.get('MinVersion', '1.0.0')
            msg, m_success = commonInterop.validateMinVersion(
                thisobj.jsondata.get("RedfishVersion", "0"), serviceVersion)
            rmessages.append(msg)

        currentLinks = [(l, links[l], thisobj) for l in links]
        # todo : churning a lot of links, causing possible slowdown even with set checks
        while len(currentLinks) > 0:
            newLinks = list()
            for linkName, link, parent in currentLinks:
                linkURI, autoExpand, linkType, linkSchema, innerJson = link

                if linkURI is None:
                    continue

                if linkURI.rstrip(
                        '/') in allLinks or linkType == 'Resource.Item':
                    continue

                if refLinks is not currentLinks and (
                        'Links' in linkName.split('.')
                        or 'RelatedItem' in linkName.split('.')
                        or 'Redundancy' in linkName.split('.')):
                    refLinks.append((linkName, link, parent))
                    continue

                if autoExpand and linkType is not None:
                    linkSuccess, linkCounts, linkResults, innerLinks, linkobj = \
                        validateSingleURI(linkURI, profile, linkURI, linkType, linkSchema, innerJson, parent=parent)
                else:
                    linkSuccess, linkCounts, linkResults, innerLinks, linkobj = \
                        validateSingleURI(linkURI, profile, linkURI, linkType, linkSchema, parent=parent)

                allLinks.add(linkURI.rstrip('/'))

                if not linkSuccess:
                    continue

                innerLinksTuple = [(l, innerLinks[l], linkobj)
                                   for l in innerLinks]
                newLinks.extend(innerLinksTuple)
                results.update(linkResults)
                SchemaType = rst.getType(linkobj.typeobj.fulltype)

                r_exists[SchemaType] = True

            if refLinks is not currentLinks and len(
                    newLinks) == 0 and len(refLinks) > 0:
                currentLinks = refLinks
            else:
                currentLinks = newLinks

    # interop service level checks
    finalResults = OrderedDict()
    traverseLogger.info('Service Level Checks')
    if URI not in ["/redfish/v1", "/redfish/v1/"]:
        resultEnum = commonInterop.sEnum.WARN
        traverseLogger.info("We are not validating root, warn only")
    else:
        resultEnum = commonInterop.sEnum.FAIL

    for item in resource_info:
        # thisobj does not exist if we didn't find the first resource
        if thisobj and item == rst.getType(thisobj.typeobj.fulltype):
            continue

        exists = r_exists.get(item, False)

        if "ConditionalRequirements" in resource_info[item]:
            innerList = resource_info[item]["ConditionalRequirements"]
            for condreq in innerList:
                if commonInterop.checkConditionalRequirementResourceLevel(
                        r_exists, condreq, item):
                    traverseLogger.info(
                        'Service Conditional for {} applies'.format(item))
                    req = condreq.get("ReadRequirement", "Mandatory")
                    rmessages.append(
                        commonInterop.msgInterop(
                            item + '.Conditional.ReadRequirement', req,
                            'Must Exist' if req == "Mandatory" else 'Any',
                            'DNE' if not exists else 'Exists',
                            resultEnum if not exists and req == "Mandatory"
                            else commonInterop.sEnum.PASS))
                else:
                    traverseLogger.info(
                        'Service Conditional for {} does not apply'.format(
                            item))

        req = resource_info[item].get("ReadRequirement", "Mandatory")

        if not exists:
            rmessages.append(
                commonInterop.msgInterop(
                    item + '.ReadRequirement', req,
                    'Must Exist' if req == "Mandatory" else 'Any', 'DNE',
                    resultEnum
                    if req == "Mandatory" else commonInterop.sEnum.PASS))
        else:
            rmessages.append(
                commonInterop.msgInterop(
                    item + '.ReadRequirement', req,
                    'Must Exist' if req == "Mandatory" else 'Any', 'Exists',
                    commonInterop.sEnum.PASS))

    for item in rmessages:
        if item.success == commonInterop.sEnum.WARN:
            rcounts['warn'] += 1
        elif item.success == commonInterop.sEnum.PASS:
            rcounts['pass'] += 1
        elif item.success == commonInterop.sEnum.FAIL:
            rcounts['fail.{}'.format(item.name)] += 1

    finalResults['n/a'] = {
        'uri': "Service Level Requirements",
        'success': rcounts.get('fail', 0) == 0,
        'counts': rcounts,
        'messages': rmessages,
        'errors': rerror.getvalue(),
        'warns': '',
        'rtime': '',
        'context': '',
        'fulltype': ''
    }
    finalResults.update(results)
    rerror.close()

    return validateSuccess, counts, finalResults, refLinks, thisobj
示例#7
0
def validateURITree(URI,
                    uriName,
                    expectedType=None,
                    expectedSchema=None,
                    expectedJson=None,
                    parent=None,
                    allLinks=None):
    # from given URI, validate it, then follow its links like nodes
    #   Other than expecting a valid URI, on success (real URI) expects valid links
    #   valid links come from getAllLinks, includes info such as expected values, etc
    #   as long as it is able to pass that info, should not crash
    # info: destinations, individual expectations of each?
    # error: on fail
    # warn: reference only?
    # debug:
    traverseLogger = rst.getLogger()

    # If this is our first called URI
    top = allLinks is None
    if top:
        allLinks = set()
    allLinks.add(URI)

    def executeLink(linkItem, parent=None):
        linkURI, autoExpand, linkType, linkSchema, innerJson, original_name = linkItem

        if linkType is not None and autoExpand:
            returnVal = validateURITree(linkURI, uriName + ' -> ' + linkName,
                                        linkType, linkSchema, innerJson,
                                        parent, allLinks)
        else:
            returnVal = validateURITree(linkURI,
                                        uriName + ' -> ' + linkName,
                                        parent=parent,
                                        allLinks=allLinks)
        traverseLogger.verboseout('%s, %s', linkName, returnVal[1])
        return returnVal

    refLinks = OrderedDict()

    validateSuccess, counts, results, links, thisobj = validateSingleURI(
        URI, uriName, expectedType, expectedSchema, expectedJson, parent)
    if validateSuccess:
        for linkName in links:
            if any(
                    x in links[linkName].origin_property for x in
                ['RelatedItem', 'Redundancy', 'Links', 'OriginOfCondition']):
                refLinks[linkName] = (links[linkName], thisobj)
                continue
            if links[linkName].uri in allLinks:
                counts['repeat'] += 1
                continue
            elif links[linkName].uri is None:
                errmsg = 'URI for NavigationProperty is missing {} {}'.format(
                    uriName, links[linkName].linktype)
                traverseLogger.error(errmsg)
                results[uriName]['errors'] += '\n' + errmsg
                counts['errorMissingOdata'] += 1
                continue
            elif links[linkName].uri.split('#')[0].endswith('/'):
                # (elegantly) add warn message to resource html
                warnmsg = 'URI acquired ends in slash: {}'.format(
                    links[linkName].uri)
                traverseLogger.warning(warnmsg)
                results[uriName]['warns'] += '\n' + warnmsg
                counts['warnTrailingSlashLink'] += 1
                newLink = ''.join(links[linkName].uri.split('/')[:-1])
                if newLink in allLinks:
                    counts['repeat'] += 1
                    continue

            success, linkCounts, linkResults, xlinks, xobj = executeLink(
                links[linkName], thisobj)
            refLinks.update(xlinks)
            if not success:
                counts['unvalidated'] += 1
            results.update(linkResults)

    if top:
        for linkName in refLinks:
            ref_link, refparent = refLinks[linkName]
            if ref_link.uri is None:
                errmsg = 'URI for ReferenceLink is missing {} {}'.format(
                    uriName, ref_link.linktype)
                traverseLogger.error(errmsg)
                results[uriName]['errors'] += '\n' + errmsg
                counts['errorMissingReferenceOdata'] += 1
                continue
            elif ref_link.uri.split('#')[0].endswith('/'):
                # (elegantly) add warn message to resource html
                warnmsg = 'Referenced URI acquired ends in slash: {}'.format(
                    ref_link.uri)
                traverseLogger.warning(warnmsg)
                results[uriName]['warns'] += '\n' + warnmsg
                counts['warnTrailingSlashRefLink'] += 1
                new_ref_link = ''.join(ref_link.uri.split('/')[:-1])
                if new_ref_link in allLinks:
                    counts['repeat'] += 1
                    continue

            if ref_link.uri not in allLinks:
                traverseLogger.verboseout('{}, {}'.format(linkName, ref_link))
                counts['reflink'] += 1
            else:
                continue

            success, linkCounts, linkResults, xlinks, xobj = executeLink(
                ref_link, refparent)
            if not success:
                counts['unvalidatedRef'] += 1
                if 'OriginOfCondition' in ref_link.origin_property:
                    traverseLogger.info(
                        'Link was unsuccessful, but non mandatory')
                    pass
                else:
                    results.update(linkResults)
            else:
                results.update(linkResults)

    return validateSuccess, counts, results, refLinks, thisobj
示例#8
0
def validateURITree(URI,
                    uriName,
                    profile,
                    expectedType=None,
                    expectedSchema=None,
                    expectedJson=None):
    """
    Validates a Tree of URIs, traversing from the first given
    """
    traverseLogger = rst.getLogger()

    allLinks = set()
    allLinks.add(URI)
    refLinks = list()

    # Resource level validation
    rcounts = Counter()
    rmessages = []
    rerror = StringIO()

    objRes = dict(profile.get('Resources'))

    # Validate top URI
    validateSuccess, counts, results, links, thisobj = \
        validateSingleURI(URI, profile, uriName, expectedType,
                          expectedSchema, expectedJson)

    # parent first, then child execution
    # do top level root first, then do each child root, then their children...
    # hold refs for last (less recursion)
    if validateSuccess:
        serviceVersion = profile.get("Protocol")
        if serviceVersion is not None:
            serviceVersion = serviceVersion.get('MinVersion', '1.0.0')
            msg, mpss = commonInterop.validateMinVersion(
                thisobj.jsondata.get("RedfishVersion", "0"), serviceVersion)
            rmessages.append(msg)

        currentLinks = [(l, links[l], thisobj) for l in links]
        # todo : churning a lot of links, causing possible slowdown even with set checks
        while len(currentLinks) > 0:
            newLinks = list()
            for linkName, link, parent in currentLinks:
                linkURI, autoExpand, linkType, linkSchema, innerJson = link

                if linkURI in allLinks or linkType == 'Resource.Item':
                    continue

                if refLinks is not currentLinks and (
                        'Links' in linkName.split('.')
                        or 'RelatedItem' in linkName.split('.')
                        or 'Redundancy' in linkName.split('.')):
                    refLinks.append((linkName, link, parent))
                    continue

                if autoExpand and linkType is not None:
                    linkSuccess, linkCounts, linkResults, innerLinks, linkobj = \
                        validateSingleURI(linkURI, profile, linkURI, linkType, linkSchema, innerJson, parent=parent)
                else:
                    linkSuccess, linkCounts, linkResults, innerLinks, linkobj = \
                        validateSingleURI(linkURI, profile, linkURI, linkType, linkSchema, parent=parent)

                allLinks.add(linkURI)

                if not linkSuccess:
                    continue

                innerLinksTuple = [(l, innerLinks[l], linkobj)
                                   for l in innerLinks]
                newLinks.extend(innerLinksTuple)
                results.update(linkResults)
                SchemaType = rst.getType(linkobj.typeobj.fulltype)

                # Check schema level for requirements
                if SchemaType in objRes:
                    traverseLogger.info(
                        "Checking service requirement for {}".format(
                            SchemaType))
                    req = objRes[SchemaType].get("ReadRequirement",
                                                 "Mandatory")
                    msg, pss = commonInterop.validateRequirement(req, None)
                    if pss and not objRes[SchemaType].get('mark', False):
                        rmessages.append(msg)
                        msg.name = SchemaType + '.' + msg.name
                        objRes[SchemaType]['mark'] = True

                    if "ConditionalRequirements" in objRes[SchemaType]:
                        innerList = objRes[SchemaType][
                            "ConditionalRequirements"]
                        newList = list()
                        for condreq in innerList:
                            condtrue = commonInterop.checkConditionalRequirement(
                                linkobj, condreq, (linkobj.jsondata, None),
                                None)
                            if condtrue:
                                msg, cpss = commonInterop.validateRequirement(
                                    condreq.get("ReadRequirement",
                                                "Mandatory"), None)
                                if cpss:
                                    rmessages.append(msg)
                                    msg.name = SchemaType + '.Conditional.' + msg.name
                                else:
                                    newList.append(condreq)
                            else:
                                newList.append(condreq)
                        objRes[SchemaType]["ConditionalRequirements"] = newList

            if refLinks is not currentLinks and len(
                    newLinks) == 0 and len(refLinks) > 0:
                currentLinks = refLinks
            else:
                currentLinks = newLinks

    # interop service level checks
    finalResults = OrderedDict()
    if URI != "/redfish/v1":
        resultEnum = commonInterop.sEnum.WARN
        traverseLogger.info("We are not validating root, warn only")
    else:
        resultEnum = commonInterop.sEnum.FAIL
    for left in objRes:
        if not objRes[left].get('mark', False):
            req = objRes[left].get("ReadRequirement", "Mandatory")
            rmessages.append(
                commonInterop.msgInterop(
                    left + '.ReadRequirement', req,
                    'Must Exist' if req == "Mandatory" else 'Any', 'DNE',
                    resultEnum))
        if "ConditionalRequirements" in objRes[left]:
            innerList = objRes[left]["ConditionalRequirements"]
            for condreq in innerList:
                req = condreq.get("ReadRequirement", "Mandatory")
                rmessages.append(
                    commonInterop.msgInterop(
                        left + '.Conditional.ReadRequirement', req,
                        'Must Exist' if req == "Mandatory" else 'Any', 'DNE',
                        resultEnum))

    for item in rmessages:
        if item.success == commonInterop.sEnum.WARN:
            rcounts['warn'] += 1
        elif item.success == commonInterop.sEnum.PASS:
            rcounts['pass'] += 1
        elif item.success == commonInterop.sEnum.FAIL:
            rcounts['fail.{}'.format(item.name)] += 1

    finalResults['n/a'] = {'uri': "Service Level Requirements", 'success':rcounts.get('fail', 0) == 0,\
            'counts':rcounts,\
            'messages':rmessages, 'errors':rerror.getvalue(), 'warns': '',\
            'rtime':'', 'context':'', 'fulltype':''}
    print(len(allLinks))
    finalResults.update(results)
    rerror.close()

    return validateSuccess, counts, finalResults, refLinks, thisobj