You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ho...@apache.org on 2017/11/16 18:53:22 UTC

[incubator-openwhisk-wskdeploy] branch master updated: Add unit tests for wskdeploy custom error types. (#632)

This is an automated email from the ASF dual-hosted git repository.

houshengbo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-wskdeploy.git


The following commit(s) were added to refs/heads/master by this push:
     new b5d1d3a  Add unit tests for wskdeploy custom error types. (#632)
b5d1d3a is described below

commit b5d1d3acb81caebddb5d0cf8256602667b998ed1
Author: Matt Rutkowski <mr...@us.ibm.com>
AuthorDate: Thu Nov 16 12:53:20 2017 -0600

    Add unit tests for wskdeploy custom error types. (#632)
    
    * Refine custom errors, update unit tests and affected files.
    
    * Introduce base FileReadError.
    
    * Adjust custom error struct inheritance.
    
    * Add last three parser error unit tests.
    
    * Add last three parser error unit tests.
    
    * Add last three parser error unit tests.
    
    * Fix errors due to custom error renaming.
    
    * Add newline in front of YAML error messages.
    
    * Updated YAMLParserError to include multiple Line #s and messages.
    
    * Updated YAMLParserError to include multiple Line #s and messages.
    
    * Updated YAMLParserError to include multiple Line #s and messages.
    
    * Disambigute UNKNOWN constant as LINE_UNKNOWN.
    
    * Disambigute UNKNOWN constant as LINE_UNKNOWN.
---
 cmd/root.go                        |   8 +-
 deployers/deploymentreader.go      |   9 +-
 deployers/deploymentreader_test.go |   1 +
 deployers/filesystemreader.go      |   6 +-
 deployers/manifestreader.go        |  40 +++--
 deployers/servicedeployer.go       |  11 +-
 parsers/deploy_parser.go           |   4 +-
 parsers/manifest_parser.go         |   8 +-
 parsers/manifest_parser_test.go    |   2 +-
 parsers/parameters.go              | 122 +++++++++----
 utils/errorhandlers.go             |  23 ---
 utils/wskdeployerror.go            | 351 ++++++++++++++++++++-----------------
 utils/wskdeployerror_test.go       | 184 +++++++++++++++++++
 13 files changed, 516 insertions(+), 253 deletions(-)

diff --git a/cmd/root.go b/cmd/root.go
index 4831c7b..df579cf 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -180,7 +180,7 @@ func Deploy() error {
 			errString := wski18n.T("Missing {{.yaml}}/{{.yml}} file. Manifest file not found at path {{.projectPath}}.\n",
 				map[string]interface{}{"yaml": utils.ManifestFileNameYaml, "yml": utils.ManifestFileNameYml,
 					"projectPath": projectPath})
-			return utils.NewErrorManifestFileNotFound(errString)
+			return utils.NewErrorManifestFileNotFound(projectPath, errString)
 		}
 		whisk.Debug(whisk.DbgInfo, stdout)
 	}
@@ -239,7 +239,7 @@ func Deploy() error {
 		errString := wski18n.T("Manifest file is not found at the path [{{.filePath}}].\n",
 			map[string]interface{}{"filePath": utils.Flags.ManifestPath})
 		whisk.Debug(whisk.DbgError, errString)
-		return utils.NewErrorManifestFileNotFound(errString)
+		return utils.NewErrorManifestFileNotFound(utils.Flags.ManifestPath, errString)
 	}
 
 }
@@ -273,7 +273,7 @@ func Undeploy() error {
 			errString := wski18n.T("Missing {{.yaml}}/{{.yml}} file. Manifest file not found at path {{.projectPath}}.\n",
 				map[string]interface{}{"yaml": utils.ManifestFileNameYaml, "yml": utils.ManifestFileNameYml,
 					"projectPath": projectPath})
-			return utils.NewErrorManifestFileNotFound(errString)
+			return utils.NewErrorManifestFileNotFound(projectPath, errString)
 		}
 		whisk.Debug(whisk.DbgInfo, stdout)
 	}
@@ -330,6 +330,6 @@ func Undeploy() error {
 		errString := wski18n.T("Manifest file is not found at the path [{{.filePath}}].\n",
 			map[string]interface{}{"filePath": utils.Flags.ManifestPath})
 		whisk.Debug(whisk.DbgError, errString)
-		return utils.NewErrorManifestFileNotFound(errString)
+		return utils.NewErrorManifestFileNotFound(utils.Flags.ManifestPath, errString)
 	}
 }
diff --git a/deployers/deploymentreader.go b/deployers/deploymentreader.go
index 21dd39e..af99451 100644
--- a/deployers/deploymentreader.go
+++ b/deployers/deploymentreader.go
@@ -145,7 +145,8 @@ func (reader *DeploymentReader) bindPackageInputsAndAnnotations() error {
 				}
 				if !keyExistsInManifest {
 					err := wski18n.T("Annotation key \"" + name + "\" does not exist in manifest file but specified in deployment file.")
-					return utils.NewYAMLFormatError(err)
+					// TODO see if we can pass in the YAML file path on first parameter
+					return utils.NewYAMLFileFormatError(utils.LINE_UNKNOWN, err)
 				}
 			}
 		}
@@ -234,7 +235,8 @@ func (reader *DeploymentReader) bindActionInputsAndAnnotations() error {
 					}
 					if !keyExistsInManifest {
 						err := wski18n.T("Annotation key \"" + name + "\" does not exist in manifest file but specified in deployment file.")
-						return utils.NewYAMLFormatError(err)
+						// TODO see if we can pass in the YAML file path on first parameter
+						return utils.NewYAMLFileFormatError(utils.LINE_UNKNOWN, err)
 					}
 				}
 			}
@@ -320,7 +322,8 @@ func (reader *DeploymentReader) bindTriggerInputsAndAnnotations() error {
 					}
 					if !keyExistsInManifest {
 						err := wski18n.T("Annotation key \"" + name + "\" does not exist in manifest file but specified in deployment file.")
-						return utils.NewYAMLFormatError(err)
+						// TODO see if we can pass in the YAML file path on first parameter
+						return utils.NewYAMLFileFormatError(utils.LINE_UNKNOWN, err)
 					}
 				}
 			}
diff --git a/deployers/deploymentreader_test.go b/deployers/deploymentreader_test.go
index a4a518e..2c2aeb1 100644
--- a/deployers/deploymentreader_test.go
+++ b/deployers/deploymentreader_test.go
@@ -45,6 +45,7 @@ func TestDeploymentReader_HandleYaml(t *testing.T) {
 	assert.NotNil(t, dr.DeploymentDescriptor.GetProject().Packages["GitHubCommits"], "DeploymentReader handle deployment yaml failed.")
 }
 
+// TODO remove this unused test?
 func TestDeployerCheck(t *testing.T) {
 	sd := NewServiceDeployer()
 	sd.DeploymentPath = "../tests/usecases/badyaml/deployment.yaml"
diff --git a/deployers/filesystemreader.go b/deployers/filesystemreader.go
index 0635bc5..f99a379 100644
--- a/deployers/filesystemreader.go
+++ b/deployers/filesystemreader.go
@@ -56,7 +56,7 @@ func (reader *FileSystemReader) ReadProjectDirectory(manifest *parsers.YAML) ([]
 		if fpath != reader.serviceDeployer.ProjectPath {
 			pathCount, err := reader.getFilePathCount(fpath)
             if err != nil {
-                return utils.NewYAMLFileReadError(err.Error())
+                return utils.NewFileReadError(fpath, err.Error())
             }
 
 			if !f.IsDir() {
@@ -76,7 +76,7 @@ func (reader *FileSystemReader) ReadProjectDirectory(manifest *parsers.YAML) ([]
 					if foundFile == true {
 						_, action, err := reader.CreateActionFromFile(reader.serviceDeployer.ManifestPath, fpath)
                         if err != nil {
-                            return utils.NewYAMLFileReadError(err.Error())
+                            return utils.NewFileReadError(fpath, err.Error())
                         }
 
 						var record utils.ActionRecord
@@ -127,7 +127,7 @@ func (reader *FileSystemReader) CreateActionFromFile(manipath, filePath string)
 
 		dat, err := new(utils.ContentReader).LocalReader.ReadLocal(filePath)
         if err != nil {
-            return name, action, utils.NewYAMLFileReadError(err.Error())
+            return name, action, utils.NewFileReadError(filePath, err.Error())
         }
 
 		action.Exec = new(whisk.Exec)
diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index 1950ca8..cf6ced1 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -46,7 +46,7 @@ func (deployer *ManifestReader) ParseManifest() (*parsers.YAML, *parsers.YAMLPar
 	manifest, err := manifestParser.ParseManifest(dep.ManifestPath)
 
 	if err != nil {
-		return manifest, manifestParser, utils.NewYAMLFileReadError(err.Error())
+		return manifest, manifestParser, utils.NewFileReadError(dep.ManifestPath, err.Error())
 	}
 	return manifest, manifestParser, nil
 }
@@ -54,7 +54,7 @@ func (deployer *ManifestReader) ParseManifest() (*parsers.YAML, *parsers.YAMLPar
 func (reader *ManifestReader) InitRootPackage(manifestParser *parsers.YAMLParser, manifest *parsers.YAML, ma whisk.KeyValue) error {
 	packages, err := manifestParser.ComposeAllPackages(manifest, reader.serviceDeployer.ManifestPath, ma)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifest.Filepath, err.Error())
 	}
 	reader.SetPackage(packages)
 
@@ -65,64 +65,66 @@ func (reader *ManifestReader) InitRootPackage(manifestParser *parsers.YAMLParser
 func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestParser *parsers.YAMLParser, manifest *parsers.YAML, ma whisk.KeyValue) error {
 
 	var err error
+	var manifestName = manifest.Filepath
+
 	deps, err := manifestParser.ComposeDependenciesFromAllPackages(manifest, deployer.serviceDeployer.ProjectPath, deployer.serviceDeployer.ManifestPath)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, ma)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	sequences, err := manifestParser.ComposeSequencesFromAllPackages(deployer.serviceDeployer.ClientConfig.Namespace, manifest, ma)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	triggers, err := manifestParser.ComposeTriggersFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, ma)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	rules, err := manifestParser.ComposeRulesFromAllPackages(manifest)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	apis, err := manifestParser.ComposeApiRecordsFromAllPackages(manifest)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetDependencies(deps)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetActions(actions)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetSequences(sequences)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetTriggers(triggers)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetRules(rules)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	err = deployer.SetApis(apis)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(manifestName, err.Error())
 	}
 
 	return nil
@@ -142,7 +144,7 @@ func (reader *ManifestReader) SetDependencies(deps map[string]utils.DependencyRe
 				gitReader := utils.NewGitReader(depName, dep)
 				err := gitReader.CloneDependency()
 				if err != nil {
-					return utils.NewYAMLFormatError(err.Error())
+					return utils.NewYAMLFileFormatError(depName, err.Error())
 				}
 			} else {
 				// TODO: we should do a check to make sure this dependency is compatible with an already installed one.
@@ -225,7 +227,7 @@ func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
 
 				err := reader.checkAction(existAction)
 				if err != nil {
-					return utils.NewYAMLFormatError(err.Error())
+					return utils.NewFileReadError(manifestAction.Filepath, err.Error())
 				}
 
 			} else {
@@ -236,7 +238,7 @@ func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
 			// not a new action so update the action in the package
 			err := reader.checkAction(manifestAction)
 			if err != nil {
-				return utils.NewYAMLFormatError(err.Error())
+				return utils.NewFileReadError(manifestAction.Filepath, err.Error())
 			}
 			reader.serviceDeployer.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name] = manifestAction
 		}
@@ -245,6 +247,7 @@ func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
 	return nil
 }
 
+// TODO create named errors
 func (reader *ManifestReader) checkAction(action utils.ActionRecord) error {
 	if action.Filepath == "" {
 		return errors.New("Error: Action " + action.Action.Name + " has no source code location set.")
@@ -294,7 +297,8 @@ func (reader *ManifestReader) SetSequences(actions []utils.ActionRecord) error {
 			// not a new action so update the action in the package
 			err := reader.checkAction(seqAction)
 			if err != nil {
-				return utils.NewYAMLFormatError(err.Error())
+				// TODO() Need a better error type here
+				return utils.NewFileReadError(seqAction.Filepath, err.Error())
 			}
 			reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Sequences[seqAction.Action.Name] = seqAction
 		}
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index 77cda4b..7bcb74d 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -132,13 +132,16 @@ func (deployer *ServiceDeployer) ConstructDeploymentPlan() error {
 		// OpenWhisk entities are annotated with Project Name and therefore
 		// Project Name in manifest/deployment file is mandatory for managed deployments
 		if deployer.ProjectName == "" {
-			return utils.NewYAMLFormatError("Project name in manifest file is mandatory for managed deployments")
+			// TODO see if we can pass in the Deployment file path on first parameter
+			// TODO see if we can move string to translation file.
+			return utils.NewYAMLFileFormatError(utils.LINE_UNKNOWN, "Project name in manifest file is mandatory for managed deployments")
 		}
 		// Every OpenWhisk entity in the manifest file will be annotated with:
 		//managed: '{"__OW__PROJECT__NAME": <name>, "__OW__PROJECT_HASH": <hash>, "__OW__FILE": <path>}'
 		deployer.ManagedAnnotation, err = utils.GenerateManagedAnnotation(deployer.ProjectName, manifest.Filepath)
 		if err != nil {
-			return utils.NewYAMLFormatError(err.Error())
+			// TODO see if we can pass in the YAML file path on first parameter
+			return utils.NewYAMLFileFormatError(utils.LINE_UNKNOWN, err.Error())
 		}
 	}
 
@@ -192,7 +195,7 @@ func (deployer *ServiceDeployer) ConstructDeploymentPlan() error {
 				errorString := wski18n.T("The name of the project/application {{.projectNameDeploy}} in deployment file at [{{.deploymentFile}}] does not match the name of the project/application {{.projectNameManifest}}} in manifest file at [{{.manifestFile}}].",
 					map[string]interface{}{"projectNameDeploy": projectNameDeploy, "deploymentFile": deployer.DeploymentPath,
 						"projectNameManifest": projectName, "manifestFile": deployer.ManifestPath})
-				return utils.NewYAMLFormatError(errorString)
+				return utils.NewYAMLFileFormatError(manifest.Filepath, errorString)
 			}
 		}
 		if err := deploymentReader.BindAssets(); err != nil {
@@ -268,7 +271,7 @@ func (deployer *ServiceDeployer) ConstructUnDeploymentPlan() (*DeploymentProject
 				errorString := wski18n.T("The name of the project/application {{.projectNameDeploy}} in deployment file at [{{.deploymentFile}}] does not match the name of the application {{.projectNameManifest}}} in manifest file at [{{.manifestFile}}].",
 					map[string]interface{}{"projectNameDeploy": projectNameDeploy, "deploymentFile": deployer.DeploymentPath,
 						"projectNameManifest": projectName, "manifestFile": deployer.ManifestPath})
-				return deployer.Deployment, utils.NewYAMLFormatError(errorString)
+				return deployer.Deployment, utils.NewYAMLFileFormatError(manifest.Filepath, errorString)
 			}
 		}
 
diff --git a/parsers/deploy_parser.go b/parsers/deploy_parser.go
index 49c6add..a751737 100644
--- a/parsers/deploy_parser.go
+++ b/parsers/deploy_parser.go
@@ -35,7 +35,7 @@ func (dm *YAMLParser) ParseDeployment(deploymentPath string) (*YAML, error) {
 	dplyyaml := YAML{}
 	content, err := new(utils.ContentReader).LocalReader.ReadLocal(deploymentPath)
     if err != nil {
-        return &dplyyaml, utils.NewYAMLFileReadError(err.Error())
+        return &dplyyaml, utils.NewFileReadError(deploymentPath, err.Error())
     }
 	err = dm.unmarshalDeployment(content, &dplyyaml)
     if err != nil {
@@ -56,7 +56,7 @@ func (dm *YAMLParser) convertErrorToLinesMsgs(errorString string) (lines []strin
 	} else {
 		errorMsg = strs[i]
 	}
-        lines = append(lines, utils.UNKNOWN)
+        lines = append(lines, utils.LINE_UNKNOWN)
         msgs = append(msgs, strings.TrimSpace(errorMsg))
     }
     return
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index b13bcb8..85bab5e 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -41,7 +41,7 @@ func ReadOrCreateManifest() (*YAML, error) {
 		dat, _ := ioutil.ReadFile(utils.ManifestFileNameYaml)
 		err := NewYAMLParser().Unmarshal(dat, &maniyaml)
 		if err != nil {
-			return &maniyaml, utils.NewYAMLFileReadError(err.Error())
+			return &maniyaml, utils.NewFileReadError(utils.ManifestFileNameYaml, err.Error())
 		}
 	}
 	return &maniyaml, nil
@@ -51,12 +51,12 @@ func ReadOrCreateManifest() (*YAML, error) {
 func Write(manifest *YAML, filename string) error {
 	output, err := NewYAMLParser().marshal(manifest)
 	if err != nil {
-		return utils.NewYAMLFormatError(err.Error())
+		return utils.NewYAMLFileFormatError(filename, err.Error())
 	}
 
 	f, err := os.Create(filename)
 	if err != nil {
-		return utils.NewYAMLFileReadError(err.Error())
+		return utils.NewFileReadError(filename, err.Error())
 	}
 	defer f.Close()
 
@@ -87,7 +87,7 @@ func (dm *YAMLParser) ParseManifest(manifestPath string) (*YAML, error) {
 
 	content, err := utils.Read(manifestPath)
 	if err != nil {
-		return &maniyaml, utils.NewYAMLFileReadError(err.Error())
+		return &maniyaml, utils.NewFileReadError(manifestPath, err.Error())
 	}
 
 	err = mm.Unmarshal(content, &maniyaml)
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index 3b9731d..cb79e1a 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -938,7 +938,7 @@ func TestResolveParameterForMultiLineParams(t *testing.T) {
     switch errorType := err.(type) {
     default:
         assert.Fail(t, "Wrong error type received: We are expecting ParserErr.")
-    case *utils.YAMLParserErr:
+    case *utils.YAMLParserError:
         assert.Equal(t, expectedErr.Message, errorType.Message,
             "Expected error " + expectedErr.Message + " but found " + errorType.Message)
     }
diff --git a/parsers/parameters.go b/parsers/parameters.go
index 69cb467..1767ec8 100644
--- a/parsers/parameters.go
+++ b/parsers/parameters.go
@@ -23,33 +23,41 @@ import (
 	"github.com/apache/incubator-openwhisk-wskdeploy/utils"
 )
 
-
 // TODO(): Support other valid Package Manifest types
 // TODO(): i.e., timestamp, version, string256, string64, string16
 // TODO(): Support JSON schema validation for type: json
 // TODO(): Support OpenAPI schema validation
+const (
+	STRING	string = "string"
+	INTEGER	string = "integer"
+	FLOAT	string = "float"
+	BOOLEAN	string = "boolean"
+	JSON	string = "json"
+)
 
 var validParameterNameMap = map[string]string{
-	"string":  "string",
-	"int":     "integer",
-	"float":   "float",
-	"bool":    "boolean",
-	"int8":    "integer",
-	"int16":   "integer",
-	"int32":   "integer",
-	"int64":   "integer",
-	"float32": "float",
-	"float64": "float",
-	"json":    "json",
-	"map":     "json",
+	STRING:    STRING,
+	FLOAT:     FLOAT,
+	BOOLEAN:   BOOLEAN,
+	INTEGER:   INTEGER,
+	"int":     INTEGER,
+	"bool":    BOOLEAN,
+	"int8":    INTEGER,
+	"int16":   INTEGER,
+	"int32":   INTEGER,
+	"int64":   INTEGER,
+	"float32": FLOAT,
+	"float64": FLOAT,
+	JSON:	   JSON,
+	"map":     JSON,
 }
 
 var typeDefaultValueMap = map[string]interface{}{
-	"string":  "",
-	"integer": 0,
-	"float":   0.0,
-	"boolean": false,
-	"json":    make(map[string]interface{}),
+	STRING:  "",
+	INTEGER: 0,
+	FLOAT:   0.0,
+	BOOLEAN: false,
+	JSON:    make(map[string]interface{}),
 	// TODO() Support these types + their validation
 	// timestamp
 	// null
@@ -73,12 +81,24 @@ func getTypeDefaultValue(typeName string) interface{} {
 	if val, ok := typeDefaultValueMap[typeName]; ok {
 		return val
 	} else {
-		// TODO() throw an error "type not found"
+		// TODO() throw an error "type not found" InvalidParameterType
 	}
 	return nil
 }
 
-func ResolveParamTypeFromValue(name string, value interface{}, filePath string) (string, error) {
+
+/*
+    ResolveParamTypeFromValue Resolves the Parameter's data type from its actual value.
+
+    Inputs:
+    - paramName: name of the parameter for error reporting
+    - filepath: the path, including name, of the YAML file which contained the parameter for error reporting
+    - value: the parameter value to resolve
+
+    Returns:
+    - (string) parameter type name as a string
+ */
+func ResolveParamTypeFromValue(paramName string, value interface{}, filePath string) (string, error) {
 	// Note: 'string' is the default type if not specified and not resolvable.
 	var paramType string = "string"
 	var err error = nil
@@ -93,9 +113,7 @@ func ResolveParamTypeFromValue(name string, value interface{}, filePath string)
 
 		} else {
 			// raise an error if parameter's value is not a known type
-			// TODO() - move string to i18n
-			msgs := []string{"Parameter [" + name + "] has a value that is not a known type. [" + actualType + "]"}
-			err = utils.NewYAMLParserErr(filePath, nil, msgs)
+			err = utils.NewInvalidParameterTypeError(filePath, paramName, actualType)
 		}
 	}
 	return paramType, err
@@ -110,8 +128,16 @@ func ResolveParamTypeFromValue(name string, value interface{}, filePath string)
     - 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.
+
+    Inputs:
+    - filePath: the path, including name, of the YAML file which contained the parameter for error reporting
+    - paramName: name of the parameter for error reporting
+    - param: pointer to Parameter structure being resolved
+
+    Returns:
+    - (interface{}) the parameter's resolved value
  */
-func resolveSingleLineParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
+func resolveSingleLineParameter(filePath string, paramName string, param *Parameter) (interface{}, error) {
 	var errorParser error
 
 	if !param.multiline {
@@ -146,8 +172,16 @@ func resolveSingleLineParameter(paramName string, param *Parameter, filePath str
     - 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
 
+    Inputs:
+    - filepath: the path, including name, of the YAML file which contained the parameter for error reporting
+    - paramName: name of the parameter for error reporting
+    - param: pointer to Parameter structure being resolved
+
+    Returns:
+    - (interface{}) the parameter's resolved value
+
  */
-func resolveMultiLineParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
+func resolveMultiLineParameter(filePath string, paramName string, param *Parameter) (interface{}, error) {
 	var errorParser error
 
 	if param.multiline {
@@ -193,10 +227,20 @@ func resolveMultiLineParameter(paramName string, param *Parameter, filePath stri
     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{}
+
+    Inputs:
+    - paramName: name of the parameter for error reporting
+    - filePath: the path, including name, of the YAML file which contained the parameter for error reporting
+    - param: pointer to Parameter structure being resolved
+    - value: the current actual value of the parameter being resolved
+
+    Returns:
+    - (interface{}) the parameter's resolved value
  */
-func resolveJSONParameter(paramName string, param *Parameter, value interface{}, filePath string) (interface{}, error) {
+func resolveJSONParameter(filePath string, paramName string, param *Parameter, value interface{}) (interface{}, error) {
 	var errorParser error
 
+	// TODO() Is the "value" function parameter really needed with the current logic (use param.Value)?
 	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 {
@@ -218,10 +262,13 @@ func resolveJSONParameter(paramName string, param *Parameter, value interface{},
 				//fmt.Printf("EXIT: Parameter [%s] type=[%v] value=[%v]\n", paramName, param.Type, temp)
 				return temp, errorParser
 			}
-		} // else TODO{}
+		} else{
+			errorParser = utils.NewParameterTypeMismatchError(filePath, paramName, JSON, param.Type)
+		}
+
 	} else {
 		msgs := []string{"Parameter [" + paramName + "] is not JSON format."}
-		return param.Value, utils.NewYAMLParserErr(filePath, nil, msgs)
+		errorParser = utils.NewYAMLParserErr(filePath, nil, msgs)
 	}
 
 	return param.Value, errorParser
@@ -240,25 +287,30 @@ func resolveJSONParameter(paramName string, param *Parameter, value interface{},
 
     Note: parameter values may set later (overridden) by an (optional) Deployment file
 
+    Inputs:
+    - paramName: name of the parameter for error reporting
+    - filepath: the path, including name, of the YAML file which contained the parameter for error reporting
+    - param: pointer to Parameter structure being resolved
+
+    Returns:
+    - (interface{}) the parameter's resolved value
  */
 func ResolveParameter(paramName string, param *Parameter, filePath string) (interface{}, error) {
 
 	var errorParser error
-	// default parameter value to empty string
+	// default resolved 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
+	// Regardless, the following functions will assure that param.Value and param.Type are correctly set
 	if !param.multiline {
-
-		// This function will assure that param.Value and param.Type are correctly set
-		value, errorParser = resolveSingleLineParameter(paramName, param, filePath)
+		value, errorParser = resolveSingleLineParameter(filePath, paramName, param)
 
 	} else {
-
-		value, errorParser = resolveMultiLineParameter(paramName, param, filePath)
+		value, errorParser = resolveMultiLineParameter(filePath, paramName, param)
 	}
 
 	// String value pre-processing (interpolation)
@@ -272,7 +324,7 @@ func ResolveParameter(paramName string, param *Parameter, filePath string) (inte
 
 	// 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)
+		value, errorParser = resolveJSONParameter(filePath, paramName, param, value)
 	}
 
 	// Default value to zero value for the Type
diff --git a/utils/errorhandlers.go b/utils/errorhandlers.go
index 0506ca4..e566c88 100644
--- a/utils/errorhandlers.go
+++ b/utils/errorhandlers.go
@@ -18,35 +18,12 @@
 package utils
 
 import (
-	"errors"
 	"fmt"
 	"github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
 	"github.com/fatih/color"
 	"github.com/mattn/go-colorable"
-	"os"
 )
 
-// Check is a util function to panic when there is an error.
-func Check(e error) {
-	defer func() {
-		if err := recover(); err != nil {
-			fmt.Printf("Runtime panic : %v", err)
-		}
-	}()
-
-	if e != nil {
-		fmt.Printf("%v", e)
-		erro := errors.New("Error happened during execution, please type 'wskdeploy -h' for help messages.")
-		fmt.Printf("%v", erro)
-		if Flags.WithinOpenWhisk {
-			PrintOpenWhiskError(e)
-		} else {
-			os.Exit(1)
-		}
-
-	}
-}
-
 func PrintOpenWhiskError(err error) {
 	outputStream := colorable.NewColorableStderr()
 	fmt.Fprintf(outputStream, "%s%s", color.RedString(wski18n.T("Error: ")), err.Error())
diff --git a/utils/wskdeployerror.go b/utils/wskdeployerror.go
index 54c997e..1c7444b 100644
--- a/utils/wskdeployerror.go
+++ b/utils/wskdeployerror.go
@@ -18,249 +18,288 @@
 package utils
 
 import (
-    "fmt"
-    "runtime"
-    "strings"
-    "path/filepath"
+	"fmt"
+	"runtime"
+	"strings"
+	"path/filepath"
 )
 
 const (
-    UNKNOWN = "Unknown"
-    UNKNOWN_VALUE = "Unknown value"
-    LINE = "line"
-    PARAMETER = "Parameter"
-    TYPE = "Type"
-    EXPECTED = "expected"
-    ACTUAL = "actual"
-    YAML_FILE = "YAML file"
-
-    ERROR_COMMAND_FAILED = "ERROR_COMMAND_FAILED"
-    ERROR_MANIFEST_FILE_NOT_FOUND = "ERROR_MANIFEST_FILE_NOT_FOUND"
-    ERROR_YAML_FILE_READ_ERROR = "ERROR_YAML_FILE_READ_ERROR"
-    ERROR_YAML_FORMAT_ERROR = "ERROR_YAML_FORMAT_ERROR"
-    ERROR_WHISK_CLIENT_ERROR = "ERROR_WHISK_CLIENT_ERROR"
-    ERROR_WHISK_CLIENT_INVALID_CONFIG = "ERROR_WHISK_CLIENT_INVALID_CONFIG"
-    ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
+	LINE_UNKNOWN = "Unknown"
+	UNKNOWN_VALUE = "Unknown value"
+	FILE = "File"
+	LINE = "Line"
+	PARAMETER = "Parameter"
+	TYPE = "Type"
+	EXPECTED = "expected"
+	ACTUAL = "actual"
+	INDENT_LEVEL_1 = "==>"
+
+	ERROR_COMMAND_FAILED = "ERROR_COMMAND_FAILED"
+	ERROR_WHISK_CLIENT_ERROR = "ERROR_WHISK_CLIENT_ERROR"
+	ERROR_WHISK_CLIENT_INVALID_CONFIG = "ERROR_WHISK_CLIENT_INVALID_CONFIG"
+	ERROR_FILE_READ_ERROR = "ERROR_FILE_READ_ERROR"
+	ERROR_MANIFEST_FILE_NOT_FOUND = "ERROR_MANIFEST_FILE_NOT_FOUND"
+	ERROR_YAML_FILE_FORMAT_ERROR = "ERROR_YAML_FILE_FORMAT_ERROR"
+	ERROR_YAML_PARSER_ERROR = "ERROR_YAML_PARSER_ERROR"
+	ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
+	ERROR_YAML_INVALID_PARAMETER_TYPE = "ERROR_YAML_INVALID_PARAMETER_TYPE"
 )
 
 /*
  * BaseError
  */
 type BaseErr struct {
-    ErrorType   string
-    FileName    string
-    LineNum     int
-    Message     string
+	ErrorType string
+	FileName  string
+	LineNum   int
+	Message   string
 }
 
 func (e *BaseErr) 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)
+	return fmt.Sprintf("%s [%d]: [%s]: %s\n", e.FileName, e.LineNum, e.ErrorType, e.Message)
 }
 
 func (e *BaseErr) SetFileName(fileName string) {
-    e.FileName = fileName
+	e.FileName = filepath.Base(fileName)
 }
 
 func (e *BaseErr) SetLineNum(lineNum int) {
-    e.LineNum = lineNum
+	e.LineNum = lineNum
 }
 
 func (e *BaseErr) SetMessage(message string) {
-    e.Message = message
+	e.Message = message
 }
 
 func (e *BaseErr) SetErrorType(errorType string) {
-    e.ErrorType = errorType
+	e.ErrorType = errorType
 }
 
 // func Caller(skip int) (pc uintptr, file string, line int, ok bool)
 func (e *BaseErr) SetCallerByStackFrameSkip(skip int) {
-    _, fn, lineNum, _ := runtime.Caller(skip)
-    e.SetFileName(filepath.Base(fn))
-    e.SetLineNum(lineNum)
+	_, fname, lineNum, _ := runtime.Caller(skip)
+	e.SetFileName(fname)
+	e.SetLineNum(lineNum)
 }
 
 /*
  * CommandError
  */
 type CommandError struct {
-    BaseErr
-    Command string
+	BaseErr
+	Command string
 }
 
 func NewCommandError(cmd string, errorMessage string) *CommandError {
-    var err = &CommandError{
-        Command: cmd,
-    }
-    err.SetCallerByStackFrameSkip(2)
-    err.SetErrorType(ERROR_COMMAND_FAILED)
-    err.SetMessage(cmd + ": " + errorMessage)
-    return err
+	var err = &CommandError{
+		Command: cmd,
+	}
+	err.SetErrorType(ERROR_COMMAND_FAILED)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetMessage(cmd + ": " + errorMessage)
+	return err
 }
 
 func (e *CommandError) Error() string {
-    return e.BaseErr.Error()
+	return e.BaseErr.Error()
 }
 
 /*
- * ManifestFileNotFoundError
+ * WhiskClientError
  */
-type ErrorManifestFileNotFound struct {
-    BaseErr
-    YAMLFilename string
+type WhiskClientError struct {
+	BaseErr
+	ErrorCode int
 }
 
-func NewErrorManifestFileNotFound(errMessage string) *ErrorManifestFileNotFound {
-    var err = &ErrorManifestFileNotFound{
-    }
-    err.SetErrorType(ERROR_MANIFEST_FILE_NOT_FOUND)
-    err.SetCallerByStackFrameSkip(2)
-    err.SetMessage(errMessage)
-    return err
+func NewWhiskClientError(errorMessage string, code int) *WhiskClientError {
+	var err = &WhiskClientError{
+		ErrorCode: code,
+	}
+	err.SetErrorType(ERROR_WHISK_CLIENT_ERROR)
+	err.SetCallerByStackFrameSkip(2)
+	str := fmt.Sprintf("Error Code: %d: %s", code, errorMessage)
+	err.SetMessage(str)
+	return err
 }
 
-func (e *ErrorManifestFileNotFound) Error() string {
-    return e.BaseErr.Error()
+/*
+ * WhiskClientInvalidConfigError
+ */
+type WhiskClientInvalidConfigError struct {
+	BaseErr
+}
+
+func NewWhiskClientInvalidConfigError(errorMessage string) *WhiskClientInvalidConfigError {
+	var err = &WhiskClientInvalidConfigError{
+	}
+	err.SetErrorType(ERROR_WHISK_CLIENT_INVALID_CONFIG)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetMessage(errorMessage)
+	return err
 }
 
 /*
- * YAMLFileReadError
+ * FileError
  */
-type YAMLFileReadError struct {
-    BaseErr
+type FileError struct {
+	BaseErr
+	ErrorFileName string
+	ErrorFilePath string
 }
 
-func NewYAMLFileReadError(errorMessage string) *YAMLFileReadError {
-    var err = &YAMLFileReadError{
-        //errorType: wski18n.T(INVALID_YAML_INPUT),
-    }
-    err.SetErrorType(ERROR_YAML_FILE_READ_ERROR)
-    err.SetCallerByStackFrameSkip(2)
-    err.SetMessage(errorMessage)
-    return err
+func (e *FileError) SetErrorFilePath(fpath string) {
+	e.ErrorFilePath = fpath
+	e.ErrorFileName = filepath.Base(fpath)
 }
 
-func (e *YAMLFileReadError) Error() string {
-    return e.BaseErr.Error()
+func (e *FileError) SetErrorFileName(fname string) {
+	e.ErrorFilePath = fname
+}
+
+func (e *FileError) Error() string {
+	return fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s\n",
+		e.FileName,
+		e.LineNum,
+		e.ErrorType,
+		e.ErrorFileName,
+		e.Message)
 }
 
 /*
- * YAMLFormatError
+ * FileReadError
  */
-type YAMLFormatError struct {
-    YAMLFileReadError
+func NewFileReadError(fpath string, errMessage string) *FileError {
+	var err = &FileError{
+	}
+	err.SetErrorType(ERROR_FILE_READ_ERROR)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetErrorFilePath(fpath)
+	err.SetMessage(errMessage)
+	return err
 }
 
-func NewYAMLFormatError(errorMessage string) *YAMLFormatError {
-    var err = &YAMLFormatError{
-        //err.SetErrorType(wski18n.T(INVALID_YAML_FORMAT))
-    }
-    err.SetErrorType(ERROR_YAML_FORMAT_ERROR)
-    err.SetCallerByStackFrameSkip(2)
-    err.SetMessage(errorMessage)
-    return err
-}
 
 /*
- * WhiskClientError
+ * ManifestFileNotFoundError
  */
-type WhiskClientError struct {
-    BaseErr
-    ErrorCode int
-}
-
-func NewWhiskClientError(errorMessage string, code int) *WhiskClientError {
-    var err = &WhiskClientError{
-        //errorType: wski18n.T(OPENWHISK_CLIENT_ERROR),
-        ErrorCode: code,
-    }
-    err.SetErrorType(ERROR_WHISK_CLIENT_ERROR)
-    err.SetCallerByStackFrameSkip(2)
-    str := fmt.Sprintf("Error Code: %d: %s", code, errorMessage)
-    err.SetMessage(str)
-    return err
+type ErrorManifestFileNotFound struct {
+	FileError
 }
 
-func (e *WhiskClientError) Error() string {
-    return e.BaseErr.Error()
+func NewErrorManifestFileNotFound(fpath string, errMessage string) *ErrorManifestFileNotFound {
+	var err = &ErrorManifestFileNotFound{
+	}
+	err.SetErrorType(ERROR_MANIFEST_FILE_NOT_FOUND)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetErrorFilePath(fpath)
+	err.SetMessage(errMessage)
+	return err
 }
 
 /*
- * WhiskClientInvalidConfigError
+ * YAMLFileFormatError
  */
-type WhiskClientInvalidConfigError struct {
-    BaseErr
+type YAMLFileFormatError struct {
+	FileError
 }
 
-func NewWhiskClientInvalidConfigError(errorMessage string) *WhiskClientInvalidConfigError {
-    var err = &WhiskClientInvalidConfigError{
-    }
-    err.SetErrorType(ERROR_WHISK_CLIENT_INVALID_CONFIG)
-    err.SetCallerByStackFrameSkip(2)
-    err.SetMessage(errorMessage)
-    return err
+func NewYAMLFileFormatError(fpath string, errorMessage string) *YAMLFileFormatError {
+	var err = &YAMLFileFormatError{
+	}
+	err.SetErrorType(ERROR_YAML_FILE_FORMAT_ERROR)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetErrorFilePath(fpath)
+	err.SetMessage(errorMessage)
+	return err
 }
 
 /*
- * YAMLParserErr
+ * ParameterTypeMismatchError
  */
-type YAMLParserErr struct {
-    BaseErr
-    YamlFile string
-    lines []string
-    msgs []string
+type ParameterTypeMismatchError struct {
+	FileError
+	Parameter    string
+	ExpectedType string
+	ActualType   string
 }
 
-func NewYAMLParserErr(yamlFile string, lines []string, msgs []string) *YAMLParserErr {
-    var err = &YAMLParserErr{
-        YamlFile: yamlFile,
-        lines: lines,
-        msgs: msgs,
-    }
-    err.SetCallerByStackFrameSkip(2)
-    return err
+func NewParameterTypeMismatchError(fpath string, param string, expectedType string, actualType string) *ParameterTypeMismatchError {
+	var err = &ParameterTypeMismatchError{
+		ExpectedType: expectedType,
+		ActualType: actualType,
+	}
+
+	err.SetErrorType(ERROR_YAML_PARAMETER_TYPE_MISMATCH)
+	err.SetCallerByStackFrameSkip(2)
+	err.SetErrorFilePath(fpath)
+	str := fmt.Sprintf("%s [%s]: %s %s: [%s], %s: [%s]",
+		PARAMETER, param,
+		TYPE,
+		EXPECTED, expectedType,
+		ACTUAL, actualType)
+	err.SetMessage(str)
+	return err
 }
 
-func (e *YAMLParserErr) Error() string {
-    result := make([]string, len(e.msgs))
-
-    for index, msg := range e.msgs {
-        var s string
-        if e.lines == nil || e.lines[index] == UNKNOWN {
-            s = fmt.Sprintf("====> %s", msg)
-        } else{
-            s = fmt.Sprintf("====> %s [%v]: %s", LINE, e.lines[index], msg)
-        }
-        result[index] = s
-    }
-    return fmt.Sprintf("\n==> %s [%d]: %s: %s: \n%s", e.FileName, e.LineNum, YAML_FILE, e.YamlFile, strings.Join(result, "\n"))
+/*
+ * InvalidParameterType
+ */
+type InvalidParameterTypeError struct {
+	FileError
+	Parameter    string
+	ActualType   string
+}
+
+func NewInvalidParameterTypeError(fpath string, param string, actualType string) *ParameterTypeMismatchError {
+	var err = &ParameterTypeMismatchError{
+		ActualType: actualType,
+	}
+	err.SetErrorFilePath(fpath)
+	err.SetErrorType(ERROR_YAML_INVALID_PARAMETER_TYPE)
+	err.SetCallerByStackFrameSkip(2)
+	str := fmt.Sprintf("%s [%s]: %s [%s]",
+		PARAMETER, param,
+		TYPE, actualType)
+	err.SetMessage(str)
+	return err
 }
 
 /*
- * ParameterTypeMismatchError
+ * YAMLParserErr
  */
-type ParameterTypeMismatchError struct {
-    BaseErr
-    Parameter       string
-    ExpectedType    string
-    ActualType      string
+type YAMLParserError struct {
+	FileError
+	lines    []string
+	msgs     []string
 }
 
-func NewParameterTypeMismatchError(param string, expectedType string, actualType string) *ParameterTypeMismatchError {
-    var err = &ParameterTypeMismatchError{
-        ExpectedType: expectedType,
-        ActualType: actualType,
-    }
-    err.SetErrorType(ERROR_YAML_PARAMETER_TYPE_MISMATCH)
-    err.SetCallerByStackFrameSkip(2)
-    str := fmt.Sprintf( "%s [%s]: %s %s: [%s], %s: [%s]", PARAMETER, param, TYPE, EXPECTED, expectedType, ACTUAL, actualType)
-    err.SetMessage(str)
-    return err
+func NewYAMLParserErr(fpath string, lines []string, msgs []string) *YAMLParserError {
+	var err = &YAMLParserError{
+		lines: lines,
+		msgs: msgs,
+	}
+	err.SetErrorType(ERROR_YAML_PARSER_ERROR)
+	err.SetErrorFilePath(fpath)
+	err.SetCallerByStackFrameSkip(2)
+	return err
 }
 
-func (e *ParameterTypeMismatchError) Error() string {
-    return e.BaseErr.Error()
+
+func (e *YAMLParserError) Error() string {
+	result := make([]string, len(e.msgs))
+
+	for index, msg := range e.msgs {
+		var s string
+		if e.lines == nil || e.lines[index] == LINE_UNKNOWN {
+			s = fmt.Sprintf("\n%s %s [%v]: %s", INDENT_LEVEL_1, LINE, LINE_UNKNOWN, msg)
+		} else {
+			s = fmt.Sprintf("\n%s %s [%v]: %s", INDENT_LEVEL_1, LINE, e.lines[index], msg)
+		}
+		result[index] = s
+	}
+
+	e.SetMessage(strings.Join(result, ""))
+	return e.FileError.Error()
 }
diff --git a/utils/wskdeployerror_test.go b/utils/wskdeployerror_test.go
new file mode 100644
index 0000000..18c809e
--- /dev/null
+++ b/utils/wskdeployerror_test.go
@@ -0,0 +1,184 @@
+// +build unit
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package utils
+
+import (
+	"testing"
+	"github.com/stretchr/testify/assert"
+	"strings"
+	"fmt"
+	"runtime"
+	"path/filepath"
+)
+
+/*
+ * TestCustomErrorOutputFormat
+ */
+func TestCustomErrorOutputFormat(t *testing.T) {
+
+	_, fn, _, _ := runtime.Caller(0)
+	packageName := filepath.Base(fn)
+	const TEST_DEFAULT_ERROR_MESSAGE = "Some bad error"
+	const TEST_COMMAND string = "test"
+	const TEST_ERROR_CODE = 400  // Bad request
+	const TEST_EXISTANT_MANIFEST_FILE = "tests/dat/manifest_validate_multiline_params.yaml"
+	const TEST_NONEXISTANT_MANIFEST_FILE = "tests/dat/missing_manifest.yaml"
+	const TEST_INVALID_YAML_MANIFEST_FILE = "tests/dat/manifest_bad_yaml_invalid_comment.yaml"
+	const TEST_PARAM_NAME = "Age"
+	const TEST_PARAM_TYPE_INT = "integer"
+	const TEST_PARAM_TYPE_FLOAT = "float"
+	const TEST_PARAM_TYPE_FOO = "foo"
+
+	/*
+	 * CommandError
+	 */
+	err1 := NewCommandError(TEST_COMMAND, TEST_DEFAULT_ERROR_MESSAGE)
+	actualResult :=  strings.TrimSpace(err1.Error())
+	expectedResult := fmt.Sprintf("%s [%d]: [%s]: %s: %s",
+		packageName,
+		err1.LineNum,
+		ERROR_COMMAND_FAILED,
+		TEST_COMMAND,
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+	 * WhiskClientError
+	 */
+	err2 := NewWhiskClientError(TEST_DEFAULT_ERROR_MESSAGE, TEST_ERROR_CODE)
+	actualResult =  strings.TrimSpace(err2.Error())
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: Error Code: %d: %s",
+		packageName,
+		err2.LineNum,
+		ERROR_WHISK_CLIENT_ERROR,
+		TEST_ERROR_CODE,
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+	 * WhiskClientInvalidConfigError
+	 */
+	err3 := NewWhiskClientInvalidConfigError(TEST_DEFAULT_ERROR_MESSAGE)
+	actualResult =  strings.TrimSpace(err3.Error())
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: %s",
+		packageName,
+		err3.LineNum,
+		ERROR_WHISK_CLIENT_INVALID_CONFIG,
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+ 	 * FileReadError
+ 	 */
+	err4 := NewFileReadError(TEST_NONEXISTANT_MANIFEST_FILE, TEST_DEFAULT_ERROR_MESSAGE)
+	actualResult =  strings.TrimSpace(err4.Error())
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err4.LineNum,
+		ERROR_FILE_READ_ERROR,
+		filepath.Base(TEST_NONEXISTANT_MANIFEST_FILE),
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+ 	 * ManifestFileNotFoundError
+ 	 */
+	err5 := NewErrorManifestFileNotFound(TEST_NONEXISTANT_MANIFEST_FILE, TEST_DEFAULT_ERROR_MESSAGE)
+	actualResult =  strings.TrimSpace(err5.Error())
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err5.LineNum,
+		ERROR_MANIFEST_FILE_NOT_FOUND,
+		filepath.Base(TEST_NONEXISTANT_MANIFEST_FILE),
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+         * YAMLFileFormatError
+         */
+	err6 := NewYAMLFileFormatError(TEST_INVALID_YAML_MANIFEST_FILE, TEST_DEFAULT_ERROR_MESSAGE)
+	actualResult =  strings.TrimSpace(err6.Error())
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err6.LineNum,
+		ERROR_YAML_FILE_FORMAT_ERROR,
+		filepath.Base(TEST_INVALID_YAML_MANIFEST_FILE),
+		TEST_DEFAULT_ERROR_MESSAGE )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+	 * ParameterTypeMismatchError
+	 */
+	err8 := NewParameterTypeMismatchError(
+		TEST_EXISTANT_MANIFEST_FILE,
+		TEST_PARAM_NAME,
+		TEST_PARAM_TYPE_INT,
+		TEST_PARAM_TYPE_FLOAT)
+	actualResult =  strings.TrimSpace(err8.Error())
+	msg8 := fmt.Sprintf("%s [%s]: %s %s: [%s], %s: [%s]",
+		PARAMETER, TEST_PARAM_NAME,
+		TYPE,
+		EXPECTED, TEST_PARAM_TYPE_INT,
+		ACTUAL, TEST_PARAM_TYPE_FLOAT)
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err8.LineNum,
+		ERROR_YAML_PARAMETER_TYPE_MISMATCH,
+		filepath.Base(TEST_EXISTANT_MANIFEST_FILE),
+		msg8 )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+	 * InvalidParameterType
+	 */
+	err9 := NewInvalidParameterTypeError(TEST_EXISTANT_MANIFEST_FILE, TEST_PARAM_NAME, TEST_PARAM_TYPE_FOO)
+	actualResult =  strings.TrimSpace(err9.Error())
+	msg9 := fmt.Sprintf("%s [%s]: %s [%s]",
+		PARAMETER, TEST_PARAM_NAME,
+		TYPE, TEST_PARAM_TYPE_FOO)
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err9.LineNum,
+		ERROR_YAML_INVALID_PARAMETER_TYPE,
+		filepath.Base(TEST_EXISTANT_MANIFEST_FILE),
+		msg9 )
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+
+	/*
+	 * YAMLParserErr
+	 */
+	var TEST_LINES    = []string{"40", LINE_UNKNOWN, "123"}
+	var TEST_MESSAGES = []string{"did not find expected key", "did not find expected ',' or ']'", "found duplicate %YAML directive"}
+
+	err10 := NewYAMLParserErr(TEST_EXISTANT_MANIFEST_FILE, TEST_LINES, TEST_MESSAGES)
+	actualResult =  strings.TrimSpace(err10.Error())
+
+	msgs := "\n==> Line [40]: did not find expected key" +
+		"\n==> Line [Unknown]: did not find expected ',' or ']'" +
+		"\n==> Line [123]: found duplicate %YAML directive"
+
+	expectedResult = fmt.Sprintf("%s [%d]: [%s]: " + FILE + ": [%s]: %s",
+		packageName,
+		err10.LineNum,
+		ERROR_YAML_PARSER_ERROR,
+		filepath.Base(TEST_EXISTANT_MANIFEST_FILE),
+		msgs)
+	assert.Equal(t, expectedResult, actualResult, "Expected [" + expectedResult + "] but got [" + actualResult + "]")
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].