mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
related: https://github.com/fnproject/fdk-go/pull/26 (#968)
adds a test for the protocol dumping of a request to the containert stdin.
there are a number of vectors to test for a cloud event, but since we're going
to change that behavior soon it's probably a waste of time to go about doing
so. in any event, this was pretty broken. my understanding of the cloud event
spec is deepening and the json stuff overall seems a little weird.
* fixes content type issue around json checking (since a string is also a json
value, we can just decode it, even though it's wasteful it's more easily
correct)
* doesn't force all json values to be map[string]interface{} and lets them be
whoever they want to be. maybe their dads are still proud.
closes #966
This commit is contained in:
@@ -21,11 +21,11 @@ type CloudEvent struct {
|
|||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
EventType string `json:"eventType"`
|
EventType string `json:"eventType"`
|
||||||
EventTypeVersion string `json:"eventTypeVersion"`
|
EventTypeVersion string `json:"eventTypeVersion"`
|
||||||
EventTime time.Time `json:"eventTime"` // TODO: ensure rfc3339 format
|
EventTime time.Time `json:"eventTime"`
|
||||||
SchemaURL string `json:"schemaURL"`
|
SchemaURL string `json:"schemaURL"`
|
||||||
ContentType string `json:"contentType"`
|
ContentType string `json:"contentType"`
|
||||||
Extensions map[string]interface{} `json:"extensions"`
|
Extensions map[string]interface{} `json:"extensions"`
|
||||||
Data interface{} `json:"data"` // from docs: the payload is encoded into a media format which is specified by the contentType attribute (e.g. application/json)
|
Data interface{} `json:"data,omitempty"` // docs: the payload is encoded into a media format which is specified by the contentType attribute (e.g. application/json)
|
||||||
}
|
}
|
||||||
|
|
||||||
type cloudEventIn struct {
|
type cloudEventIn struct {
|
||||||
@@ -63,6 +63,8 @@ func (h *CloudEventProtocol) writeJSONToContainer(ci CallInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: handle binary
|
||||||
|
|
||||||
var in cloudEventIn
|
var in cloudEventIn
|
||||||
if ci.IsCloudEvent() {
|
if ci.IsCloudEvent() {
|
||||||
// then it's already in the right format, let's parse it, then modify
|
// then it's already in the right format, let's parse it, then modify
|
||||||
@@ -80,18 +82,13 @@ func (h *CloudEventProtocol) writeJSONToContainer(ci CallInfo) error {
|
|||||||
Source: ci.RequestURL(),
|
Source: ci.RequestURL(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if buf.Len() == 0 {
|
// NOTE: data is an optional field, we can leave it as nil
|
||||||
// nada
|
if buf.Len() > 0 {
|
||||||
// todo: should we leave as null, pass in empty string, omitempty or some default for the content type, eg: {} for json?
|
// NOTE: if it's not contentType=application/json, then a string is a valid json value, so this will work.
|
||||||
} else if ci.ContentType() == "application/json" {
|
err := json.NewDecoder(buf).Decode(&in.Data)
|
||||||
d := map[string]interface{}{}
|
|
||||||
err = json.NewDecoder(buf).Decode(&d)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Invalid json body with contentType 'application/json'. %v", err)
|
return fmt.Errorf("Invalid json body with contentType 'application/json'. %v", err)
|
||||||
}
|
}
|
||||||
in.Data = d
|
|
||||||
} else {
|
|
||||||
in.Data = buf.String()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// todo: deal with the dual ID's, one from outside, one from inside
|
// todo: deal with the dual ID's, one from outside, one from inside
|
||||||
|
|||||||
100
api/agent/protocol/cloudevent_test.go
Normal file
100
api/agent/protocol/cloudevent_test.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// implements CallInfo, modify as needed
|
||||||
|
type testCall struct {
|
||||||
|
cloud bool
|
||||||
|
contentType string
|
||||||
|
input io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testCall) IsCloudEvent() bool { return t.cloud }
|
||||||
|
func (t *testCall) CallID() string { return "foo" }
|
||||||
|
func (t *testCall) ContentType() string { return t.contentType }
|
||||||
|
func (t *testCall) Input() io.Reader { return t.input }
|
||||||
|
func (t *testCall) Deadline() strfmt.DateTime {
|
||||||
|
return strfmt.DateTime(time.Now().Add(30 * time.Second))
|
||||||
|
}
|
||||||
|
func (t *testCall) CallType() string { return "sync" }
|
||||||
|
func (t *testCall) ProtocolType() string { return "http" }
|
||||||
|
func (t *testCall) Request() *http.Request { return nil } // unused here
|
||||||
|
func (t *testCall) Method() string { return "GET" }
|
||||||
|
func (t *testCall) RequestURL() string { return "http://example.com/r/yo/dawg" }
|
||||||
|
func (t *testCall) Headers() map[string][]string { return map[string][]string{} }
|
||||||
|
|
||||||
|
func TestJSONMap(t *testing.T) {
|
||||||
|
in := strings.NewReader(`{"yo":"dawg"}`)
|
||||||
|
|
||||||
|
var ib, ob bytes.Buffer
|
||||||
|
cep := &CloudEventProtocol{
|
||||||
|
in: &ib,
|
||||||
|
out: &ob,
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := &testCall{false, "application/json; charset=utf-8", in}
|
||||||
|
|
||||||
|
err := cep.writeJSONToContainer(tc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var oce CloudEvent
|
||||||
|
err = json.NewDecoder(&ib).Decode(&oce)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mappo, ok := oce.Data.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("data field should be map[string]interface{}: %T", oce.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := mappo["yo"].(string)
|
||||||
|
if v != "dawg" {
|
||||||
|
t.Fatal("value in map is wrong", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONNotMap(t *testing.T) {
|
||||||
|
// we accept all json values here https://tools.ietf.org/html/rfc7159#section-3
|
||||||
|
in := strings.NewReader(`true`)
|
||||||
|
|
||||||
|
var ib, ob bytes.Buffer
|
||||||
|
cep := &CloudEventProtocol{
|
||||||
|
in: &ib,
|
||||||
|
out: &ob,
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := &testCall{false, "application/json", in}
|
||||||
|
|
||||||
|
err := cep.writeJSONToContainer(tc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var oce CloudEvent
|
||||||
|
err = json.NewDecoder(&ib).Decode(&oce)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolo, ok := oce.Data.(bool)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("data field should be bool: %T", oce.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !boolo {
|
||||||
|
t.Fatal("bool should be true", boolo)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user