This is an automated email from the ASF dual-hosted git repository.
mrutkowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwhisk-client-go.git
The following commit(s) were added to refs/heads/master by this push:
new d272b2b Parse an action's application error (#133)
d272b2b is described below
commit d272b2b1129269d384c1dbba6c39156abc10ad3c
Author: Mark Deuser <[email protected]>
AuthorDate: Wed Dec 11 11:53:14 2019 -0500
Parse an action's application error (#133)
* Generically parse the application error
* Update vendor.json to include all dependent packages
* gofmt
* don't display the application error as the action's error
* put back original vendor.json
---
whisk/client.go | 99 +++++++++++++++++++++++++++++++++++++++++++++++-----
whisk/client_test.go | 19 ++++++++++
2 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/whisk/client.go b/whisk/client.go
index 91b8a79..9ea01bc 100644
--- a/whisk/client.go
+++ b/whisk/client.go
@@ -586,9 +586,13 @@ func parseApplicationError(resp *http.Response, data
[]byte, v interface{}) (*ht
// Handle application errors that occur when --result option is false
(#5)
if err == nil && whiskErrorResponse != nil &&
whiskErrorResponse.Response != nil && whiskErrorResponse.Response.Status != nil
{
Debug(DbgInfo, "Detected response status `%s` that a
whisk.error(\"%#v\") was returned\n",
- *whiskErrorResponse.Response.Status,
*whiskErrorResponse.Response.Result)
+ *whiskErrorResponse.Response.Status,
whiskErrorResponse.Response.Result)
+
+ errStr :=
getApplicationErrorMessage(whiskErrorResponse.Response.Result)
+ Debug(DbgInfo, "Application error received: %s\n", errStr)
+
errMsg := wski18n.T("The following application error was
received: {{.err}}",
- map[string]interface{}{"err":
*whiskErrorResponse.Response.Result})
+ map[string]interface{}{"err": errStr})
whiskErr := MakeWskError(errors.New(errMsg),
resp.StatusCode-256, NO_DISPLAY_MSG, NO_DISPLAY_USAGE,
NO_MSG_DISPLAYED, DISPLAY_PREFIX, APPLICATION_ERR)
return parseSuccessResponse(resp, data, v), whiskErr
@@ -600,10 +604,10 @@ func parseApplicationError(resp *http.Response, data
[]byte, v interface{}) (*ht
// Handle application errors that occur with blocking invocations when
--result option is true (#5)
if err == nil && appErrResult.Error != nil {
Debug(DbgInfo, "Error code is null, blocking with result
invocation error has occurred\n")
- errMsg := fmt.Sprintf("%v", *appErrResult.Error)
- Debug(DbgInfo, "Application error received: %s\n", errMsg)
+ errStr := getApplicationErrorMessage(*appErrResult.Error)
+ Debug(DbgInfo, "Application error received: %s\n", errStr)
- whiskErr := MakeWskError(errors.New(errMsg),
resp.StatusCode-256, NO_DISPLAY_MSG, NO_DISPLAY_USAGE,
+ whiskErr := MakeWskError(errors.New(errStr),
resp.StatusCode-256, NO_DISPLAY_MSG, NO_DISPLAY_USAGE,
NO_MSG_DISPLAYED, DISPLAY_PREFIX, APPLICATION_ERR)
return parseSuccessResponse(resp, data, v), whiskErr
}
@@ -616,6 +620,85 @@ func parseApplicationError(resp *http.Response, data
[]byte, v interface{}) (*ht
return resp, whiskErr
}
+func getApplicationErrorMessage(errResp interface{}) string {
+ var errStr string
+
+ // Handle error results that looks like:
+ //
+ // {
+ // "error": {
+ // "error": "An error string",
+ // "message": "An error message",
+ // "another-message": "Another error message"
+ // }
+ // }
+ // Returns "An error string; An error message; Another error message"
+ //
+ // OR
+ // {
+ // "error": "An error string"
+ // }
+ // Returns "An error string"
+ //
+ // OR
+ // {
+ // "error": {
+ // "custom-err": {
+ // "error": "An error string",
+ // "message": "An error message"
+ // }
+ // }
+ // }
+ // Returns "{"error": { "custom-err": { "error": "An error string",
"message": "An error message" } } }"
+
+ errMapIntf, errMapIntfOk := errResp.(map[string]interface{})
+ if !errMapIntfOk {
+ errStr = fmt.Sprintf("%v", errResp)
+ } else {
+ // Check if the "error" field in the response JSON
+ errObjIntf, errObjIntfOk := errMapIntf["error"]
+ if !errObjIntfOk {
+ errStr = fmt.Sprintf("%v", errMapIntf)
+ } else {
+ // Check if the "error" field value is a JSON object
+ errObj, errObjOk := errObjIntf.(map[string]interface{})
+ if !errObjOk {
+ // The "error" field value is not JSON; check
if it's a string
+ errorStr, errorStrOk := errObjIntf.(string)
+ if !errorStrOk {
+ errStr = fmt.Sprintf("%v", errObjIntf)
+ } else {
+ errStr = errorStr
+ }
+ } else {
+ Debug(DbgInfo, "Application failure error json:
%+v\n", errObj)
+
+ // Concatenate all string field values into a
single error string
+ msgSeparator := ""
+ for _, val := range errObj {
+ valStr, valStrOk := val.(string)
+ if valStrOk {
+ errStr = errStr + msgSeparator
+ valStr
+ msgSeparator = "; "
+ }
+ }
+
+ // If no top level string fields exist, return
the entire error object
+ // Return a nice JSON string if possible;
otherwise let Go try it's best
+ if len(errStr) == 0 {
+ jsonBytes, err := json.Marshal(errObj)
+ if err != nil {
+ errStr = fmt.Sprintf("%v",
errObj)
+ } else {
+ errStr = string(jsonBytes)
+ }
+ }
+ }
+ }
+ }
+
+ return errStr
+}
func parseSuccessResponse(resp *http.Response, data []byte, v interface{})
*http.Response {
Debug(DbgInfo, "Parsing HTTP response into struct type: %s\n",
reflect.TypeOf(v))
@@ -660,9 +743,9 @@ type WhiskErrorResponse struct {
}
type WhiskResponse struct {
- Result *WhiskResult `json:"result"`
- Success bool `json:"success"`
- Status *interface{} `json:"status"`
+ Result map[string]interface{} `json:"result"`
+ Success bool `json:"success"`
+ Status *interface{} `json:"status"`
}
type WhiskResult struct {
diff --git a/whisk/client_test.go b/whisk/client_test.go
index ec27b63..b580c97 100644
--- a/whisk/client_test.go
+++ b/whisk/client_test.go
@@ -168,3 +168,22 @@ func TestAdditionalHeaders(t *testing.T) {
assert.Equal(t, "Value1", newRequestUrl.Header.Get("Key1"))
assert.Equal(t, "Value2", newRequestUrl.Header.Get("Key2"))
}
+
+func TestParseApplicationError(t *testing.T) {
+ appErr1 := map[string]interface{}{
+ "error": map[string]interface{}{
+ "error": "An error string",
+ "message": "An error message",
+ },
+ }
+
+ appErr2 := map[string]interface{}{
+ "error": "Another error string",
+ }
+
+ errStr := getApplicationErrorMessage(appErr1)
+ assert.Equal(t, "An error string; An error message", errStr)
+
+ errStr = getApplicationErrorMessage(appErr2)
+ assert.Equal(t, "Another error string", errStr)
+}