You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2017/10/23 19:29:25 UTC
[GitHub] houshengbo closed pull request #607: JSON Output support
houshengbo closed pull request #607: JSON Output support
URL: https://github.com/apache/incubator-openwhisk-wskdeploy/pull/607
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index 08c5c99..c6ce6d2 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -376,16 +376,20 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
// set the name of the action (which is the key)
action.Name = key
+ // Create action data object with CLI
+ wskaction := new(whisk.Action)
+ wskaction.Exec = new(whisk.Exec)
+
+ /*
+ * Action.Function
+ */
//set action.Function to action.Location
//because Location is deprecated in Action entity
if action.Function == "" && action.Location != "" {
action.Function = action.Location
}
- wskaction := new(whisk.Action)
//bind action, and exposed URL
-
- wskaction.Exec = new(whisk.Exec)
if action.Function != "" {
filePath := strings.TrimRight(filePath, splitFilePath[len(splitFilePath)-1]) + action.Function
@@ -419,7 +423,7 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
kind = "nodejs:6"
errStr := wski18n.T("Unsupported runtime type, set to nodejs")
whisk.Debug(whisk.DbgWarn, errStr)
- //add the user input kind here
+ // TODO() add the user input kind here if interactive
}
wskaction.Exec.Kind = kind
@@ -441,6 +445,9 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
}
+ /*
+ * Action.Runtime
+ */
if action.Runtime != "" {
if utils.CheckExistRuntime(action.Runtime, utils.Rts) {
wskaction.Exec.Kind = action.Runtime
@@ -458,11 +465,13 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
wskaction.Exec.Main = action.Main
}
+ /*
+ * Action.Inputs
+ */
keyValArr := make(whisk.KeyValueArr, 0)
for name, param := range action.Inputs {
var keyVal whisk.KeyValue
keyVal.Key = name
-
keyVal.Value, errorParser = ResolveParameter(name, ¶m, filePath)
if errorParser != nil {
@@ -474,19 +483,51 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
}
}
+ // if we have successfully parser valid key/value parameters
if len(keyValArr) > 0 {
wskaction.Parameters = keyValArr
}
+ /*
+ * Action.Outputs
+ */
+ keyValArr = make(whisk.KeyValueArr, 0)
+ for name, param := range action.Outputs {
+ var keyVal whisk.KeyValue
+ keyVal.Key = name
+ keyVal.Value, errorParser = ResolveParameter(name, ¶m, filePath)
+
+ // short circuit on error
+ if errorParser != nil {
+ return nil, errorParser
+ }
+
+ if keyVal.Value != nil {
+ keyValArr = append(keyValArr, keyVal)
+ }
+ }
+
+ // TODO{} add outputs as annotations (work to discuss officially supporting for compositions)
+ if len(keyValArr) > 0 {
+ //wskaction.Annotations // TBD
+ }
+
+ /*
+ * Action.Annotations
+ */
keyValArr = make(whisk.KeyValueArr, 0)
for name, value := range action.Annotations {
var keyVal whisk.KeyValue
keyVal.Key = name
keyVal.Value = utils.GetEnvVar(value)
-
keyValArr = append(keyValArr, keyVal)
+ // TODO{} Fix Annottions; they are not added to Action if web-export key is not present
+ // Need to assure annotations are added/set even if web-export is not set on the action.
}
+ /*
+ * Web Export
+ */
// only set the webaction when the annotations are not empty.
if action.Webexport == "true" {
// TODO() why is this commented out? we should now support annotations...
@@ -497,7 +538,9 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
}
}
- //set limitations
+ /*
+ * Action.Limits
+ */
if action.Limits!=nil {
wsklimits := new(whisk.Limits)
if utils.LimitsTimeoutValidation(action.Limits.Timeout) {
@@ -769,97 +812,192 @@ func ResolveParamTypeFromValue(name string, value interface{}, filePath string)
return paramType, err
}
-// Resolve input parameter (i.e., type, value, default)
-// Note: parameter values may set later (overriddNen) by an (optional) Deployment file
-func ResolveParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
- var errorParser error
- var tempType string
- // default parameter value to empty string
- var value interface{} = ""
+/*
+ resolveSingleLineParameter assures that a Parameter's Type is correctly identified and set from its Value.
- // Trace Parameter struct before any resolution
- //dumpParameter(paramName, param, "BEFORE")
+ Additionally, this function:
+
+ - detects if the parameter value contains the name of a valid OpenWhisk parameter types. if so, the
+ - param.Type is set to detected OpenWhisk parameter type.
+ - param.Value is set to the zero (default) value for that OpenWhisk parameter type.
+ */
+func resolveSingleLineParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
+ var errorParser error
- // Parameters can be single OR multi-line declarations which must be processed/validated differently
if !param.multiline {
- // we have a single-line parameter declaration
// We need to identify parameter Type here for later validation
param.Type, errorParser = ResolveParamTypeFromValue(paramName, param.Value, filePath)
// In single-line format, the param's <value> can be a "Type name" and NOT an actual value.
// if this is the case, we must detect it and set the value to the default for that type name.
- if param.Value!=nil && param.Type == "string" {
+ if param.Value != nil && param.Type == "string" {
// The value is a <string>; now we must test if is the name of a known Type
- var tempValue = param.Value.(string)
- if isValidParameterType(tempValue) {
+ if isValidParameterType(param.Value.(string)) {
// If the value is indeed the name of a Type, we must change BOTH its
// Type to be that type and its value to that Type's default value
- // (which happens later by setting it to nil here
param.Type = param.Value.(string)
- param.Value = nil
+ param.Value = getTypeDefaultValue(param.Type)
+ fmt.Printf("EXIT: Parameter [%s] type=[%v] value=[%v]\n", paramName, param.Type, param.Value)
}
}
} else {
- // we have a multi-line parameter declaration
+ msgs := []string{"Parameter [" + paramName + "] is not single-line format."}
+ return param.Value, utils.NewParserErr(filePath, nil, msgs)
+ }
+
+ return param.Value, errorParser
+}
+
+/*
+ resolveMultiLineParameter assures that the values for Parameter Type and Value are properly set and are valid.
+
+ Additionally, this function:
+ - uses param.Default as param.Value if param.Value is not provided
+ - uses the actual param.Value data type for param.type if param.Type is not provided
+
+ */
+func resolveMultiLineParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
+ var errorParser error
+
+ if param.multiline {
+ var valueType string
// if we do not have a value, but have a default, use it for the value
if param.Value == nil && param.Default != nil {
param.Value = param.Default
}
- // if we also have a type at this point, verify value (and/or default) matches type, if not error
// Note: if either the value or default is in conflict with the type then this is an error
- tempType, errorParser = ResolveParamTypeFromValue(paramName, param.Value, filePath)
-
- // if we do not have a value or default, but have a type, find its default and use it for the value
- if param.Type != "" && !isValidParameterType(param.Type) {
- // TODO() - move string to i18n
- msgs := []string{"Parameter [" + paramName + "] has an invalid Type. [" + param.Type + "]"}
- return value, utils.NewParserErr(filePath, nil, msgs)
- } else if param.Type == "" {
- param.Type = tempType
+ valueType, errorParser = ResolveParamTypeFromValue(paramName, param.Value, filePath)
+
+ // if we have a declared parameter Type, assure that it is a known value
+ if param.Type != "" {
+ if !isValidParameterType(param.Type) {
+ // TODO() - move string to i18n
+ msgs := []string{"Parameter [" + paramName + "] has an invalid Type. [" + param.Type + "]"}
+ return param.Value, utils.NewParserErr(filePath, nil, msgs)
+ }
+ } else {
+ // if we do not have a value for the Parameter Type, use the Parameter Value's Type
+ param.Type = valueType
}
+
+ // TODO{} if the declared and actual parameter type conflict, generate TypeMismatch error
+ //if param.Type != valueType{
+ // errorParser = utils.NewParameterTypeMismatchError("", param.Type, valueType )
+ //}
+ } else {
+ msgs := []string{"Parameter [" + paramName + "] is not multiline format."}
+ return param.Value, utils.NewParserErr(filePath, nil, msgs)
}
- // Make sure the parameter's value is a valid, non-empty string and startsWith '$" (dollar) sign
- value = utils.GetEnvVar(param.Value)
- // JSON - Handle both cases, where value 1) is a string containing JSON, 2) is a map of JSON
+ return param.Value, errorParser
+}
- // Case 1: if user set parameter type to 'json' and the value's type is a 'string'
- if str, ok := value.(string); ok && param.Type == "json" {
- var parsed interface{}
- err := json.Unmarshal([]byte(str), &parsed)
- if err == nil {
- fmt.Printf("EXIT: Parameter type=[%v] value=[%v]\n", param.Type, parsed)
- return parsed, err
+
+/*
+ resolveJSONParameter assure JSON data is converted to a map[string]{interface*} type.
+
+ This function handles the forms JSON data appears in:
+ 1) a string containing JSON, which needs to be parsed into map[string]interface{}
+ 2) is a map of JSON (but not a map[string]interface{}
+ */
+func resolveJSONParameter(paramName string, param *Parameter, value interface{}, filePath string) (interface{}, error) {
+ var errorParser error
+
+ if param.Type == "json" {
+ // Case 1: if user set parameter type to 'json' and the value's type is a 'string'
+ if str, ok := value.(string); ok {
+ var parsed interface{}
+ errParser := json.Unmarshal([]byte(str), &parsed)
+ if errParser == nil {
+ //fmt.Printf("EXIT: Parameter [%s] type=[%v] value=[%v]\n", paramName, param.Type, parsed)
+ return parsed, errParser
+ }
}
+
+ // Case 2: value contains a map of JSON
+ // We must make sure the map type is map[string]interface{}; otherwise we cannot
+ // marshall it later on to serialize in the body of an HTTP request.
+ if( param.Value != nil && reflect.TypeOf(param.Value).Kind() == reflect.Map ) {
+ if _, ok := param.Value.(map[interface{}]interface{}); ok {
+ var temp map[string]interface{} =
+ utils.ConvertInterfaceMap(param.Value.(map[interface{}]interface{}))
+ //fmt.Printf("EXIT: Parameter [%s] type=[%v] value=[%v]\n", paramName, param.Type, temp)
+ return temp, errorParser
+ }
+ } // else TODO{}
+ } else {
+ msgs := []string{"Parameter [" + paramName + "] is not JSON format."}
+ return param.Value, utils.NewParserErr(filePath, nil, msgs)
}
- // Case 2: value contains a map of JSON
- // We must make sure the map type is map[string]interface{}; otherwise we cannot
- // marshall it later on to serialize in the body of an HTTP request.
- if( param.Value != nil && reflect.TypeOf(param.Value).Kind() == reflect.Map ) {
- if _, ok := param.Value.(map[interface{}]interface{}); ok {
- var temp map[string]interface{} =
- utils.ConvertInterfaceMap(param.Value.(map[interface{}]interface{}))
- fmt.Printf("EXIT: Parameter type=[%v] value=[%v]\n", param.Type, temp)
- return temp, errorParser
- }
+ return param.Value, errorParser
+}
+
+/*
+ ResolveParameter assures that the Parameter structure's values are correctly filled out for
+ further processing. This includes special processing for
+
+ - single-line format parameters
+ - deriving missing param.Type from param.Value
+ - resolving case where param.Value contains a valid Parameter type name
+ - multi-line format parameters:
+ - assures that param.Value is set while taking into account param.Default
+ - validating param.Type
+
+ Note: parameter values may set later (overridden) by an (optional) Deployment file
+
+ */
+func ResolveParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
+
+ var errorParser error
+ // default parameter value to empty string
+ var value interface{} = ""
+
+ // Trace Parameter struct before any resolution
+ //dumpParameter(paramName, param, "BEFORE")
+
+ // Parameters can be single OR multi-line declarations which must be processed/validated differently
+ if !param.multiline {
+
+ // This function will assure that param.Value and param.Type are correctly set
+ value, errorParser = resolveSingleLineParameter(paramName, param, filePath)
+
+ } else {
+
+ value, errorParser = resolveMultiLineParameter(paramName, param, filePath)
}
- // Default to an empty string, do NOT error/terminate as Value may be provided later bu a Deployment file.
+ // String value pre-processing (interpolation)
+ // See if we have any Environment Variable replacement within the parameter's value
+
+ // Make sure the parameter's value is a valid, non-empty string
+ if ( param.Value != nil && param.Type == "string") {
+ // perform $ notation replacement on string if any exist
+ value = utils.GetEnvVar(param.Value)
+ }
+
+ // JSON - Handle both cases, where value 1) is a string containing JSON, 2) is a map of JSON
+ if param.Type == "json" {
+ value, errorParser = resolveJSONParameter(paramName, param, value, filePath)
+ }
+
+ // Default value to zero value for the Type
+ // Do NOT error/terminate as Value may be provided later by a Deployment file.
if value == nil {
value = getTypeDefaultValue(param.Type)
// @TODO(): Need warning message here to warn of default usage, support for warnings (non-fatal)
+ //msgs := []string{"Parameter [" + paramName + "] is not multiline format."}
+ //return param.Value, utils.NewParserErr(filePath, nil, msgs)
}
// Trace Parameter struct after resolution
//dumpParameter(paramName, param, "AFTER")
- //fmt.Printf("EXIT: Parameter type=[%v] value=[%v]\n", param.Type, value)
-
+ //fmt.Printf("EXIT: Parameter [%s] type=[%v] value=[%v]\n", paramName, param.Type, value)
return value, errorParser
}
@@ -912,6 +1050,7 @@ func dumpParameter(paramName string, param *Parameter, separator string) {
if param != nil {
fmt.Printf("\t\tParameter.Description: [%s]\n", param.Description)
fmt.Printf("\t\tParameter.Type: [%s]\n", param.Type)
+ fmt.Printf("\t\t--> Actual Type: [%T]\n", param.Value)
fmt.Printf("\t\tParameter.Value: [%v]\n", param.Value)
fmt.Printf("\t\tParameter.Default: [%v]\n", param.Default)
}
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index 39c1a6a..0aef582 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -223,23 +223,8 @@ func TestUnmarshalForMissingPackage(t *testing.T) {
/*
Test 7: validate manifest_parser:ParseManifest() method for multiline parameters
- manifest_parser should be able to parse all different mutliline combinations of
- inputs section including:
-
- case 1: value only
- param:
- value: <value>
- case 2: type only
- param:
- type: <type>
- case 3: type and value only
- param:
- type: <type>
- value: <value>
- case 4: default value
- param:
- type: <type>
- default: <default value>
+ manifest_parser should be able to parse all different multiline combinations of
+ inputs section.
*/
func TestParseManifestForMultiLineParams(t *testing.T) {
// manifest file is located under ../tests folder
@@ -337,16 +322,18 @@ func TestParseManifestForMultiLineParams(t *testing.T) {
}
}
- // validate outputs
- // output payload is of type string and has a description
- if payload, ok := action.Outputs["payload"]; ok {
- p := payload.(map[interface{}]interface{})
- expectedResult = "string"
- actualResult = p["type"].(string)
- assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
- expectedResult = "parameter dump"
- actualResult = p["description"].(string)
- assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
+ // validate Outputs from this action
+ for output, param := range action.Outputs {
+ switch output {
+ case "payload":
+ expectedType := "string"
+ actualType := param.Type
+ assert.Equal(t, expectedType, actualType, "Expected Type: " + expectedType + ", but got: " + actualType)
+ expectedDesc := "parameter dump"
+ actualDesc := param.Description
+ assert.Equal(t, expectedDesc, actualDesc, "Expected " + expectedDesc + " but got " + actualDesc)
+
+ }
}
}
}
@@ -387,7 +374,7 @@ func TestParseManifestForSingleLineParams(t *testing.T) {
actualResult = strconv.FormatInt(int64(len(action.Inputs)), 10)
assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
- // validate inputs to this action
+ // validate Inputs to this action
for input, param := range action.Inputs {
switch input {
case "param_simple_string":
@@ -445,16 +432,18 @@ func TestParseManifestForSingleLineParams(t *testing.T) {
}
}
- // validate outputs
- // output payload is of type string and has a description
- if payload, ok := action.Outputs["payload"]; ok {
- p := payload.(map[interface{}]interface{})
- expectedResult = "string"
- actualResult = p["type"].(string)
- assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
- expectedResult = "parameter dump"
- actualResult = p["description"].(string)
- assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
+ // validate Outputs from this action
+ for output, param := range action.Outputs {
+ switch output {
+ case "payload":
+ expectedResult = "string"
+ actualResult = param.Type
+ assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
+
+ expectedResult = "parameter dump"
+ actualResult = param.Description
+ assert.Equal(t, expectedResult, actualResult, "Expected " + expectedResult + " but got " + actualResult)
+ }
}
}
}
@@ -530,6 +519,7 @@ func TestComposeActionsForInvalidRuntime(t *testing.T) {
_, err := p.ComposeActionsFromAllPackages(m, tmpfile.Name())
// (TODO) uncomment the following test case after issue #307 is fixed
// (TODO) its failing right now as we are lacking check on invalid runtime
+ // TODO() https://github.com/apache/incubator-openwhisk-wskdeploy/issues/608
// assert.NotNil(t, err, "Invalid runtime, ComposeActions should report an error")
// (TODO) remove this print statement after uncommenting above test case
fmt.Println(err)
@@ -545,7 +535,12 @@ func TestComposeActionsForSingleLineParams(t *testing.T) {
manifestFile := "../tests/dat/manifest_validate_singleline_params.yaml"
// read and parse manifest.yaml file
p := NewYAMLParser()
- m, _ := p.ParseManifest(manifestFile)
+ m, err := p.ParseManifest(manifestFile)
+
+ if err != nil {
+ assert.Fail(t, "Failed to parse manifest: " + manifestFile )
+ }
+
actions, err := p.ComposeActionsFromAllPackages(m, manifestFile)
if err == nil {
@@ -699,7 +694,12 @@ func TestComposeActionsForMultiLineParams(t *testing.T) {
manifestFile := "../tests/dat/manifest_validate_multiline_params.yaml"
// read and parse manifest.yaml file
p := NewYAMLParser()
- m, _ := p.ParseManifest(manifestFile)
+ m, err := p.ParseManifest(manifestFile)
+
+ if err != nil {
+ assert.Fail(t, "Failed to parse manifest: " + manifestFile )
+ }
+
actions, err := p.ComposeActionsFromAllPackages(m, manifestFile)
if err == nil {
@@ -954,7 +954,11 @@ func TestParseManifestForJSONParams(t *testing.T) {
// manifest file is located under ../tests folder
manifestFile := "../tests/dat/manifest_validate_json_params.yaml"
// read and parse manifest.yaml file
- m, _ := NewYAMLParser().ParseManifest(manifestFile)
+ m, err := NewYAMLParser().ParseManifest(manifestFile)
+
+ if err != nil {
+ assert.Fail(t, "Failed to parse manifest: " + manifestFile )
+ }
// validate package name should be "validate"
packageName := "validate_json"
@@ -1017,12 +1021,15 @@ func TestParseManifestForJSONParams(t *testing.T) {
}
}
- // TODO{} We do not yet support json outputs
- // validate outputs
- // output payload is of type string and has a description
- //if payload, ok := action.Outputs["fellowship"]; ok {
- // p := payload.(map[interface{}]interface{})
- //}
+ // validate Outputs from this action
+ for output, param := range action.Outputs {
+ switch output {
+ case "fellowship":
+ expectedType := "json"
+ actualType := param.Type
+ assert.Equal(t, expectedType, actualType, "Expected Type: " + expectedType + ", but got: " + actualType)
+ }
+ }
}
}
@@ -1108,30 +1115,15 @@ func TestComposeSequences(t *testing.T) {
}
func TestComposeTriggers(t *testing.T) {
- data := `package:
- name: helloworld
- triggers:
- trigger1:
- inputs:
- name: string
- place: string
- trigger2:
- feed: myfeed
- inputs:
- name: myname
- place: myplace`
- tmpfile, err := _createTmpfile(data, "manifest_parser_test_")
+ // read and parse manifest.yaml file located under ../tests folder
+ manifestFile := "../tests/dat/manifest_data_compose_triggers.yaml"
+ p := NewYAMLParser()
+ m, err := p.ParseManifest(manifestFile)
if err != nil {
- assert.Fail(t, "Failed to create temp file")
+ assert.Fail(t, "Failed to parse manifest: " + manifestFile )
}
- defer func() {
- tmpfile.Close()
- os.Remove(tmpfile.Name())
- }()
- // read and parse manifest.yaml file
- p := NewYAMLParser()
- m, _ := p.ParseManifest(tmpfile.Name())
- triggerList, err := p.ComposeTriggersFromAllPackages(m, tmpfile.Name())
+
+ triggerList, err := p.ComposeTriggersFromAllPackages(m, manifestFile)
if err != nil {
assert.Fail(t, "Failed to compose trigger")
}
@@ -1315,65 +1307,42 @@ func TestComposeDependencies(t *testing.T) {
}
}
-func TestInvalidKeyManifestYaml(t *testing.T) {
- data := `package:
- name: helloWorldTriggerRule
- version: 1.0
- invalidKey: test
- license: Apache-2.0`
- tmpfile, err := _createTmpfile(data, "manifest_parser_test_")
- if err != nil {
- assert.Fail(t, "Failed to create temp file")
- }
- defer func() {
- tmpfile.Close()
- os.Remove(tmpfile.Name())
- }()
+func TestBadYAMLInvalidPackageKeyInManifest(t *testing.T) {
+ // read and parse manifest.yaml file located under ../tests folder
p := NewYAMLParser()
- _, err = p.ParseManifest(tmpfile.Name())
+ _, err := p.ParseManifest("../tests/dat/manifest_bad_yaml_invalid_package_key.yaml")
+
assert.NotNil(t, err)
// go-yaml/yaml prints the wrong line number for mapping values. It should be 4.
assert.Contains(t, err.Error(), "line 2: field invalidKey not found in struct parsers.Package")
}
-func TestMappingValueManifestYaml(t *testing.T) {
- data := `package:
- name: helloWorldTriggerRule
- version: 1.0
- license: Apache-2.0
- actions: test`
- tmpfile, err := _createTmpfile(data, "manifest_parser_test_")
- if err != nil {
- assert.Fail(t, "Failed to create temp file")
- }
- defer func() {
- tmpfile.Close()
- os.Remove(tmpfile.Name())
- }()
+func TestBadYAMLInvalidKeyMappingValueInManifest(t *testing.T) {
+ // read and parse manifest.yaml file located under ../tests folder
p := NewYAMLParser()
- _, err = p.ParseManifest(tmpfile.Name())
+ _, err := p.ParseManifest("../tests/dat/manifest_bad_yaml_invalid_key_mapping_value.yaml")
+
assert.NotNil(t, err)
// go-yaml/yaml prints the wrong line number for mapping values. It should be 5.
assert.Contains(t, err.Error(), "line 4: mapping values are not allowed in this context")
}
-func TestMissingRootValueManifestYaml(t *testing.T) {
- data := `actions:
- helloNodejs:
- function: actions/hello.js`
- tmpfile, err := _createTmpfile(data, "manifest_parser_test_")
- if err != nil {
- assert.Fail(t, "Failed to create temp file")
- }
- defer func() {
- tmpfile.Close()
- os.Remove(tmpfile.Name())
- }()
+func TestBadYAMLMissingRootKeyInManifest(t *testing.T) {
+ // read and parse manifest.yaml file located under ../tests folder
p := NewYAMLParser()
- _, err = p.ParseManifest(tmpfile.Name())
+ _, err := p.ParseManifest("../tests/dat/manifest_bad_yaml_missing_root_key.yaml")
+
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "line 1: field actions not found in struct parsers.YAML")
+}
+
+func TestBadYAMLInvalidCommentInManifest(t *testing.T) {
+ // read and parse manifest.yaml file located under ../tests folder
+ p := NewYAMLParser()
+ _, err := p.ParseManifest("../tests/dat/manifest_bad_yaml_invalid_comment.yaml")
+ assert.NotNil(t, err)
+ assert.Contains(t, err.Error(), "line 13: could not find expected ':'")
}
// validate manifest_parser:Unmarshal() method for package in manifest YAML
@@ -1552,7 +1521,7 @@ func TestParseYAML_param(t *testing.T) {
panic(err)
}
- packageName := "manifest6"
+ packageName := "validateParams"
assert.Equal(t, 1, len(manifest.Packages[packageName].Actions), "Get action list failed.")
for action_name := range manifest.Packages[packageName].Actions {
diff --git a/parsers/yamlparser.go b/parsers/yamlparser.go
index 4b7a2db..974ce5b 100644
--- a/parsers/yamlparser.go
+++ b/parsers/yamlparser.go
@@ -58,7 +58,7 @@ type Action struct {
Namespace string `yaml:"namespace"` //used in deployment.yaml
Credential string `yaml:"credential"` //used in deployment.yaml
Inputs map[string]Parameter `yaml:"inputs"` //used in both manifest.yaml and deployment.yaml
- Outputs map[string]interface{} `yaml:"outputs"` //used in manifest.yaml
+ Outputs map[string]Parameter `yaml:"outputs"` //used in manifest.yaml
//mapping to wsk.Action.Name
Name string
Annotations map[string]interface{} `yaml:"annotations,omitempty"`
diff --git a/tests/dat/manifest_bad_yaml_2.yaml b/tests/dat/manifest_bad_yaml_2.yaml
deleted file mode 100644
index bd4d895..0000000
--- a/tests/dat/manifest_bad_yaml_2.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-package:
- name: helloWorldTriggerRule
- version: 1.0
- invalidKey: test
- license: Apache-2.0
- invalidKey2: test
-
-# go-yaml/yaml prints the wrong line number for mapping values. It should be 4.
diff --git a/tests/dat/manifest_bad_yaml_3.yaml b/tests/dat/manifest_bad_yaml_3.yaml
deleted file mode 100644
index bcffb6e..0000000
--- a/tests/dat/manifest_bad_yaml_3.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-packages:
- helloWorldTriggerRule:
- version: 1.0
- license: Apache-2.0
- actions: test
-
-# go-yaml/yaml prints the wrong line number for mapping values. It should be 5.
-
diff --git a/tests/dat/manifest_bad_yaml_4.yaml b/tests/dat/manifest_bad_yaml_4.yaml
deleted file mode 100644
index da73f3e..0000000
--- a/tests/dat/manifest_bad_yaml_4.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-actions:
- helloNodejs:
- function: actions/hello.js
-
-# go-yaml/yaml prints the wrong line number for mapping values. It should be 5.
-
diff --git a/tests/dat/manifest_bad_yaml.yaml b/tests/dat/manifest_bad_yaml_invalid_comment.yaml
similarity index 89%
rename from tests/dat/manifest_bad_yaml.yaml
rename to tests/dat/manifest_bad_yaml_invalid_comment.yaml
index e4fcf70..e1330e5 100644
--- a/tests/dat/manifest_bad_yaml.yaml
+++ b/tests/dat/manifest_bad_yaml_invalid_comment.yaml
@@ -1,5 +1,5 @@
packages:
- BadYAML:
+ testBadYAMLInvalidCommentInManifest:
actions:
# helloworld action in NodeJS
helloNodejs:
diff --git a/tests/dat/manifest_bad_yaml_invalid_key_mapping_value.yaml b/tests/dat/manifest_bad_yaml_invalid_key_mapping_value.yaml
new file mode 100644
index 0000000..5d0cd70
--- /dev/null
+++ b/tests/dat/manifest_bad_yaml_invalid_key_mapping_value.yaml
@@ -0,0 +1,8 @@
+packages:
+ testBadYAMLInvalidKeyMappingValueInManifest:
+ version: 1.0
+ license: Apache-2.0
+ actions: test
+
+# go-yaml/yaml "line 4: mapping values are not allowed in this context".
+
diff --git a/tests/dat/manifest_bad_yaml_invalid_package_key.yaml b/tests/dat/manifest_bad_yaml_invalid_package_key.yaml
new file mode 100644
index 0000000..2d74f7a
--- /dev/null
+++ b/tests/dat/manifest_bad_yaml_invalid_package_key.yaml
@@ -0,0 +1,7 @@
+package:
+ name: testBadYAMLInvalidPackageKeyInManifest
+ version: 1.0
+ invalidKey: test
+ license: Apache-2.0
+
+# go-yaml/yaml "line 2: field invalidKey not found in struct parsers.Package".
diff --git a/tests/dat/manifest_bad_yaml_missing_root_key.yaml b/tests/dat/manifest_bad_yaml_missing_root_key.yaml
new file mode 100644
index 0000000..b8d3d0b
--- /dev/null
+++ b/tests/dat/manifest_bad_yaml_missing_root_key.yaml
@@ -0,0 +1,6 @@
+actions:
+ testBadYAMLMissingRootKeyInManifest:
+ function: actions/hello.js
+
+# go-yaml/yaml "line 1: field actions not found in struct parsers.YAML".
+
diff --git a/tests/dat/manifest_data_compose_triggers.yaml b/tests/dat/manifest_data_compose_triggers.yaml
new file mode 100644
index 0000000..1d99fe9
--- /dev/null
+++ b/tests/dat/manifest_data_compose_triggers.yaml
@@ -0,0 +1,12 @@
+package:
+ name: trigger_compose
+ triggers:
+ trigger1:
+ inputs:
+ name: string
+ place: string
+ trigger2:
+ feed: myfeed
+ inputs:
+ name: myname
+ place: myplace
diff --git a/tests/dat/manifest_validate_params.yaml b/tests/dat/manifest_validate_params.yaml
index 584b7ed..0bd226b 100644
--- a/tests/dat/manifest_validate_params.yaml
+++ b/tests/dat/manifest_validate_params.yaml
@@ -1,5 +1,5 @@
packages:
- manifest6:
+ validateParams:
actions:
action1:
inputs:
diff --git a/tests/src/integration/common/wskdeploy.go b/tests/src/integration/common/wskdeploy.go
index b142789..190353a 100644
--- a/tests/src/integration/common/wskdeploy.go
+++ b/tests/src/integration/common/wskdeploy.go
@@ -200,7 +200,7 @@ func (wskdeploy *Wskdeploy) GetDeploymentObjects(manifestPath string, deployment
utils.Rts = utils.DefaultRts
}
- //invokce ConstructDeploymentPlan to create the in memory objects for deployment
+ //invoke ConstructDeploymentPlan to create the in memory objects for deployment
err = deployer.ConstructDeploymentPlan()
if err != nil {
return nil,err
diff --git a/utils/flags.go b/utils/flags.go
index 03390ad..7b35856 100644
--- a/utils/flags.go
+++ b/utils/flags.go
@@ -33,8 +33,8 @@ var Flags struct {
UseDefaults bool
UseInteractive bool
Strict bool // strict flag to support user defined runtime version.
- Key string
- Cert string
+ Key string
+ Cert string
//action flag definition
//from go cli
diff --git a/utils/misc_test.go b/utils/misc_test.go
index 638468c..94203ad 100644
--- a/utils/misc_test.go
+++ b/utils/misc_test.go
@@ -82,20 +82,20 @@ func TestDependencies(t *testing.T) {
func TestParseOpenWhisk(t *testing.T) {
openwhiskHost := "https://openwhisk.ng.bluemix.net"
- openwhisk, err := ParseOpenWhisk(openwhiskHost)
- assert.Equal(t, nil, err, "parse openwhisk info error happened.")
- converted := ConvertToMap(openwhisk)
- assert.Equal(t, 1, len(converted["nodejs"]), "not expected length")
- assert.Equal(t, 1, len(converted["php"]), "not expected length")
- assert.Equal(t, 1, len(converted["java"]), "not expected length")
- assert.Equal(t, 3, len(converted["python"]), "not expected length")
- assert.Equal(t, 2, len(converted["swift"]), "not expected length")
+ openwhisk, err := ParseOpenWhisk(openwhiskHost)
+ assert.Equal(t, nil, err, "parse openwhisk info error happened.")
+ converted := ConvertToMap(openwhisk)
+ assert.Equal(t, 1, len(converted["nodejs"]), "not expected length")
+ assert.Equal(t, 1, len(converted["php"]), "not expected length")
+ assert.Equal(t, 1, len(converted["java"]), "not expected length")
+ assert.Equal(t, 3, len(converted["python"]), "not expected length")
+ assert.Equal(t, 2, len(converted["swift"]), "not expected length")
}
func TestNewZipWritter(t *testing.T) {
- filePath := "../tests/src/integration/zipaction/actions/cat"
- zipName := filePath + ".zip"
- err := NewZipWritter(filePath, zipName).Zip()
- defer os.Remove(zipName)
- assert.Equal(t, nil, err, "zip folder error happened.")
+ filePath := "../tests/src/integration/zipaction/actions/cat"
+ zipName := filePath + ".zip"
+ err := NewZipWritter(filePath, zipName).Zip()
+ defer os.Remove(zipName)
+ assert.Equal(t, nil, err, "zip folder error happened.")
}
diff --git a/utils/wskdeployerror.go b/utils/wskdeployerror.go
index d699184..6613384 100644
--- a/utils/wskdeployerror.go
+++ b/utils/wskdeployerror.go
@@ -29,6 +29,7 @@ const (
INVALID_YAML_INPUT = "Invalid input of Yaml file"
INVALID_YAML_FORMAT = "Invalid input of Yaml format"
OPENWHISK_CLIENT_ERROR = "OpenWhisk Client Error"
+ PARAMETER_TYPE_MISMATCH = "Parameter type mismatch error"
MANIFEST_NOT_FOUND = INVALID_YAML_INPUT // TODO{} This should be a unique message.
UNKNOWN = "Unknown"
UNKNOWN_VALUE = "Unknown value"
@@ -89,7 +90,10 @@ func NewErrorManifestFileNotFound(errMessage string) *ErrorManifestFileNotFound
}
func (e *ErrorManifestFileNotFound) Error() string {
- return fmt.Sprintf("%s [%d]: %s =====> %s\n", e.FileName, e.LineNum, e.errorType, e.Message)
+ if e.errorType == "" {
+ return fmt.Sprintf("%s [%d]: %s\n", e.FileName, e.LineNum, e.Message)
+ }
+ return fmt.Sprintf("%s [%d]: %s ==> %s\n", e.FileName, e.LineNum, e.errorType, e.Message)
}
type InputYamlFileError struct {
@@ -113,6 +117,9 @@ func (e *InputYamlFileError) SetErrorType(errorType string) {
}
func (e *InputYamlFileError) Error() string {
+ if e.errorType == "" {
+ return fmt.Sprintf("%s [%d]: %s\n", e.FileName, e.LineNum, e.Message)
+ }
return fmt.Sprintf("%s [%d]: %s %s\n", e.FileName, e.LineNum, e.errorType, e.Message)
}
@@ -199,3 +206,33 @@ func (e *ParserErr) Error() string {
}
return fmt.Sprintf("\n==> %s [%d]: Failed to parse the yaml file: %s: \n%s", fn, e.LineNum, e.YamlFile, strings.Join(result, "\n"))
}
+
+type ParameterTypeMismatchError struct {
+ BaseErr
+ errorType string
+ expectedType string
+ actualType string
+}
+
+func (e *ParameterTypeMismatchError) Error() string {
+ if e.errorType == "" {
+ return fmt.Sprintf("%s [%d]: %s\n", e.FileName, e.LineNum, e.Message)
+ }
+ return fmt.Sprintf("%s [%d]: %s ==> %s\n", e.FileName, e.LineNum, e.errorType, e.Message)
+}
+
+func NewParameterTypeMismatchError(errMessage string, expectedType string, actualType string) *ParameterTypeMismatchError {
+ _, fn, lineNum, _ := runtime.Caller(1)
+ var err = &ParameterTypeMismatchError{
+ // TODO{} add i18n
+ //errorType: wski18n.T(PARAMETER_TYPE_MISMATCH),
+ errorType: PARAMETER_TYPE_MISMATCH,
+ expectedType: expectedType,
+ actualType: actualType,
+ }
+
+ err.SetFileName(filepath.Base(fn))
+ err.SetLineNum(lineNum)
+ err.SetMessage(errMessage)
+ return err
+}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services