Files
fn-serverless/test/fn-system-tests/exec_fn_test.go
Tom Coupland d56a49b321 Remove V1 endpoints and Routes (#1210)
Largely a removal job, however many tests, particularly system level
ones relied on Routes. These have been migrated to use Fns.

* Add 410 response to swagger
* No app names in log tags
* Adding constraint in GetCall for FnID
* Adding test to check FnID is required on call
* Add fn_id to call selector
* Fix text in docker mem warning
* Correct buildConfig func name
* Test fix up
* Removing CPU setting from Agent test

CPU setting has been deprecated, but the code base is still riddled
with it. This just removes it from this layer. Really we need to
remove it from Call.

* Remove fn id check on calls
* Reintroduce fn id required on call
* Adding fnID to calls for execute test
* Correct setting of app id in middleware
* Removes root middlewares ability to redirect fun invocations
* Add over sized test check
* Removing call fn id check
2018-09-17 16:44:51 +01:00

290 lines
6.8 KiB
Go

package tests
import (
"bytes"
"context"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"testing"
"time"
"github.com/fnproject/fn/api/id"
"github.com/fnproject/fn/api/models"
)
// TODO deprecate with routes
func TestCanExecuteFunction(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
app := &models.App{Name: id.New().String()}
app = ensureApp(t, app)
fn := &models.Fn{
AppID: app.ID,
Name: id.New().String(),
Image: image,
Format: format,
ResourceConfig: models.ResourceConfig{
Memory: memory,
},
}
fn = ensureFn(t, fn)
lb, err := LB()
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
u := url.URL{
Scheme: "http",
Host: lb,
}
u.Path = path.Join(u.Path, "invoke", fn.ID)
body := `{"echoContent": "HelloWorld", "sleepTime": 0, "isDebug": true}`
content := bytes.NewBuffer([]byte(body))
output := &bytes.Buffer{}
resp, err := callFN(ctx, u.String(), content, output)
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
echo, err := getEchoContent(output.Bytes())
if err != nil || echo != "HelloWorld" {
t.Fatalf("getEchoContent/HelloWorld check failed on %v", output)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("StatusCode check failed on %v", resp.StatusCode)
}
// Now let's check FN_CHEESE, since LB and runners have override/extension mechanism
// to insert FN_CHEESE into config
cheese, err := getConfigContent("FN_CHEESE", output.Bytes())
if err != nil || cheese != "Tete de Moine" {
t.Fatalf("getConfigContent/FN_CHEESE check failed (%v) on %v", err, output)
}
// Now let's check FN_WINE, since runners have override to insert this.
wine, err := getConfigContent("FN_WINE", output.Bytes())
if err != nil || wine != "1982 Margaux" {
t.Fatalf("getConfigContent/FN_WINE check failed (%v) on %v", err, output)
}
}
func TestCanExecuteBigOutput(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
app := &models.App{Name: id.New().String()}
app = ensureApp(t, app)
fn := &models.Fn{
AppID: app.ID,
Name: id.New().String(),
Image: image,
Format: format,
ResourceConfig: models.ResourceConfig{
Memory: memory,
},
}
fn = ensureFn(t, fn)
lb, err := LB()
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
u := url.URL{
Scheme: "http",
Host: lb,
}
u.Path = path.Join(u.Path, "invoke", fn.ID)
// Approx 5.3MB output
body := `{"echoContent": "HelloWorld", "sleepTime": 0, "isDebug": true, "trailerRepeat": 410000}`
content := bytes.NewBuffer([]byte(body))
output := &bytes.Buffer{}
resp, err := callFN(ctx, u.String(), content, output)
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
t.Logf("getEchoContent/HelloWorld size %d", len(output.Bytes()))
echo, err := getEchoContent(output.Bytes())
if err != nil || echo != "HelloWorld" {
t.Fatalf("getEchoContent/HelloWorld check failed on %v", output)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("StatusCode check failed on %v", resp.StatusCode)
}
}
func TestCanExecuteTooBigOutput(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
app := &models.App{Name: id.New().String()}
app = ensureApp(t, app)
fn := &models.Fn{
AppID: app.ID,
Name: id.New().String(),
Image: image,
Format: format,
ResourceConfig: models.ResourceConfig{
Memory: memory,
},
}
fn = ensureFn(t, fn)
lb, err := LB()
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
u := url.URL{
Scheme: "http",
Host: lb,
}
u.Path = path.Join(u.Path, "invoke", fn.ID)
// > 6MB output
body := `{"echoContent": "HelloWorld", "sleepTime": 0, "isDebug": true, "trailerRepeat": 600000}`
content := bytes.NewBuffer([]byte(body))
output := &bytes.Buffer{}
resp, err := callFN(ctx, u.String(), content, output)
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
exp := "{\"message\":\"function response too large\"}\n"
actual := output.String()
if !strings.Contains(exp, actual) || len(exp) != len(actual) {
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", exp, output.String())
}
if resp.StatusCode != http.StatusBadGateway {
t.Fatalf("StatusCode check failed on %v", resp.StatusCode)
}
}
func TestCanExecuteEmptyOutput(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
app := &models.App{Name: id.New().String()}
app = ensureApp(t, app)
fn := &models.Fn{
AppID: app.ID,
Name: id.New().String(),
Image: image,
Format: format,
ResourceConfig: models.ResourceConfig{
Memory: memory,
},
}
fn = ensureFn(t, fn)
lb, err := LB()
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
u := url.URL{
Scheme: "http",
Host: lb,
}
u.Path = path.Join(u.Path, "invoke", fn.ID)
// empty body output
body := `{"sleepTime": 0, "isDebug": true, "isEmptyBody": true}`
content := bytes.NewBuffer([]byte(body))
output := &bytes.Buffer{}
resp, err := callFN(ctx, u.String(), content, output)
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
actual := output.String()
if 0 != len(actual) {
t.Fatalf("Assertion error.\n\tExpected empty\n\tActual: %v", output.String())
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("StatusCode check failed on %v", resp.StatusCode)
}
}
func TestBasicConcurrentExecution(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
app := &models.App{Name: id.New().String()}
app = ensureApp(t, app)
fn := &models.Fn{
AppID: app.ID,
Name: id.New().String(),
Image: image,
Format: format,
ResourceConfig: models.ResourceConfig{
Memory: memory,
},
}
fn = ensureFn(t, fn)
lb, err := LB()
if err != nil {
t.Fatalf("Got unexpected error: %v", err)
}
u := url.URL{
Scheme: "http",
Host: lb,
}
u.Path = path.Join(u.Path, "invoke", fn.ID)
results := make(chan error)
concurrentFuncs := 10
for i := 0; i < concurrentFuncs; i++ {
go func() {
body := `{"echoContent": "HelloWorld", "sleepTime": 0, "isDebug": true}`
content := bytes.NewBuffer([]byte(body))
output := &bytes.Buffer{}
resp, err := callFN(ctx, u.String(), content, output)
if err != nil {
results <- fmt.Errorf("Got unexpected error: %v", err)
return
}
echo, err := getEchoContent(output.Bytes())
if err != nil || echo != "HelloWorld" {
results <- fmt.Errorf("Assertion error.\n\tActual: %v", output.String())
return
}
if resp.StatusCode != http.StatusOK {
results <- fmt.Errorf("StatusCode check failed on %v", resp.StatusCode)
return
}
results <- nil
}()
}
for i := 0; i < concurrentFuncs; i++ {
err := <-results
if err != nil {
t.Fatalf("Error in basic concurrency execution test: %v", err)
}
}
}