-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support array result include sequence action #170
Changes from all commits
881e291
5d9d514
820ece8
f404472
ad69b32
2243586
f077a0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ import ( | |
"io" | ||
"log" | ||
"os" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
|
@@ -42,10 +43,11 @@ func main() { | |
log.Printf("ACTION ENV: %v", os.Environ()) | ||
} | ||
|
||
// assign the main function | ||
type Action func(event map[string]interface{}) map[string]interface{} | ||
var action Action | ||
action = Main | ||
resultKind := reflect.TypeOf(Main).Out(0).Kind() | ||
if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { | ||
fmt.Println("Support map and slice and array only") | ||
os.Exit(1) | ||
} | ||
|
||
// input | ||
out := os.NewFile(3, "pipe") | ||
|
@@ -89,12 +91,29 @@ func main() { | |
} | ||
} | ||
// get payload if not empty | ||
var payload map[string]interface{} | ||
isJsonObjectParam := true | ||
var payloadForJsonObject map[string]interface{} | ||
var payloadForJsonArray []interface{} | ||
if value, ok := input["value"].(map[string]interface{}); ok { | ||
payload = value | ||
payloadForJsonObject = value | ||
} else { | ||
if value, ok := input["value"].([]interface{}); ok { | ||
payloadForJsonArray = value | ||
isJsonObjectParam = false | ||
} | ||
} | ||
// process the request | ||
result := action(payload) | ||
var result interface{} | ||
funcMain := reflect.ValueOf(Main) | ||
if isJsonObjectParam { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} | ||
reflectResult := funcMain.Call(param) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If invokes Main directly, compile would be failed. |
||
result = reflectResult[0].Interface() | ||
} else { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} | ||
reflectResult := funcMain.Call(param) | ||
result = reflectResult[0].Interface() | ||
} | ||
// encode the answer | ||
output, err := json.Marshal(&result) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ import ( | |
"io" | ||
"log" | ||
"os" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
|
@@ -50,10 +51,11 @@ func main() { | |
log.Printf("Environment: %v", os.Environ()) | ||
} | ||
|
||
// assign the main function | ||
type Action func(event map[string]interface{}) map[string]interface{} | ||
var action Action | ||
action = Main | ||
resultKind := reflect.TypeOf(Main).Out(0).Kind() | ||
if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { | ||
fmt.Println("Support map and slice and array only") | ||
os.Exit(1) | ||
} | ||
|
||
// input | ||
out := os.NewFile(3, "pipe") | ||
|
@@ -100,12 +102,29 @@ func main() { | |
} | ||
} | ||
// get payload if not empty | ||
var payload map[string]interface{} | ||
isJsonObjectParam := true | ||
var payloadForJsonObject map[string]interface{} | ||
var payloadForJsonArray []interface{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Support json array as input param, this is for sequence action |
||
if value, ok := input["value"].(map[string]interface{}); ok { | ||
payload = value | ||
payloadForJsonObject = value | ||
} else { | ||
if value, ok := input["value"].([]interface{}); ok { | ||
payloadForJsonArray = value | ||
isJsonObjectParam = false | ||
} | ||
} | ||
// process the request | ||
result := action(payload) | ||
var result interface{} | ||
funcMain := reflect.ValueOf(Main) | ||
if isJsonObjectParam { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} | ||
reflectResult := funcMain.Call(param) | ||
result = reflectResult[0].Interface() | ||
} else { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} | ||
reflectResult := funcMain.Call(param) | ||
result = reflectResult[0].Interface() | ||
} | ||
// encode the answer | ||
output, err := json.Marshal(&result) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ import ( | |
"io" | ||
"log" | ||
"os" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
|
@@ -50,10 +51,11 @@ func main() { | |
log.Printf("Environment: %v", os.Environ()) | ||
} | ||
|
||
// assign the main function | ||
type Action func(event map[string]interface{}) map[string]interface{} | ||
var action Action | ||
action = Main | ||
resultKind := reflect.TypeOf(Main).Out(0).Kind() | ||
if resultKind != reflect.Map && resultKind != reflect.Slice && resultKind != reflect.Array { | ||
fmt.Println("Support map and slice and array only") | ||
os.Exit(1) | ||
} | ||
|
||
// input | ||
out := os.NewFile(3, "pipe") | ||
|
@@ -100,12 +102,29 @@ func main() { | |
} | ||
} | ||
// get payload if not empty | ||
var payload map[string]interface{} | ||
isJsonObjectParam := true | ||
var payloadForJsonObject map[string]interface{} | ||
var payloadForJsonArray []interface{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Support jsonArray as input param as well. this is for sequence action |
||
if value, ok := input["value"].(map[string]interface{}); ok { | ||
payload = value | ||
payloadForJsonObject = value | ||
} else { | ||
if value, ok := input["value"].([]interface{}); ok { | ||
payloadForJsonArray = value | ||
isJsonObjectParam = false | ||
} | ||
} | ||
// process the request | ||
result := action(payload) | ||
var result interface{} | ||
funcMain := reflect.ValueOf(Main) | ||
if isJsonObjectParam { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonObject)} | ||
reflectResult := funcMain.Call(param) | ||
result = reflectResult[0].Interface() | ||
} else { | ||
param := []reflect.Value{reflect.ValueOf(payloadForJsonArray)} | ||
reflectResult := funcMain.Call(param) | ||
result = reflectResult[0].Interface() | ||
} | ||
// encode the answer | ||
output, err := json.Marshal(&result) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,10 +82,14 @@ func (ap *ActionProxy) runHandler(w http.ResponseWriter, r *http.Request) { | |
|
||
// check if the answer is an object map | ||
var objmap map[string]*json.RawMessage | ||
var objarray []interface{} | ||
err = json.Unmarshal(response, &objmap) | ||
if err != nil { | ||
sendError(w, http.StatusBadGateway, "The action did not return a dictionary or array.") | ||
return | ||
err = json.Unmarshal(response, &objarray) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First, parse the result as json, if failed, parse the result as array. |
||
if err != nil { | ||
sendError(w, http.StatusBadGateway, "The action did not return a dictionary or array.") | ||
return | ||
} | ||
} | ||
|
||
w.Header().Set("Content-Type", "application/json") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ import actionContainers.{ActionContainer, ActionProxyContainerTestUtils} | |
import actionContainers.ActionContainer.withContainer | ||
import common.WskActorSystem | ||
|
||
import spray.json.{JsObject, JsString} | ||
import spray.json.{JsArray, JsObject, JsString} | ||
|
||
abstract class ActionLoopGoContainerTests | ||
extends ActionProxyContainerTestUtils | ||
|
@@ -135,4 +135,51 @@ abstract class ActionLoopGoContainerTests | |
c.run(helloMsg()) should be(okMsg("hello-Hello", "Hello, Demo!")) | ||
} | ||
} | ||
|
||
it should "support return array result" in { | ||
val helloArrayGo = { | ||
s""" | ||
|package main | ||
| | ||
|func Main(obj map[string]interface{}) []interface{} { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So if we want to use the JSON array params, do we have to use this signature for the main function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for JSON array params, can use like blow
hm..it is better to add a test case for json array params as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok now I get it. So originally the signature of the
And now we add support for JSON array params. |
||
| result := []interface{}{"a", "b"} | ||
| return result | ||
|} | ||
| | ||
""".stripMargin | ||
} | ||
val src = ExeBuilder.mkBase64SrcZip( | ||
Seq( | ||
Seq(s"main.go") -> helloArrayGo | ||
)) | ||
withActionLoopContainer { c => | ||
c.init(initPayload(src))._1 shouldBe (200) | ||
val result = c.runForJsArray(JsObject()) | ||
result._1 shouldBe (200) | ||
result._2 shouldBe Some(JsArray(JsString("a"), JsString("b"))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Compare the result |
||
} | ||
} | ||
|
||
it should "support array as input param" in { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add another test case for support array as input param |
||
val helloArrayGo = { | ||
s""" | ||
|package main | ||
| | ||
|func Main(obj []interface{}) []interface{} { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder what happens when the argument of the main function is an array and an object parameter is passed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @upgle
Can't invoke the Main directly due to compile error, should use reflect to invoke. Btw, why can invoke Main direclty before? because the input param's data type is explicit. |
||
| return obj | ||
|} | ||
| | ||
""".stripMargin | ||
} | ||
val src = ExeBuilder.mkBase64SrcZip( | ||
Seq( | ||
Seq(s"main.go") -> helloArrayGo | ||
)) | ||
withActionLoopContainer { c => | ||
c.init(initPayload(src))._1 shouldBe (200) | ||
val result = c.runForJsArray(runPayload(JsArray(JsString("a"), JsString("b")))) | ||
result._1 shouldBe (200) | ||
result._2 shouldBe Some(JsArray(JsString("a"), JsString("b"))) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not that familiar with the runtime-go code.
Where this
Main
comes from?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the user's action's Main. i debugged the /init(or /run) before, when execute
/init
, it will inject user action codes to action container's suitable directory, the common/gobuild.py.launcher.go can recognize this Main method.