fn: more functionality into fn-test-utils (#752)

read/write a file on disk, alloc/leak memory.
This commit is contained in:
Tolga Ceylan
2018-02-09 13:23:40 -08:00
committed by GitHub
parent 27179ddf54
commit bed3b5ddff

View File

@@ -4,11 +4,13 @@ import (
"context"
"encoding/json"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"time"
fdk "github.com/fnproject/fdk-go"
"net/http"
)
type AppRequest struct {
@@ -24,18 +26,48 @@ type AppRequest struct {
IsDebug bool `json:"isDebug,omitempty"`
// simulate crash
IsCrash bool `json:"isCrash,omitempty"`
// read a file from disk
ReadFile string `json:"readFile,omitempty"`
// fill created with with zero bytes of specified size
ReadFileSize int `json:"readFileSize,omitempty"`
// create a file on disk
CreateFile string `json:"createFile,omitempty"`
// fill created with with zero bytes of specified size
CreateFileSize int `json:"createFileSize,omitempty"`
// allocate RAM and hold until next request
AllocateMemory int `json:"allocateMemory,om itempty"`
// leak RAM forever
LeakMemory int `json:"leakMemory,omitempty"`
// TODO: simulate slow read/slow write
// TODO: simulate partial write/read
// TODO: simulate mem leak
// TODO: simulate high cpu usage
// TODO: simulate high mem usage
// TODO: simulate partial IO write/read
// TODO: simulate high cpu usage (async and sync)
// TODO: simulate large body upload/download
// TODO: infinite loop
}
// ever growing memory leak chunks
var Leaks []*[]byte
// memory to hold on to at every request, new requests overwrite it.
var Hold []byte
type AppResponse struct {
Request AppRequest `json:"request"`
Headers http.Header `json:"header"`
Config map[string]string `json:"config"`
Data map[string]string `json:"data"`
}
func init() {
Leaks = make([]*[]byte, 0, 0)
}
func getTotalLeaks() int {
total := 0
for idx, _ := range Leaks {
total += len(*(Leaks[idx]))
}
return total
}
func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
@@ -59,11 +91,6 @@ func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
time.Sleep(time.Duration(request.SleepTime) * time.Millisecond)
}
// simulate crash
if request.IsCrash {
panic("Crash requested")
}
// custom response code
if request.ResponseCode != 0 {
fdk.WriteStatus(out, request.ResponseCode)
@@ -78,7 +105,54 @@ func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
fdk.SetHeader(out, "Content-Type", "application/json")
}
data := make(map[string]string)
// read a file
if request.ReadFile != "" {
if request.IsDebug {
log.Printf("Reading file %s", request.ReadFile)
}
out, err := readFile(request.ReadFile, request.ReadFileSize)
if err != nil {
data[request.ReadFile+".read_error"] = err.Error()
} else {
data[request.ReadFile+".read_output"] = out
}
}
// create a file
if request.CreateFile != "" {
if request.IsDebug {
log.Printf("Creating file %s (size: %d)", request.CreateFile, request.CreateFileSize)
}
err := createFile(request.CreateFile, request.CreateFileSize)
if err != nil {
data[request.CreateFile+".create_error"] = err.Error()
}
}
// handle one time alloc request (hold on to the memory until next request)
if request.AllocateMemory != 0 && request.IsDebug {
log.Printf("Allocating memory size: %d", request.AllocateMemory)
}
Hold = getChunk(request.AllocateMemory)
// leak memory forever
if request.LeakMemory != 0 {
if request.IsDebug {
log.Printf("Leaking memory size: %d total: %d", request.LeakMemory, getTotalLeaks())
}
chunk := getChunk(request.LeakMemory)
Leaks = append(Leaks, &chunk)
}
// simulate crash
if request.IsCrash {
panic("Crash requested")
}
resp := AppResponse{
Data: data,
Request: request,
Headers: fnctx.Header,
Config: fnctx.Config,
@@ -90,3 +164,40 @@ func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
func main() {
fdk.Handle(fdk.HandlerFunc(AppHandler))
}
func getChunk(size int) []byte {
chunk := make([]byte, size)
// fill it
for idx, _ := range chunk {
chunk[idx] = 1
}
return chunk
}
func readFile(name string, size int) (string, error) {
// read the whole file into memory
out, err := ioutil.ReadFile(name)
if err != nil {
return "", err
}
// only respond with partion output if requested
if size > 0 {
return string(out[:size]), nil
}
return string(out), nil
}
func createFile(name string, size int) error {
f, err := os.Create(name)
if err != nil {
return err
}
if size > 0 {
err := f.Truncate(int64(size))
if err != nil {
return err
}
}
return nil
}