From d5e341bc22977beac2cc2c9d4b9368245cefda3a Mon Sep 17 00:00:00 2001 From: Yuli Shlosberg Date: Tue, 28 Nov 2017 15:55:44 +0200 Subject: [PATCH] add tests Change-Id: Ifa5f6891a06d6bf5ae82d0dd73ee01aa60967afe Issue-ID: SDC-695 Signed-off-by: Yuli Shlosberg --- pom.xml | 15 +- .../sdc/toscaparser/api/CapabilityAssignment.java | 8 +- .../sdc/toscaparser/api/DataEntity.java.orig | 453 ----------- .../sdc/toscaparser/api/EntityTemplate.java | 2 +- .../sdc/toscaparser/api/TopologyTemplate.java.orig | 859 --------------------- .../sdc/toscaparser/api/ToscaTemplate.java | 5 +- .../sdc/toscaparser/api/elements/NodeType.java | 15 +- .../toscaparser/api/elements/TypeValidation.java | 1 + .../sdc/toscaparser/api}/JToscaMetadataParse.java | 19 +- .../csars/tmpCSAR_Huawei_vSPGW_fixed.csar.csar | Bin 0 -> 44576 bytes version.properties | 2 +- 11 files changed, 51 insertions(+), 1328 deletions(-) delete mode 100644 src/main/java/org/openecomp/sdc/toscaparser/api/DataEntity.java.orig delete mode 100644 src/main/java/org/openecomp/sdc/toscaparser/api/TopologyTemplate.java.orig rename src/test/java/{org.openecomp.sdc.toscaparser => org/openecomp/sdc/toscaparser/api}/JToscaMetadataParse.java (55%) create mode 100644 src/test/resources/csars/tmpCSAR_Huawei_vSPGW_fixed.csar.csar diff --git a/pom.xml b/pom.xml index b7172c6..c277b0c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.openecomp.sdc.jtosca jtosca - 1.1.16-SNAPSHOT + 1.1.19-SNAPSHOT sdc-jtosca @@ -160,7 +160,18 @@ maven-javadoc-plugin 2.10.3 - + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + */* + + + org.sonarsource.scanner.maven sonar-maven-plugin diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/CapabilityAssignment.java b/src/main/java/org/openecomp/sdc/toscaparser/api/CapabilityAssignment.java index 0eaa099..f3bc2bd 100644 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/CapabilityAssignment.java +++ b/src/main/java/org/openecomp/sdc/toscaparser/api/CapabilityAssignment.java @@ -12,13 +12,15 @@ public class CapabilityAssignment { private String name; private LinkedHashMap _properties; private CapabilityTypeDef _definition; + private LinkedHashMap _customDef; public CapabilityAssignment(String cname, - LinkedHashMap cproperties, - CapabilityTypeDef cdefinition) { + LinkedHashMap cproperties, + CapabilityTypeDef cdefinition, LinkedHashMap customDef) { name = cname; _properties = cproperties; _definition = cdefinition; + _customDef = customDef; } /** @@ -38,7 +40,7 @@ public class CapabilityAssignment { if(propsDef != null) { PropertyDef pd = (PropertyDef)propsDef.get(pname); if(pd != null) { - properties.add(new Property(pname,pvalue,pd.getSchema(),null)); + properties.add(new Property(pname,pvalue,pd.getSchema(), _customDef)); } } } diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/DataEntity.java.orig b/src/main/java/org/openecomp/sdc/toscaparser/api/DataEntity.java.orig deleted file mode 100644 index 2c6d923..0000000 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/DataEntity.java.orig +++ /dev/null @@ -1,453 +0,0 @@ -package org.openecomp.sdc.toscaparser.api; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; - -import org.openecomp.sdc.toscaparser.api.common.ValidationIssueCollector; -import org.openecomp.sdc.toscaparser.api.elements.*; -import org.openecomp.sdc.toscaparser.api.elements.constraints.Constraint; -import org.openecomp.sdc.toscaparser.api.elements.constraints.Schema; -import org.openecomp.sdc.toscaparser.api.functions.Function; -import org.openecomp.sdc.toscaparser.api.utils.TOSCAVersionProperty; -import org.openecomp.sdc.toscaparser.api.utils.ValidateUtils; - -public class DataEntity { - // A complex data value entity - - private LinkedHashMap customDef; - private DataType dataType; - private LinkedHashMap schema; - private Object value; - private String propertyName; - - public DataEntity(String _dataTypeName,Object _valueDict, - LinkedHashMap _customDef,String _propName) { - - customDef = _customDef; - dataType = new DataType(_dataTypeName,_customDef); - schema = dataType.getAllProperties(); - value = _valueDict; - propertyName = _propName; - } - - @SuppressWarnings("unchecked") - public Object validate() { - // Validate the value by the definition of the datatype - - // A datatype can not have both 'type' and 'properties' definitions. - // If the datatype has 'type' definition - if(dataType.getValueType() != null) { - value = DataEntity.validateDatatype(dataType.getValueType(),value,null,customDef,null); - Schema schemaCls = new Schema(propertyName,dataType.getDefs()); - for(Constraint constraint: schemaCls.getConstraints()) { - constraint.validate(value); - } - } - // If the datatype has 'properties' definition - else { - if(!(value instanceof LinkedHashMap)) { - //ERROR under investigation - ExceptionCollector.appendWarning(String.format( - "TypeMismatchError: \"%s\" is not a map. The type is \"%s\"", - value.toString(),dataType.getType())); -<<<<<<< HEAD - return value; - } - LinkedHashMap valueDict = (LinkedHashMap)value; -======= - - if (value instanceof List) - value = ((List) value).get(0); - - if (!(value instanceof LinkedHashMap)) - return value; - } - - - - LinkedHashMap valueDict = (LinkedHashMap)value; ->>>>>>> master - ArrayList allowedProps = new ArrayList<>(); - ArrayList requiredProps = new ArrayList<>(); - LinkedHashMap defaultProps = new LinkedHashMap<>(); - if(schema != null) { - allowedProps.addAll(schema.keySet()); - for(String name: schema.keySet()) { - PropertyDef propDef = schema.get(name); - if(propDef.isRequired()) { - requiredProps.add(name); - } - if(propDef.getDefault() != null) { - defaultProps.put(name,propDef.getDefault()); - } - } - } - - // check allowed field - for(String valueKey: valueDict.keySet()) { - //1710 devlop JSON validation - if(!("json").equals(dataType.getType()) && !allowedProps.contains(valueKey)) { - ExceptionCollector.appendException(String.format( - "UnknownFieldError: Data value of type \"%s\" contains unknown field \"%s\"", - dataType.getType(),valueKey)); - } - } - - // check default field - for(String defKey: defaultProps.keySet()) { - Object defValue = defaultProps.get(defKey); - if(valueDict.get(defKey) == null) { - valueDict.put(defKey, defValue); - } - - } - - // check missing field - ArrayList missingProp = new ArrayList<>(); - for(String reqKey: requiredProps) { - if(!valueDict.keySet().contains(reqKey)) { - missingProp.add(reqKey); - } - } - if(missingProp.size() > 0) { - ExceptionCollector.appendWarning(String.format( - "MissingRequiredFieldError: Data value of type \"%s\" is missing required field(s) \"%s\"", - dataType.getType(),missingProp.toString())); - } - - // check every field - for(String vname: valueDict.keySet()) { - Object vvalue = valueDict.get(vname); - LinkedHashMap schemaName = _findSchema(vname); - if(schemaName == null) { - continue; - } - Schema propSchema = new Schema(vname,schemaName); - // check if field value meets type defined - DataEntity.validateDatatype(propSchema.getType(), - vvalue, - propSchema.getEntrySchema(), - customDef, - null); - - // check if field value meets constraints defined - if(propSchema.getConstraints() != null) { - for(Constraint constraint: propSchema.getConstraints()) { - if(vvalue instanceof ArrayList) { - for(Object val: (ArrayList)vvalue) { - constraint.validate(val); - } - } - else { - constraint.validate(vvalue); - } - } - } - } - } - return value; - } - - private LinkedHashMap _findSchema(String name) { - if(schema != null && schema.get(name) != null) { - return schema.get(name).getSchema(); - } - return null; - } - - public static Object validateDatatype(String type, - Object value, - LinkedHashMap entrySchema, - LinkedHashMap customDef, - String propName) { - // Validate value with given type - - // If type is list or map, validate its entry by entry_schema(if defined) - // If type is a user-defined complex datatype, custom_def is required. - - if(Function.isFunction(value)) { - return value; - } - else if (type == null) { - //NOT ANALYZED - ExceptionCollector.appendWarning(String.format( - "MissingType: Type is missing for value \"%s\"", - value.toString())); - return value; - } - else if(type.equals(Schema.STRING)) { - return ValidateUtils.validateString(value); - } - else if(type.equals(Schema.INTEGER)) { - return ValidateUtils.validateInteger(value); - } - else if(type.equals(Schema.FLOAT)) { - return ValidateUtils.validateFloat(value); - } - else if(type.equals(Schema.NUMBER)) { - return ValidateUtils.validateNumeric(value); - } - else if(type.equals(Schema.BOOLEAN)) { - return ValidateUtils.validateBoolean(value); - } - else if(type.equals(Schema.RANGE)) { - return ValidateUtils.validateRange(value); - } - else if(type.equals(Schema.TIMESTAMP)) { - ValidateUtils.validateTimestamp(value); - return value; - } - else if(type.equals(Schema.LIST)) { - ValidateUtils.validateList(value); - if(entrySchema != null) { - DataEntity.validateEntry(value,entrySchema,customDef); - } - return value; - } - else if(type.equals(Schema.SCALAR_UNIT_SIZE)) { - return (new ScalarUnitSize(value)).validateScalarUnit(); - } - else if(type.equals(Schema.SCALAR_UNIT_FREQUENCY)) { - return (new ScalarUnitFrequency(value)).validateScalarUnit(); - } - else if(type.equals(Schema.SCALAR_UNIT_TIME)) { - return (new ScalarUnitTime(value)).validateScalarUnit(); - } - else if(type.equals(Schema.VERSION)) { - return (new TOSCAVersionProperty(value)).getVersion(); - } - else if(type.equals(Schema.MAP)) { - ValidateUtils.validateMap(value); - if(entrySchema != null) { - DataEntity.validateEntry(value,entrySchema,customDef); - } - return value; - } - else if(type.equals(Schema.PORTSPEC)) { - // tODO(TBD) bug 1567063, validate source & target as PortDef type - // as complex types not just as integers - PortSpec.validateAdditionalReq(value,propName,customDef); - } - else { - DataEntity data = new DataEntity(type,value,customDef,null); - return data.validate(); - } - - return value; - } - - @SuppressWarnings("unchecked") - public static Object validateEntry(Object value, - LinkedHashMap entrySchema, - LinkedHashMap customDef) { - - // Validate entries for map and list - Schema schema = new Schema(null,entrySchema); - Object valueob = value; - ArrayList valueList = null; - if(valueob instanceof LinkedHashMap) { - valueList = new ArrayList(((LinkedHashMap)valueob).values()); - } - else if(valueob instanceof ArrayList) { - valueList = (ArrayList)valueob; - } - if(valueList != null) { - for(Object v: valueList) { - DataEntity.validateDatatype(schema.getType(),v,schema.getEntrySchema(),customDef,null); - if(schema.getConstraints() != null) { - for(Constraint constraint: schema.getConstraints()) { - constraint.validate(v); - } - } - } - } - return value; - } - - @Override - public String toString() { - return "DataEntity{" + - "customDef=" + customDef + - ", dataType=" + dataType + - ", schema=" + schema + - ", value=" + value + - ", propertyName='" + propertyName + '\'' + - '}'; - } -} - -/*python - -from toscaparser.common.exception import ExceptionCollector -from toscaparser.common.exception import MissingRequiredFieldError -from toscaparser.common.exception import TypeMismatchError -from toscaparser.common.exception import UnknownFieldError -from toscaparser.elements.constraints import Schema -from toscaparser.elements.datatype import DataType -from toscaparser.elements.portspectype import PortSpec -from toscaparser.elements.scalarunit import ScalarUnit_Frequency -from toscaparser.elements.scalarunit import ScalarUnit_Size -from toscaparser.elements.scalarunit import ScalarUnit_Time -from toscaparser.utils.gettextutils import _ -from toscaparser.utils import validateutils - - -class DataEntity(object): - '''A complex data value entity.''' - - def __init__(self, datatypename, value_dict, custom_def=None, - prop_name=None): - self.custom_def = custom_def - self.datatype = DataType(datatypename, custom_def) - self.schema = self.datatype.get_all_properties() - self.value = value_dict - self.property_name = prop_name - - def validate(self): - '''Validate the value by the definition of the datatype.''' - - # A datatype can not have both 'type' and 'properties' definitions. - # If the datatype has 'type' definition - if self.datatype.value_type: - self.value = DataEntity.validate_datatype(self.datatype.value_type, - self.value, - None, - self.custom_def) - schema = Schema(self.property_name, self.datatype.defs) - for constraint in schema.constraints: - constraint.validate(self.value) - # If the datatype has 'properties' definition - else: - if not isinstance(self.value, dict): - ExceptionCollector.appendException( - TypeMismatchError(what=self.value, - type=self.datatype.type)) - allowed_props = [] - required_props = [] - default_props = {} - if self.schema: - allowed_props = self.schema.keys() - for name, prop_def in self.schema.items(): - if prop_def.required: - required_props.append(name) - if prop_def.default: - default_props[name] = prop_def.default - - # check allowed field - for value_key in list(self.value.keys()): - if value_key not in allowed_props: - ExceptionCollector.appendException( - UnknownFieldError(what=(_('Data value of type "%s"') - % self.datatype.type), - field=value_key)) - - # check default field - for def_key, def_value in list(default_props.items()): - if def_key not in list(self.value.keys()): - self.value[def_key] = def_value - - # check missing field - missingprop = [] - for req_key in required_props: - if req_key not in list(self.value.keys()): - missingprop.append(req_key) - if missingprop: - ExceptionCollector.appendException( - MissingRequiredFieldError( - what=(_('Data value of type "%s"') - % self.datatype.type), required=missingprop)) - - # check every field - for name, value in list(self.value.items()): - schema_name = self._find_schema(name) - if not schema_name: - continue - prop_schema = Schema(name, schema_name) - # check if field value meets type defined - DataEntity.validate_datatype(prop_schema.type, value, - prop_schema.entry_schema, - self.custom_def) - # check if field value meets constraints defined - if prop_schema.constraints: - for constraint in prop_schema.constraints: - if isinstance(value, list): - for val in value: - constraint.validate(val) - else: - constraint.validate(value) - - return self.value - - def _find_schema(self, name): - if self.schema and name in self.schema.keys(): - return self.schema[name].schema - - @staticmethod - def validate_datatype(type, value, entry_schema=None, custom_def=None, - prop_name=None): - '''Validate value with given type. - - If type is list or map, validate its entry by entry_schema(if defined) - If type is a user-defined complex datatype, custom_def is required. - ''' - from toscaparser.functions import is_function - if is_function(value): - return value - if type == Schema.STRING: - return validateutils.validate_string(value) - elif type == Schema.INTEGER: - return validateutils.validate_integer(value) - elif type == Schema.FLOAT: - return validateutils.validate_float(value) - elif type == Schema.NUMBER: - return validateutils.validate_numeric(value) - elif type == Schema.BOOLEAN: - return validateutils.validate_boolean(value) - elif type == Schema.RANGE: - return validateutils.validate_range(value) - elif type == Schema.TIMESTAMP: - validateutils.validate_timestamp(value) - return value - elif type == Schema.LIST: - validateutils.validate_list(value) - if entry_schema: - DataEntity.validate_entry(value, entry_schema, custom_def) - return value - elif type == Schema.SCALAR_UNIT_SIZE: - return ScalarUnit_Size(value).validate_scalar_unit() - elif type == Schema.SCALAR_UNIT_FREQUENCY: - return ScalarUnit_Frequency(value).validate_scalar_unit() - elif type == Schema.SCALAR_UNIT_TIME: - return ScalarUnit_Time(value).validate_scalar_unit() - elif type == Schema.VERSION: - return validateutils.TOSCAVersionProperty(value).get_version() - elif type == Schema.MAP: - validateutils.validate_map(value) - if entry_schema: - DataEntity.validate_entry(value, entry_schema, custom_def) - return value - elif type == Schema.PORTSPEC: - # tODO(TBD) bug 1567063, validate source & target as PortDef type - # as complex types not just as integers - PortSpec.validate_additional_req(value, prop_name, custom_def) - else: - data = DataEntity(type, value, custom_def) - return data.validate() - - @staticmethod - def validate_entry(value, entry_schema, custom_def=None): - '''Validate entries for map and list.''' - schema = Schema(None, entry_schema) - valuelist = value - if isinstance(value, dict): - valuelist = list(value.values()) - for v in valuelist: - DataEntity.validate_datatype(schema.type, v, schema.entry_schema, - custom_def) - if schema.constraints: - for constraint in schema.constraints: - constraint.validate(v) - return value -*/ \ No newline at end of file diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/EntityTemplate.java b/src/main/java/org/openecomp/sdc/toscaparser/api/EntityTemplate.java index 32de069..ed19d88 100644 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/EntityTemplate.java +++ b/src/main/java/org/openecomp/sdc/toscaparser/api/EntityTemplate.java @@ -279,7 +279,7 @@ public abstract class EntityTemplate { if(pp != null) { properties.putAll(pp); } - CapabilityAssignment cap = new CapabilityAssignment(name, properties, c); + CapabilityAssignment cap = new CapabilityAssignment(name, properties, c, customDef); capability.add(cap); } } diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/TopologyTemplate.java.orig b/src/main/java/org/openecomp/sdc/toscaparser/api/TopologyTemplate.java.orig deleted file mode 100644 index 7e5f4af..0000000 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/TopologyTemplate.java.orig +++ /dev/null @@ -1,859 +0,0 @@ -package org.openecomp.sdc.toscaparser.api; - -import org.openecomp.sdc.toscaparser.api.common.JToscaError; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.openecomp.sdc.toscaparser.api.common.ValidationIssueCollector; -import org.openecomp.sdc.toscaparser.api.elements.InterfacesDef; -import org.openecomp.sdc.toscaparser.api.elements.NodeType; -import org.openecomp.sdc.toscaparser.api.elements.RelationshipType; -import org.openecomp.sdc.toscaparser.api.functions.Function; -import org.openecomp.sdc.toscaparser.api.functions.GetAttribute; -import org.openecomp.sdc.toscaparser.api.functions.GetInput; -import org.openecomp.sdc.toscaparser.api.parameters.Input; -import org.openecomp.sdc.toscaparser.api.parameters.Output; -import org.openecomp.sdc.toscaparser.api.utils.ThreadLocalsHolder; - -public class TopologyTemplate { - - private static final String DESCRIPTION = "description"; - private static final String INPUTS = "inputs"; - private static final String NODE_TEMPLATES = "node_templates"; - private static final String RELATIONSHIP_TEMPLATES = "relationship_templates"; - private static final String OUTPUTS = "outputs"; - private static final String GROUPS = "groups"; - private static final String SUBSTITUTION_MAPPINGS = "substitution_mappings"; - private static final String POLICIES = "policies"; - private static final String METADATA = "metadata"; - - private static String SECTIONS[] = { - DESCRIPTION, INPUTS, NODE_TEMPLATES, RELATIONSHIP_TEMPLATES, - OUTPUTS, GROUPS, SUBSTITUTION_MAPPINGS, POLICIES, METADATA - }; - - private LinkedHashMap tpl; - LinkedHashMap metaData; - private ArrayList inputs; - private ArrayList outputs; - private ArrayList relationshipTemplates; - private ArrayList nodeTemplates; - private LinkedHashMap customDefs; - private LinkedHashMap relTypes;//TYPE - private NodeTemplate subMappedNodeTemplate; - private ArrayList groups; - private ArrayList policies; - private LinkedHashMap parsedParams = null;//TYPE - private String description; - private ToscaGraph graph; - private SubstitutionMappings substitutionMappings; - - public TopologyTemplate( - LinkedHashMap _template, - LinkedHashMap _customDefs, - LinkedHashMap _relTypes,//TYPE - LinkedHashMap _parsedParams, - NodeTemplate _subMappedNodeTemplate) { - - tpl = _template; - if(tpl != null) { - subMappedNodeTemplate = _subMappedNodeTemplate; - metaData = _metaData(); - customDefs = _customDefs; - relTypes = _relTypes; - parsedParams = _parsedParams; - _validateField(); - description = _tplDescription(); - inputs = _inputs(); - relationshipTemplates =_relationshipTemplates(); - nodeTemplates = _nodeTemplates(); - outputs = _outputs(); - if(nodeTemplates != null) { - graph = new ToscaGraph(nodeTemplates); - } - groups = _groups(); - policies = _policies(); - _processIntrinsicFunctions(); - substitutionMappings = _substitutionMappings(); - } - } - - @SuppressWarnings("unchecked") - private ArrayList _inputs() { - //DumpUtils.dumpYaml(customDefs,0); - ArrayList alInputs = new ArrayList<>(); - for(String name: _tplInputs().keySet()) { - Object attrs = _tplInputs().get(name); - Input input = new Input(name,(LinkedHashMap)attrs,customDefs); - if(parsedParams != null && parsedParams.get(name) != null) { - input.validate(parsedParams.get(name)); - } - else { - Object _default = input.getDefault(); - if(_default != null) { - input.validate(_default); - } - } - if((parsedParams != null && parsedParams.get(input.getName()) == null || parsedParams == null) - && input.isRequired() && input.getDefault() == null) { - System.out.format("Log warning: The required parameter \"%s\" is not provided\n",input.getName()); - } - alInputs.add(input); - } - return alInputs; - - } - - private LinkedHashMap _metaData() { - if(tpl.get(METADATA) != null) { - return (LinkedHashMap)tpl.get(METADATA); - } - else { - return new LinkedHashMap(); - } - - } - - private ArrayList _nodeTemplates() { - ArrayList alNodeTemplates = new ArrayList<>(); - LinkedHashMap tpls = _tplNodeTemplates(); - if(tpls != null) { - for(String name: tpls.keySet()) { - NodeTemplate tpl = new NodeTemplate(name, - tpls, - customDefs, - relationshipTemplates, - relTypes); - if(tpl.getTypeDefinition() != null) { - boolean b = NodeType.TOSCA_DEF.get(tpl.getType()) != null; - if(b || (tpl.getCustomDef() != null && !tpl.getCustomDef().isEmpty())) { - tpl.validate(); - alNodeTemplates.add(tpl); - } - } - } - } - return alNodeTemplates; - } - - @SuppressWarnings("unchecked") - private ArrayList _relationshipTemplates() { - ArrayList alRelationshipTemplates = new ArrayList<>(); - LinkedHashMap tpls = _tplRelationshipTemplates(); - if(tpls != null) { - for(String name: tpls.keySet()) { - RelationshipTemplate tpl = new RelationshipTemplate( - (LinkedHashMap)tpls.get(name),name,customDefs,null,null); - - alRelationshipTemplates.add(tpl); - } - } - return alRelationshipTemplates; - } - - private ArrayList _outputs() { - ArrayList alOutputs = new ArrayList<>(); - for(Map.Entry me: _tplOutputs().entrySet()) { - String oname = me.getKey(); - LinkedHashMap oattrs = (LinkedHashMap)me.getValue(); - Output o = new Output(oname,oattrs); - o.validate(); - alOutputs.add(o); - } - return alOutputs; - } - - private SubstitutionMappings _substitutionMappings() { - LinkedHashMap tplSubstitutionMapping = (LinkedHashMap) _tplSubstitutionMappings(); - - //*** the commenting-out below and the weaker condition are in the Python source - // #if tpl_substitution_mapping and self.sub_mapped_node_template: - if(tplSubstitutionMapping != null && tplSubstitutionMapping.size() > 0) { - return new SubstitutionMappings(tplSubstitutionMapping, - nodeTemplates, - inputs, - outputs, - groups, - subMappedNodeTemplate, - customDefs); - } - return null; - - } - - @SuppressWarnings("unchecked") - private ArrayList _policies() { - ArrayList alPolicies = new ArrayList<>(); - for(Object po: _tplPolicies()) { - LinkedHashMap policy = (LinkedHashMap)po; - for(Map.Entry me: policy.entrySet()) { - String policyName = me.getKey(); - LinkedHashMap policyTpl = (LinkedHashMap)me.getValue(); - ArrayList targetList = (ArrayList)policyTpl.get("targets"); - //ArrayList targetObjects = new ArrayList<>(); - ArrayList targetNodes = new ArrayList<>(); - ArrayList targetObjects = new ArrayList<>(); - ArrayList targetGroups = new ArrayList<>(); - String targetsType = "groups"; - if(targetList != null && targetList.size() >= 1) { - targetGroups = _getPolicyGroups(targetList); - if(targetGroups == null) { - targetsType = "node_templates"; - targetNodes = _getGroupMembers(targetList); - for(NodeTemplate nt: targetNodes) { - targetObjects.add(nt); - } - } - else { - for(Group gr: targetGroups) { - targetObjects.add(gr); - } - } - } - Policy policyObj = new Policy(policyName, - policyTpl, - targetObjects, - targetsType, - customDefs); - alPolicies.add(policyObj); - } - } - return alPolicies; - } - - private ArrayList _groups() { - ArrayList groups = new ArrayList<>(); - ArrayList memberNodes = null; - for(Map.Entry me: _tplGroups().entrySet()) { - String groupName = me.getKey(); - LinkedHashMap groupTpl = (LinkedHashMap)me.getValue(); - ArrayList memberNames = (ArrayList)groupTpl.get("members"); - if(memberNames != null) { - DataEntity.validateDatatype("list", memberNames,null,null,null); - if(memberNames.size() < 1 || - (new HashSet(memberNames)).size() != memberNames.size()) { - ThreadLocalsHolder.getCollector().appendError(new JToscaError("JE241", String.format( - "InvalidGroupTargetException: Member nodes \"%s\" should be >= 1 and not repeated", - memberNames.toString()))); - } - else { - memberNodes = _getGroupMembers(memberNames); - } - } - Group group = new Group(groupName, - groupTpl, - memberNodes, - customDefs); - groups.add(group); - } - return groups; - } - - private ArrayList _getGroupMembers(ArrayList memberNames) { - ArrayList memberNodes = new ArrayList<>(); - _validateGroupMembers(memberNames); - for(String member: memberNames) { - for(NodeTemplate node: nodeTemplates) { - if(member.equals(node.getName())) { - memberNodes.add(node); - } - } - } - return memberNodes; - } - - private ArrayList _getPolicyGroups(ArrayList memberNames) { - ArrayList memberGroups = new ArrayList<>(); - for(String member: memberNames) { - for(Group group: groups) { - if(member.equals(group.getName())) { - memberGroups.add(group); - } - } - } - return memberGroups; - } - - private void _validateGroupMembers(ArrayList members) { - ArrayList nodeNames = new ArrayList<>(); - for(NodeTemplate node: nodeTemplates) { - nodeNames.add(node.getName()); - } - for(String member: members) { - if(!nodeNames.contains(member)) { - ThreadLocalsHolder.getCollector().appendError(new JToscaError("JE242", String.format( - "InvalidGroupTargetException: Target member \"%s\" is not found in \"nodeTemplates\"",member))); - } - } - } - - // topology template can act like node template - // it is exposed by substitution_mappings. - - public String nodetype() { - return substitutionMappings.getNodeType(); - } - - public LinkedHashMap capabilities() { - return substitutionMappings.getCapabilities(); - } - - public LinkedHashMap requirements() { - return substitutionMappings.getRequirements(); - } - - private String _tplDescription() { - return (String)tpl.get(DESCRIPTION); - //if description: - // return description.rstrip() - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplInputs() { - if(tpl.get(INPUTS) != null) { - return (LinkedHashMap)tpl.get(INPUTS); - } - else { - return new LinkedHashMap(); - } - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplNodeTemplates() { - return (LinkedHashMap)tpl.get(NODE_TEMPLATES); - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplRelationshipTemplates() { - if(tpl.get(RELATIONSHIP_TEMPLATES) != null) { - return (LinkedHashMap)tpl.get(RELATIONSHIP_TEMPLATES); - } - else { - return new LinkedHashMap(); - } - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplOutputs() { - if(tpl.get(OUTPUTS) != null) { - return (LinkedHashMap)tpl.get(OUTPUTS); - } - else { - return new LinkedHashMap(); - } - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplSubstitutionMappings() { - if(tpl.get(SUBSTITUTION_MAPPINGS) != null) { - return (LinkedHashMap)tpl.get(SUBSTITUTION_MAPPINGS); - } - else { - return new LinkedHashMap(); - } - } - - @SuppressWarnings("unchecked") - private LinkedHashMap _tplGroups() { - if(tpl.get(GROUPS) != null) { - return (LinkedHashMap)tpl.get(GROUPS); - } - else { - return new LinkedHashMap(); - } - } - - @SuppressWarnings("unchecked") - private ArrayList _tplPolicies() { - if(tpl.get(POLICIES) != null) { - return (ArrayList)tpl.get(POLICIES); - } - else { - return new ArrayList(); - } - } - - private void _validateField() { - for(String name: tpl.keySet()) { - boolean bFound = false; - for(String section: SECTIONS) { - if(name.equals(section)) { - bFound = true; - break; - } - } - if(!bFound) { - ThreadLocalsHolder.getCollector().appendError(new JToscaError("JE243", String.format( - "UnknownFieldError: TopologyTemplate contains unknown field \"%s\"",name))); - } - } - } - - @SuppressWarnings("unchecked") - private void _processIntrinsicFunctions() { - // Process intrinsic functions - - // Current implementation processes functions within node template - // properties, requirements, interfaces inputs and template outputs. - - if(nodeTemplates != null) { - for(NodeTemplate nt: nodeTemplates) { - for(Property prop: nt.getPropertiesObjects()) { - prop.setValue(Function.getFunction(this,nt,prop.getValue())); - } - for(InterfacesDef ifd: nt.getInterfaces()) { - LinkedHashMap ifin = ifd.getInputs(); - if(ifin != null) { - for(Map.Entry me: ifin.entrySet()) { - String name = me.getKey(); - Object value = Function.getFunction(this,nt,me.getValue()); - ifd.setInput(name,value); - } - } - } - if(nt.getRequirements() != null && - nt.getRequirements() instanceof ArrayList) { - for(Object oreq: nt.getRequirements()) { - LinkedHashMap req = (LinkedHashMap)oreq; - LinkedHashMap rel = req; - for(String reqName: req.keySet()) { - Object reqItem = req.get(reqName); - if(reqItem instanceof LinkedHashMap) { - Object t = ((LinkedHashMap)reqItem).get("relationship"); - // it can be a string or a LHM... - if(t instanceof LinkedHashMap) { - rel = (LinkedHashMap)t; - } - else { - // we set it to null to fail the next test - // and avoid the get("proprties") - rel = null; - } - break; - } - } - if(rel != null && rel.get("properties") != null) { - LinkedHashMap relprops = - (LinkedHashMap)rel.get("properties"); - for(String key: relprops.keySet()) { - Object value = relprops.get(key); - Object func = Function.getFunction(this,req,value); - relprops.put(key,func); - } - } - } - } - if(nt.getCapabilitiesObjects() != null) { - for(Capability cap: nt.getCapabilitiesObjects()) { - if(cap.getPropertiesObjects() != null) { - for(Property prop: cap.getPropertiesObjects()) { - Object propvalue = Function.getFunction(this,nt,prop.getValue()); - if(propvalue instanceof GetInput) { - propvalue = ((GetInput)propvalue).result(); - for(String p: cap.getProperties().keySet()) { - //Object v = cap.getProperties().get(p); - if(p.equals(prop.getName())) { - cap.setProperty(p,propvalue); - } - } - } - } - } - } - } - for(RelationshipType rel: nt.getRelationships().keySet()) { - NodeTemplate node = nt.getRelationships().get(rel); - ArrayList relTpls = node.getRelationshipTemplate(); - if(relTpls != null) { - for(RelationshipTemplate relTpl: relTpls) { - // TT 5 - for(InterfacesDef iface: relTpl.getInterfaces()) { - if(iface.getInputs() != null) { - for(String name: iface.getInputs().keySet()) { - Object value = iface.getInputs().get(name); - Object func = Function.getFunction( - this, - relTpl, - value); - iface.setInput(name,func); - } - } - } - } - } - } - } - } - for(Output output: outputs) { - Object func = Function.getFunction(this,outputs,output.getValue()); - if(func instanceof GetAttribute) { - output.setAttr(Output.VALUE,func); - } - } - } - - public static String getSubMappingNodeType(LinkedHashMap topologyTpl) { - if(topologyTpl != null && topologyTpl instanceof LinkedHashMap) { - Object submapTpl = topologyTpl.get(SUBSTITUTION_MAPPINGS); - return SubstitutionMappings.stGetNodeType((LinkedHashMap)submapTpl); - } - return null; - } - - // getters - - public LinkedHashMap getTpl() { - return tpl; - } - - public LinkedHashMap getMetadata() { - return metaData; - } - - public ArrayList getInputs() { - return inputs; - } - - public ArrayList getOutputs() { - return outputs; - } - - public ArrayList getPolicies() { - return policies; - } - - public ArrayList getRelationshipTemplates() { - return relationshipTemplates; - } - - public ArrayList getNodeTemplates() { - return nodeTemplates; - } - - public ArrayList getGroups() { - return groups; - } - - public SubstitutionMappings getSubstitutionMappings() { - return substitutionMappings; - } - - public LinkedHashMap getParsedParams() { - return parsedParams; - } -} - -/*python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import logging - -from toscaparser.common import exception -from toscaparser.dataentity import DataEntity -from toscaparser import functions -from toscaparser.groups import Group -from toscaparser.nodetemplate import NodeTemplate -from toscaparser.parameters import Input -from toscaparser.parameters import Output -from toscaparser.policy import Policy -from toscaparser.relationship_template import RelationshipTemplate -from toscaparser.substitution_mappings import SubstitutionMappings -from toscaparser.tpl_relationship_graph import ToscaGraph -from toscaparser.utils.gettextutils import _ - - -# Topology template key names -SECTIONS = (DESCRIPTION, INPUTS, NODE_TEMPLATES, - RELATIONSHIP_TEMPLATES, OUTPUTS, GROUPS, - SUBSTITUION_MAPPINGS, POLICIES) = \ - ('description', 'inputs', 'node_templates', - 'relationship_templates', 'outputs', 'groups', - 'substitution_mappings', 'policies') - -log = logging.getLogger("tosca.model") - - -class TopologyTemplate(object): - - '''Load the template data.''' - def __init__(self, template, custom_defs, - rel_types=None, parsed_params=None, - sub_mapped_node_template=None): - self.tpl = template - self.sub_mapped_node_template = sub_mapped_node_template - if self.tpl: - self.custom_defs = custom_defs - self.rel_types = rel_types - self.parsed_params = parsed_params - self._validate_field() - self.description = self._tpl_description() - self.inputs = self._inputs() - self.relationship_templates = self._relationship_templates() - self.nodetemplates = self._nodetemplates() - self.outputs = self._outputs() - if hasattr(self, 'nodetemplates'): - self.graph = ToscaGraph(self.nodetemplates) - self.groups = self._groups() - self.policies = self._policies() - self._process_intrinsic_functions() - self.substitution_mappings = self._substitution_mappings() - - def _inputs(self): - inputs = [] - for name, attrs in self._tpl_inputs().items(): - input = Input(name, attrs) - if self.parsed_params and name in self.parsed_params: - input.validate(self.parsed_params[name]) - else: - default = input.default - if default: - input.validate(default) - if (self.parsed_params and input.name not in self.parsed_params - or self.parsed_params is None) and input.required \ - and input.default is None: - log.warning(_('The required parameter %s ' - 'is not provided') % input.name) - - inputs.append(input) - return inputs - - def _nodetemplates(self): - nodetemplates = [] - tpls = self._tpl_nodetemplates() - if tpls: - for name in tpls: - tpl = NodeTemplate(name, tpls, self.custom_defs, - self.relationship_templates, - self.rel_types) - if (tpl.type_definition and - (tpl.type in tpl.type_definition.TOSCA_DEF or - (tpl.type not in tpl.type_definition.TOSCA_DEF and - bool(tpl.custom_def)))): - tpl.validate(self) - nodetemplates.append(tpl) - return nodetemplates - - def _relationship_templates(self): - rel_templates = [] - tpls = self._tpl_relationship_templates() - for name in tpls: - tpl = RelationshipTemplate(tpls[name], name, self.custom_defs) - rel_templates.append(tpl) - return rel_templates - - def _outputs(self): - outputs = [] - for name, attrs in self._tpl_outputs().items(): - output = Output(name, attrs) - output.validate() - outputs.append(output) - return outputs - - def _substitution_mappings(self): - tpl_substitution_mapping = self._tpl_substitution_mappings() - # if tpl_substitution_mapping and self.sub_mapped_node_template: - if tpl_substitution_mapping: - return SubstitutionMappings(tpl_substitution_mapping, - self.nodetemplates, - self.inputs, - self.outputs, - self.sub_mapped_node_template, - self.custom_defs) - - def _policies(self): - policies = [] - for policy in self._tpl_policies(): - for policy_name, policy_tpl in policy.items(): - target_list = policy_tpl.get('targets') - if target_list and len(target_list) >= 1: - target_objects = [] - targets_type = "groups" - target_objects = self._get_policy_groups(target_list) - if not target_objects: - targets_type = "node_templates" - target_objects = self._get_group_members(target_list) - policyObj = Policy(policy_name, policy_tpl, - target_objects, targets_type, - self.custom_defs) - policies.append(policyObj) - return policies - - def _groups(self): - groups = [] - member_nodes = None - for group_name, group_tpl in self._tpl_groups().items(): - member_names = group_tpl.get('members') - if member_names is not None: - DataEntity.validate_datatype('list', member_names) - if len(member_names) < 1 or \ - len(member_names) != len(set(member_names)): - exception.ExceptionCollector.appendException( - exception.InvalidGroupTargetException( - message=_('Member nodes "%s" should be >= 1 ' - 'and not repeated') % member_names)) - else: - member_nodes = self._get_group_members(member_names) - group = Group(group_name, group_tpl, - member_nodes, - self.custom_defs) - groups.append(group) - return groups - - def _get_group_members(self, member_names): - member_nodes = [] - self._validate_group_members(member_names) - for member in member_names: - for node in self.nodetemplates: - if node.name == member: - member_nodes.append(node) - return member_nodes - - def _get_policy_groups(self, member_names): - member_groups = [] - for member in member_names: - for group in self.groups: - if group.name == member: - member_groups.append(group) - return member_groups - - def _validate_group_members(self, members): - node_names = [] - for node in self.nodetemplates: - node_names.append(node.name) - for member in members: - if member not in node_names: - exception.ExceptionCollector.appendException( - exception.InvalidGroupTargetException( - message=_('Target member "%s" is not found in ' - 'node_templates') % member)) - - # topology template can act like node template - # it is exposed by substitution_mappings. - def nodetype(self): - return self.substitution_mappings.node_type \ - if self.substitution_mappings else None - - def capabilities(self): - return self.substitution_mappings.capabilities \ - if self.substitution_mappings else None - - def requirements(self): - return self.substitution_mappings.requirements \ - if self.substitution_mappings else None - - def _tpl_description(self): - description = self.tpl.get(DESCRIPTION) - if description: - return description.rstrip() - - def _tpl_inputs(self): - return self.tpl.get(INPUTS) or {} - - def _tpl_nodetemplates(self): - return self.tpl.get(NODE_TEMPLATES) - - def _tpl_relationship_templates(self): - return self.tpl.get(RELATIONSHIP_TEMPLATES) or {} - - def _tpl_outputs(self): - return self.tpl.get(OUTPUTS) or {} - - def _tpl_substitution_mappings(self): - return self.tpl.get(SUBSTITUION_MAPPINGS) or {} - - def _tpl_groups(self): - return self.tpl.get(GROUPS) or {} - - def _tpl_policies(self): - return self.tpl.get(POLICIES) or {} - - def _validate_field(self): - for name in self.tpl: - if name not in SECTIONS: - exception.ExceptionCollector.appendException( - exception.UnknownFieldError(what='Template', field=name)) - - def _process_intrinsic_functions(self): - """Process intrinsic functions - - Current implementation processes functions within node template - properties, requirements, interfaces inputs and template outputs. - """ - if hasattr(self, 'nodetemplates'): - for node_template in self.nodetemplates: - for prop in node_template.get_properties_objects(): - prop.value = functions.get_function(self, - node_template, - prop.value) - for interface in node_template.interfaces: - if interface.inputs: - for name, value in interface.inputs.items(): - interface.inputs[name] = functions.get_function( - self, - node_template, - value) - if node_template.requirements and \ - isinstance(node_template.requirements, list): - for req in node_template.requirements: - rel = req - for req_name, req_item in req.items(): - if isinstance(req_item, dict): - rel = req_item.get('relationship') - break - if rel and 'properties' in rel: - for key, value in rel['properties'].items(): - rel['properties'][key] = \ - functions.get_function(self, - req, - value) - if node_template.get_capabilities_objects(): - for cap in node_template.get_capabilities_objects(): - if cap.get_properties_objects(): - for prop in cap.get_properties_objects(): - propvalue = functions.get_function( - self, - node_template, - prop.value) - if isinstance(propvalue, functions.GetInput): - propvalue = propvalue.result() - for p, v in cap._properties.items(): - if p == prop.name: - cap._properties[p] = propvalue - for rel, node in node_template.relationships.items(): - rel_tpls = node.relationship_tpl - if rel_tpls: - for rel_tpl in rel_tpls: - for interface in rel_tpl.interfaces: - if interface.inputs: - for name, value in \ - interface.inputs.items(): - interface.inputs[name] = \ - functions.get_function(self, - rel_tpl, - value) - for output in self.outputs: - func = functions.get_function(self, self.outputs, output.value) - if isinstance(func, functions.GetAttribute): - output.attrs[output.VALUE] = func - - @classmethod - def get_sub_mapping_node_type(cls, topology_tpl): - if topology_tpl and isinstance(topology_tpl, dict): - submap_tpl = topology_tpl.get(SUBSTITUION_MAPPINGS) - return SubstitutionMappings.get_node_type(submap_tpl) -*/ \ No newline at end of file diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/ToscaTemplate.java b/src/main/java/org/openecomp/sdc/toscaparser/api/ToscaTemplate.java index f5902c4..4c6ba3a 100644 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/ToscaTemplate.java +++ b/src/main/java/org/openecomp/sdc/toscaparser/api/ToscaTemplate.java @@ -116,11 +116,13 @@ public class ToscaTemplate extends Object { VALID_TEMPLATE_VERSIONS = new ArrayList<>(); VALID_TEMPLATE_VERSIONS.add("tosca_simple_yaml_1_0"); + VALID_TEMPLATE_VERSIONS.add("tosca_simple_yaml_1_1"); VALID_TEMPLATE_VERSIONS.addAll(exttools.getVersions()); ADDITIONAL_SECTIONS = new LinkedHashMap<>(); SPECIAL_SECTIONS = new ArrayList<>(); SPECIAL_SECTIONS.add(METADATA); ADDITIONAL_SECTIONS.put("tosca_simple_yaml_1_0",SPECIAL_SECTIONS); + ADDITIONAL_SECTIONS.put("tosca_simple_yaml_1_1",SPECIAL_SECTIONS); ADDITIONAL_SECTIONS.putAll(exttools.getSections()); //long startTime = System.nanoTime(); @@ -495,8 +497,9 @@ public class ToscaTemplate extends Object { "InvalidTemplateVersion: \"%s\" is invalid. Valid versions are %s", sVersion,VALID_TEMPLATE_VERSIONS.toString()))); } - else if(!sVersion.equals("tosca_simple_yaml_1_0")) { + else if ((!sVersion.equals("tosca_simple_yaml_1_0") && !sVersion.equals("tosca_simple_yaml_1_1"))) { EntityType.updateDefinitions(sVersion); + } } diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/elements/NodeType.java b/src/main/java/org/openecomp/sdc/toscaparser/api/elements/NodeType.java index cb4aa74..48fbe59 100644 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/elements/NodeType.java +++ b/src/main/java/org/openecomp/sdc/toscaparser/api/elements/NodeType.java @@ -131,16 +131,15 @@ public class NodeType extends StatefulEntityType { // This method will lookup all node types if they have the // provided capability. - // Filter the node types ArrayList nodeTypes = new ArrayList<>(); - for(String nt: TOSCA_DEF.keySet()) { - if(nt.startsWith(NODE_PREFIX) && !nt.equals("tosca.nodes.Root")) { + for(String nt: customDef.keySet()) { + if(nt.startsWith(NODE_PREFIX) || nt.startsWith("org.openecomp") && !nt.equals("tosca.nodes.Root")) { nodeTypes.add(nt); } } for(String nt: nodeTypes) { - LinkedHashMap nodeDef = (LinkedHashMap)TOSCA_DEF.get(nt); + LinkedHashMap nodeDef = (LinkedHashMap)customDef.get(nt); if(nodeDef instanceof LinkedHashMap && nodeDef.get("capabilities") != null) { LinkedHashMap nodeCaps = (LinkedHashMap)nodeDef.get("capabilities"); if(nodeCaps != null) { @@ -161,13 +160,17 @@ public class NodeType extends StatefulEntityType { @SuppressWarnings("unchecked") private String _getRelation(String key,String ndtype) { String relation = null; - NodeType ntype = new NodeType(ndtype,null); + NodeType ntype = new NodeType(ndtype, customDef); LinkedHashMap caps = ntype.getCapabilities(); if(caps != null && caps.get(key) != null) { CapabilityTypeDef c = caps.get(key); for(int i=0; i< RELATIONSHIP_TYPE.length; i++) { String r = RELATIONSHIP_TYPE[i]; - LinkedHashMap rtypedef = (LinkedHashMap)TOSCA_DEF.get(r); + if(r != null) { + relation = r; + break; + } + LinkedHashMap rtypedef = (LinkedHashMap)customDef.get(r); for(Object o: rtypedef.values()) { LinkedHashMap properties = (LinkedHashMap)o; if(properties.get(c.getType()) != null) { diff --git a/src/main/java/org/openecomp/sdc/toscaparser/api/elements/TypeValidation.java b/src/main/java/org/openecomp/sdc/toscaparser/api/elements/TypeValidation.java index 50c9739..7bfe333 100644 --- a/src/main/java/org/openecomp/sdc/toscaparser/api/elements/TypeValidation.java +++ b/src/main/java/org/openecomp/sdc/toscaparser/api/elements/TypeValidation.java @@ -41,6 +41,7 @@ public class TypeValidation { private static ArrayList _getVTV() { ArrayList vtv = new ArrayList<>(); vtv.add("tosca_simple_yaml_1_0"); + vtv.add("tosca_simple_yaml_1_1"); ExtTools exttools = new ExtTools(); vtv.addAll(exttools.getVersions()); return vtv; diff --git a/src/test/java/org.openecomp.sdc.toscaparser/JToscaMetadataParse.java b/src/test/java/org/openecomp/sdc/toscaparser/api/JToscaMetadataParse.java similarity index 55% rename from src/test/java/org.openecomp.sdc.toscaparser/JToscaMetadataParse.java rename to src/test/java/org/openecomp/sdc/toscaparser/api/JToscaMetadataParse.java index 584a0fd..79d166f 100644 --- a/src/test/java/org.openecomp.sdc.toscaparser/JToscaMetadataParse.java +++ b/src/test/java/org/openecomp/sdc/toscaparser/api/JToscaMetadataParse.java @@ -1,14 +1,17 @@ -package org.openecomp.sdc.toscaparser; +package org.openecomp.sdc.toscaparser.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.Collection; import java.util.LinkedHashMap; import org.junit.Test; -import org.openecomp.sdc.toscaparser.api.ToscaTemplate; import org.openecomp.sdc.toscaparser.api.common.JToscaException; +import org.openecomp.sdc.toscaparser.api.common.JToscaValidationIssue; +import org.openecomp.sdc.toscaparser.api.utils.ThreadLocalsHolder; public class JToscaMetadataParse { @@ -23,4 +26,16 @@ public class JToscaMetadataParse { assertNotNull(entryDefinition); assertEquals("tosca_helloworld.yaml", entryDefinition); } + + @Test + public void noWarningsAfterParse() throws JToscaException { + String fileStr = JToscaMetadataParse.class.getClassLoader().getResource("csars/tmpCSAR_Huawei_vSPGW_fixed.csar.csar").getFile(); + File file = new File(fileStr); + ToscaTemplate toscaTemplate = new ToscaTemplate(file.getAbsolutePath(), null, true, null); + + +// Collection issues = ThreadLocalsHolder.getCollector().getValidationIssues().values(); +// assertTrue(issues.size() == 0 ); + } + } diff --git a/src/test/resources/csars/tmpCSAR_Huawei_vSPGW_fixed.csar.csar b/src/test/resources/csars/tmpCSAR_Huawei_vSPGW_fixed.csar.csar new file mode 100644 index 0000000000000000000000000000000000000000..70f8cc42b2a92041f59e470d7c0c10d4cc6ab666 GIT binary patch literal 44576 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󞜛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 literal 0 HcmV?d00001 diff --git a/version.properties b/version.properties index f7d411d..f842c49 100644 --- a/version.properties +++ b/version.properties @@ -5,7 +5,7 @@ major=1 minor=1 -patch=16 +patch=19 base_version=${major}.${minor}.${patch} -- 2.16.6