Files
fn-serverless/api/agent/drivers/docker/docker_test.go
Tolga Ceylan e67d0e5f3f fn: Call extensions/overriding and more customization friendly docker driver (#1065)
In pure-runner and LB agent, service providers might want to set specific driver options.

For example, to add cpu-shares to functions, LB can add the information as extensions
to the Call and pass this via gRPC to runners. Runners then pick these extensions from
gRPC call and pass it to driver. Using a custom driver implementation, pure-runners can
process these extensions to modify docker.CreateContainerOptions.

To achieve this, LB agents can now be configured using a call overrider.

Pure-runners can be configured using a custom docker driver.

RunnerCall and Call interfaces both expose call extensions.

An example to demonstrate this is implemented in test/fn-system-tests/system_test.go
which registers a call overrider for LB agent as well as a simple custom docker driver.
In this example, LB agent adds a key-value to extensions and runners add this key-value
as an environment variable to the container.
2018-06-18 14:42:28 -07:00

215 lines
5.4 KiB
Go

package docker
import (
"bytes"
"context"
"io"
"strings"
"testing"
"time"
"github.com/fnproject/fn/api/agent/drivers"
)
type taskDockerTest struct {
id string
input io.Reader
output io.Writer
errors io.Writer
}
func (f *taskDockerTest) Command() string { return "" }
func (f *taskDockerTest) EnvVars() map[string]string {
return map[string]string{"FN_FORMAT": "default"}
}
func (f *taskDockerTest) Id() string { return f.id }
func (f *taskDockerTest) Group() string { return "" }
func (f *taskDockerTest) Image() string { return "fnproject/fn-test-utils" }
func (f *taskDockerTest) Timeout() time.Duration { return 30 * time.Second }
func (f *taskDockerTest) Logger() (stdout, stderr io.Writer) { return f.output, f.errors }
func (f *taskDockerTest) WriteStat(context.Context, drivers.Stat) { /* TODO */ }
func (f *taskDockerTest) Volumes() [][2]string { return [][2]string{} }
func (f *taskDockerTest) Memory() uint64 { return 256 * 1024 * 1024 }
func (f *taskDockerTest) CPUs() uint64 { return 0 }
func (f *taskDockerTest) FsSize() uint64 { return 0 }
func (f *taskDockerTest) TmpFsSize() uint64 { return 0 }
func (f *taskDockerTest) WorkDir() string { return "" }
func (f *taskDockerTest) Close() {}
func (f *taskDockerTest) Input() io.Reader { return f.input }
func (f *taskDockerTest) Extensions() map[string]string { return nil }
func TestRunnerDocker(t *testing.T) {
dkr := NewDocker(drivers.Config{})
ctx := context.Background()
var output bytes.Buffer
var errors bytes.Buffer
task := &taskDockerTest{"test-docker", bytes.NewBufferString(`{"isDebug": true}`), &output, &errors}
cookie, err := dkr.CreateCookie(ctx, task)
if err != nil {
t.Fatal("Couldn't create task cookie")
}
defer cookie.Close(ctx)
err = dkr.PrepareCookie(ctx, cookie)
if err != nil {
t.Fatal("Couldn't prepare task test")
}
waiter, err := cookie.Run(ctx)
if err != nil {
t.Fatal(err)
}
result := waiter.Wait(ctx)
if result.Error() != nil {
t.Fatal(result.Error())
}
if result.Status() != "success" {
t.Fatalf("Test should successfully run the image: %s output: %s errors: %s",
result.Error(), output.String(), errors.String())
}
}
func TestRunnerDockerNetworks(t *testing.T) {
dkr := NewDocker(drivers.Config{
DockerNetworks: "test1 test2",
})
ctx := context.Background()
var output bytes.Buffer
var errors bytes.Buffer
task1 := &taskDockerTest{"test-docker1", bytes.NewBufferString(`{"isDebug": true}`), &output, &errors}
task2 := &taskDockerTest{"test-docker2", bytes.NewBufferString(`{"isDebug": true}`), &output, &errors}
cookie1, err := dkr.CreateCookie(ctx, task1)
if err != nil {
t.Fatal("Couldn't create task1 cookie")
}
defer cookie1.Close(ctx)
err = dkr.PrepareCookie(ctx, cookie1)
if err != nil {
t.Fatal("Couldn't prepare task1 test")
}
cookie2, err := dkr.CreateCookie(ctx, task2)
if err != nil {
t.Fatal("Couldn't create task2 cookie")
}
defer cookie2.Close(ctx)
err = dkr.PrepareCookie(ctx, cookie2)
if err != nil {
t.Fatal("Couldn't prepare task2 test")
}
defer cookie2.Close(ctx)
c1 := cookie1.(*cookie)
c2 := cookie2.(*cookie)
var tally = map[string]uint64{
"test1": 0,
"test2": 0,
}
tally[c1.netId]++
tally[c2.netId]++
for key, val := range tally {
if val != 1 {
t.Fatalf("netId unbalanced network usage for %s expected 1 got %d", key, val)
}
}
}
func TestRunnerDockerVersion(t *testing.T) {
dkr := NewDocker(drivers.Config{
ServerVersion: "0.0.0",
})
if dkr == nil {
t.Fatal("should not be nil")
}
err := checkDockerVersion(dkr, "1.0.0")
if err != nil {
t.Fatal(err)
}
err = checkDockerVersion(dkr, "9999.0.0")
if err == nil {
t.Fatal("should have failed")
}
}
func TestRunnerDockerStdin(t *testing.T) {
dkr := NewDocker(drivers.Config{})
ctx := context.Background()
input := `{"echoContent": "italian parsley", "isDebug": true}`
var output bytes.Buffer
var errors bytes.Buffer
task := &taskDockerTest{"test-docker-stdin", bytes.NewBufferString(input), &output, &errors}
cookie, err := dkr.CreateCookie(ctx, task)
if err != nil {
t.Fatal("Couldn't create task cookie")
}
defer cookie.Close(ctx)
err = dkr.PrepareCookie(ctx, cookie)
if err != nil {
t.Fatal("Couldn't prepare task test")
}
waiter, err := cookie.Run(ctx)
if err != nil {
t.Fatal(err)
}
result := waiter.Wait(ctx)
if result.Error() != nil {
t.Fatal(result.Error())
}
if result.Status() != "success" {
t.Fatalf("Test should successfully run the image: %s output: %s errors: %s",
result.Error(), output.String(), errors.String())
}
expect := "italian parsley"
got := output.String()
if !strings.Contains(got, expect) {
t.Errorf("Test expected output to contain '%s', got '%s'", expect, got)
}
}
//
//func TestRegistry(t *testing.T) {
// image := "fnproject/fn-test-utils"
//
// sizer, err := CheckRegistry(context.Background(), image, docker.AuthConfiguration{})
// if err != nil {
// t.Fatal("expected registry check not to fail, got:", err)
// }
//
// size, err := sizer.Size()
// if err != nil {
// t.Fatal("expected sizer not to fail, got:", err)
// }
//
// if size <= 0 {
// t.Fatal("expected positive size for image that exists, got size:", size)
// }
//}