Files
fn-serverless/api/agent/protocol/json_test.go
Tolga Ceylan a57907eed0 fn: user friendly timeout handling changes (#1021)
* fn: user friendly timeout handling changes

Timeout setting in routes now means "maximum amount
of time a function can run in a container".

Total wait time for a given http request is now expected
to be handled by the client. As long as the client waits,
the LB, runner or agents will search for resources to
schedule it.
2018-06-01 13:18:13 -07:00

213 lines
5.4 KiB
Go

package protocol
import (
"bytes"
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
"github.com/fnproject/fn/api/models"
)
type RequestData struct {
A string `json:"a"`
}
func setupRequest(data interface{}) (*callInfoImpl, context.CancelFunc) {
req := &http.Request{
Method: http.MethodPost,
URL: &url.URL{
Scheme: "http",
Host: "localhost:8080",
Path: "/v1/apps",
RawQuery: "something=something&etc=etc",
},
ProtoMajor: 1,
ProtoMinor: 1,
Header: http.Header{
"Host": []string{"localhost:8080"},
"User-Agent": []string{"curl/7.51.0"},
"Content-Type": []string{"application/json"},
},
Host: "localhost:8080",
}
var buf bytes.Buffer
if data != nil {
_ = json.NewEncoder(&buf).Encode(data)
}
req.Body = ioutil.NopCloser(&buf)
call := &models.Call{Type: "sync"}
// fixup URL in models.Call
call.URL = req.URL.String()
ctx, cancel := context.WithTimeout(req.Context(), 1*time.Second)
ci := &callInfoImpl{call: call, req: req.WithContext(ctx)}
return ci, cancel
}
func TestJSONProtocolwriteJSONInputRequestBasicFields(t *testing.T) {
ci, cancel := setupRequest(nil)
defer cancel()
r, w := io.Pipe()
proto := JSONProtocol{w, r}
go func() {
err := proto.writeJSONToContainer(ci)
if err != nil {
t.Error(err.Error())
}
w.Close()
}()
incomingReq := &jsonIn{}
bb := new(bytes.Buffer)
_, err := bb.ReadFrom(r)
if err != nil {
t.Error(err.Error())
}
err = json.Unmarshal(bb.Bytes(), incomingReq)
if err != nil {
t.Error(err.Error())
}
if incomingReq.CallID != ci.CallID() {
t.Errorf("Request CallID assertion mismatch: expected: %s, got %s",
ci.CallID(), incomingReq.CallID)
}
if incomingReq.ContentType != ci.ContentType() {
t.Errorf("Request ContentType assertion mismatch: expected: %s, got %s",
ci.ContentType(), incomingReq.ContentType)
}
if incomingReq.Deadline != ci.Deadline().String() {
t.Errorf("Request Deadline assertion mismatch: expected: %s, got %s",
ci.Deadline(), incomingReq.Deadline)
}
}
func TestJSONProtocolwriteJSONInputRequestWithData(t *testing.T) {
rDataBefore := RequestData{A: "a"}
ci, cancel := setupRequest(rDataBefore)
defer cancel()
r, w := io.Pipe()
proto := JSONProtocol{w, r}
go func() {
err := proto.writeJSONToContainer(ci)
if err != nil {
t.Error(err.Error())
}
w.Close()
}()
incomingReq := &jsonIn{}
bb := new(bytes.Buffer)
_, err := bb.ReadFrom(r)
if err != nil {
t.Error(err.Error())
}
err = json.Unmarshal(bb.Bytes(), incomingReq)
if err != nil {
t.Error(err.Error())
}
rDataAfter := new(RequestData)
err = json.Unmarshal([]byte(incomingReq.Body), &rDataAfter)
if err != nil {
t.Error(err.Error())
}
if rDataBefore.A != rDataAfter.A {
t.Errorf("Request data assertion mismatch: expected: %s, got %s",
rDataBefore.A, rDataAfter.A)
}
if incomingReq.Protocol.Type != ci.ProtocolType() {
t.Errorf("Call protocol type assertion mismatch: expected: %s, got %s",
ci.ProtocolType(), incomingReq.Protocol.Type)
}
if incomingReq.Protocol.Method != ci.Method() {
t.Errorf("Call protocol method assertion mismatch: expected: %s, got %s",
ci.Method(), incomingReq.Protocol.Method)
}
if incomingReq.Protocol.RequestURL != ci.RequestURL() {
t.Errorf("Call protocol request URL assertion mismatch: expected: %s, got %s",
ci.RequestURL(), incomingReq.Protocol.RequestURL)
}
}
func TestJSONProtocolwriteJSONInputRequestWithoutData(t *testing.T) {
ci, cancel := setupRequest(nil)
defer cancel()
r, w := io.Pipe()
proto := JSONProtocol{w, r}
go func() {
err := proto.writeJSONToContainer(ci)
if err != nil {
t.Error(err.Error())
}
w.Close()
}()
incomingReq := &jsonIn{}
bb := new(bytes.Buffer)
_, err := bb.ReadFrom(r)
if err != nil {
t.Error(err.Error())
}
err = json.Unmarshal(bb.Bytes(), incomingReq)
if err != nil {
t.Error(err.Error())
}
if incomingReq.Body != "" {
t.Errorf("Request body assertion mismatch: expected: %s, got %s",
"<empty-string>", incomingReq.Body)
}
if !models.Headers(ci.req.Header).Equals(models.Headers(incomingReq.Protocol.Headers)) {
t.Errorf("Request headers assertion mismatch: expected: %s, got %s",
ci.req.Header, incomingReq.Protocol.Headers)
}
if incomingReq.Protocol.Type != ci.ProtocolType() {
t.Errorf("Call protocol type assertion mismatch: expected: %s, got %s",
ci.ProtocolType(), incomingReq.Protocol.Type)
}
if incomingReq.Protocol.Method != ci.Method() {
t.Errorf("Call protocol method assertion mismatch: expected: %s, got %s",
ci.Method(), incomingReq.Protocol.Method)
}
if incomingReq.Protocol.RequestURL != ci.RequestURL() {
t.Errorf("Call protocol request URL assertion mismatch: expected: %s, got %s",
ci.RequestURL(), incomingReq.Protocol.RequestURL)
}
}
func TestJSONProtocolwriteJSONInputRequestWithQuery(t *testing.T) {
ci, cancel := setupRequest(nil)
defer cancel()
r, w := io.Pipe()
proto := JSONProtocol{w, r}
go func() {
err := proto.writeJSONToContainer(ci)
if err != nil {
t.Error(err.Error())
}
w.Close()
}()
incomingReq := &jsonIn{}
bb := new(bytes.Buffer)
_, err := bb.ReadFrom(r)
if err != nil {
t.Error(err.Error())
}
err = json.Unmarshal(bb.Bytes(), incomingReq)
if err != nil {
t.Error(err.Error())
}
if incomingReq.Protocol.RequestURL != ci.call.URL {
t.Errorf("Request URL does not match protocol URL: expected: %s, got %s",
ci.call.URL, incomingReq.Protocol.RequestURL)
}
}