mirror of https://github.com/knative/func.git
core tests with mocks for pusher and deployer
This commit is contained in:
parent
713ae960dd
commit
8d09582051
|
@ -34,28 +34,28 @@ type DNSProvider interface {
|
||||||
|
|
||||||
// Initializer creates the initial/stub Service Function code on first create.
|
// Initializer creates the initial/stub Service Function code on first create.
|
||||||
type Initializer interface {
|
type Initializer interface {
|
||||||
// Initialize a Service Function of the given language, in root, with name.
|
// Initialize a Service Function of the given name, using the templates for
|
||||||
|
// the given language, written into the given path.
|
||||||
Initialize(name, language, path string) error
|
Initialize(name, language, path string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder of function source to runnable image.
|
// Builder of function source to runnable image.
|
||||||
type Builder interface {
|
type Builder interface {
|
||||||
// Build a runnable image of the function whose source is located at path,
|
// Build a function service of the given name with source located at path.
|
||||||
// returning an image.
|
// returns the image name built.
|
||||||
Build(name, path string) (image string, err error)
|
Build(name, path string) (image string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pusher of function image to a registry.
|
// Pusher of function image to a registry.
|
||||||
type Pusher interface {
|
type Pusher interface {
|
||||||
// Push a runnable image of the function to a registry.
|
// Push the image of the function service.
|
||||||
Push(image string) error
|
Push(image string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deployer of function source to running status.
|
// Deployer of function source to running status.
|
||||||
type Deployer interface {
|
type Deployer interface {
|
||||||
// Deploy a function of the given name whose source is located at path,
|
// Deploy a service function of given name, using given backing image.
|
||||||
// returning an address.
|
Deploy(name, image string) (address string, err error)
|
||||||
Deploy(name, path string) (address string, err error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runner runs the function locally.
|
// Runner runs the function locally.
|
||||||
|
@ -212,7 +212,7 @@ func (c *Client) Create(language string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the image to the configured registry
|
// Push the image for the names service to the configured registry
|
||||||
if err = c.pusher.Push(image); err != nil {
|
if err = c.pusher.Push(image); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ type manualBuilder struct {
|
||||||
output io.Writer
|
output io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *manualBuilder) Build(name, root string) (string, error) {
|
func (i *manualBuilder) Build(name, root string) (image string, err error) {
|
||||||
fmt.Fprintf(i.output, "Please manually build image for '%v' using code at '%v'\n", name, root)
|
fmt.Fprintf(i.output, "Please manually build image for '%v' using code at '%v'\n", name, root)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ type manualPusher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *manualPusher) Push(image string) error {
|
func (i *manualPusher) Push(image string) error {
|
||||||
fmt.Fprintf(i.output, "Please manually push image '%v'", image)
|
fmt.Fprintf(i.output, "Please manually push image '%v'\n", image)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,8 +369,8 @@ type manualDeployer struct {
|
||||||
output io.Writer
|
output io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *manualDeployer) Deploy(name, root string) (string, error) {
|
func (i *manualDeployer) Deploy(name, image string) (string, error) {
|
||||||
fmt.Fprintf(i.output, "Please manually deploy '%v' using code at '%v'\n", name, root)
|
fmt.Fprintf(i.output, "Please manually deploy '%v'\n", name)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,11 @@ import (
|
||||||
"github.com/lkingland/faas/client/mock"
|
"github.com/lkingland/faas/client/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestNew ensures that instantiation succeeds when invoked normally
|
// TestNew ensures that instantiation succeeds or fails as expected.
|
||||||
// and fails if not given a deriveable domain.
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
// Instantiation with optional explicit service name should succeed.
|
// Instantiation with optional explicit service name should succeed.
|
||||||
_, err := client.New(
|
_, err := client.New(
|
||||||
client.WithName("my.example.com"), // be explicity rather than path-derive
|
client.WithName("my.example.com")) // be explicit rather than path-derive
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -28,8 +26,8 @@ func TestNew(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiation without an explicit service name, and no derivable service
|
// Instantiation without an explicit service name, but no derivable service
|
||||||
// name (because of limiting path recursion for deriviation) should fail.
|
// name (because of limiting path recursion) should fail.
|
||||||
_, err = client.New(
|
_, err = client.New(
|
||||||
client.WithDomainSearchLimit(0), // limit ability to derive from path.
|
client.WithDomainSearchLimit(0), // limit ability to derive from path.
|
||||||
)
|
)
|
||||||
|
@ -44,18 +42,25 @@ func TestNew(t *testing.T) {
|
||||||
// parameter, as it is derived from path by default.
|
// parameter, as it is derived from path by default.
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
client, err := client.New(
|
client, err := client.New(
|
||||||
client.WithName("my.example.com"), // be explicity rather than path-derive
|
client.WithName("my.example.com"),
|
||||||
client.WithVerbose(true), // enable verbose logging
|
client.WithInitializer(mock.NewInitializer()),
|
||||||
)
|
) // be explicit rather than path-derive
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// missing language should error
|
|
||||||
|
// create a Function Service call missing language should error
|
||||||
if err := client.Create(""); err == nil {
|
if err := client.Create(""); err == nil {
|
||||||
t.Fatal("missing language did not generate error")
|
t.Fatal("missing language did not generate error")
|
||||||
}
|
}
|
||||||
// Any language provided works by default, with the concrete implementation
|
|
||||||
// of the initializer being the decider if the language provided is supported.
|
// create a Function Service call witn an unsupported language should bubble
|
||||||
|
// the error generated by the underlying initializer.
|
||||||
|
if err := client.Create("cobol"); err == nil {
|
||||||
|
t.Fatal("unsupported language did not generate error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A supported langauge should not error.
|
||||||
if err := client.Create("go"); err != nil {
|
if err := client.Create("go"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -65,10 +70,10 @@ func TestCreate(t *testing.T) {
|
||||||
// Initializer, Builder, Pusher and Deployer with expected parameters.
|
// Initializer, Builder, Pusher and Deployer with expected parameters.
|
||||||
func TestCreateDelegates(t *testing.T) {
|
func TestCreateDelegates(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
path = "testdata/example.com/admin"
|
path = "testdata/example.com/admin" // .. in which to initialize
|
||||||
name = "admin.example.com"
|
name = "admin.example.com" // expected to be derived
|
||||||
image = "example.registry/user/datestamp-hash"
|
image = "my.hub/user/imagestamp" // expected image
|
||||||
route = "https://admin.example.com/"
|
route = "https://admin.example.com/" // expected final route
|
||||||
initializer = mock.NewInitializer()
|
initializer = mock.NewInitializer()
|
||||||
builder = mock.NewBuilder()
|
builder = mock.NewBuilder()
|
||||||
pusher = mock.NewPusher()
|
pusher = mock.NewPusher()
|
||||||
|
@ -86,7 +91,10 @@ func TestCreateDelegates(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The initializer should receive the name expected from the path,
|
// Register function delegates on the mocks which validate assertions
|
||||||
|
// -------------
|
||||||
|
|
||||||
|
// The initializer should receive the name expected from the path,
|
||||||
// the passed language, and an absolute path to the funciton soruce.
|
// the passed language, and an absolute path to the funciton soruce.
|
||||||
initializer.InitializeFn = func(name, language, path string) error {
|
initializer.InitializeFn = func(name, language, path string) error {
|
||||||
if name != "admin.example.com" {
|
if name != "admin.example.com" {
|
||||||
|
@ -108,22 +116,24 @@ func TestCreateDelegates(t *testing.T) {
|
||||||
// The builder should be invoked with a service name and path to its source
|
// The builder should be invoked with a service name and path to its source
|
||||||
// function code. For this test, it is a name derived from the test path.
|
// function code. For this test, it is a name derived from the test path.
|
||||||
// An example image name is returned.
|
// An example image name is returned.
|
||||||
builder.BuildFn = func(name2, path2 string) (image2 string, err error) {
|
builder.BuildFn = func(name2, path2 string) (string, error) {
|
||||||
if name != name {
|
if name != name {
|
||||||
t.Fatalf("deployer expected name %v, got '%v'", name, name2)
|
t.Fatalf("builder expected name %v, got '%v'", name, name2)
|
||||||
}
|
}
|
||||||
expectedPath, err := filepath.Abs(path)
|
expectedPath, err := filepath.Abs(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if path2 != expectedPath {
|
if path2 != expectedPath {
|
||||||
t.Fatalf("deployer expected path '%v', got '%v'", expectedPath, path)
|
t.Fatalf("builder expected path '%v', got '%v'", expectedPath, path)
|
||||||
}
|
}
|
||||||
// image name would be calculated from registry, user, time and git hash
|
// The final image name will be determined by the builder implementation,
|
||||||
|
// but whatever it is (in this case fabricarted); it should be returned
|
||||||
|
// and later provided to the pusher.
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pusher should be invoked with the image name generated by the builder.
|
// The pusher should be invoked with the image to push.
|
||||||
pusher.PushFn = func(image2 string) error {
|
pusher.PushFn = func(image2 string) error {
|
||||||
if image2 != image {
|
if image2 != image {
|
||||||
t.Fatalf("pusher expected image '%v', got '%v'", image, image2)
|
t.Fatalf("pusher expected image '%v', got '%v'", image, image2)
|
||||||
|
@ -134,19 +144,20 @@ func TestCreateDelegates(t *testing.T) {
|
||||||
|
|
||||||
// The deployer should be invoked with the service name and image, and return
|
// The deployer should be invoked with the service name and image, and return
|
||||||
// the final accessible address.
|
// the final accessible address.
|
||||||
deployer.DeployFn = func(name2, image2 string) (address string, err error) {
|
deployer.DeployFn = func(name2 string) (address string, err error) {
|
||||||
if name2 != name {
|
if name2 != name {
|
||||||
t.Fatalf("deployer expected name '%v', got '%v'", name, name2)
|
t.Fatalf("deployer expected name '%v', got '%v'", name, name2)
|
||||||
}
|
}
|
||||||
if image2 != image {
|
|
||||||
t.Fatalf("deployer expected image '%v', got '%v'", image, image2)
|
|
||||||
}
|
|
||||||
// service of given name would be deployed using the given image and
|
// service of given name would be deployed using the given image and
|
||||||
// allocated route returned.
|
// allocated route returned.
|
||||||
return route, nil
|
return route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the Creation task using a valid language.
|
// Invocation
|
||||||
|
// -------------
|
||||||
|
|
||||||
|
// Invoke the creation, triggering the function delegates, and
|
||||||
|
// perform follow-up assertions that the functions were indeed invoked.
|
||||||
if err := client.Create("go"); err != nil {
|
if err := client.Create("go"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ func NewBuilder() *Builder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Builder) Build(name, path string) (image string, err error) {
|
func (i *Builder) Build(name, path string) (string, error) {
|
||||||
i.BuildInvoked = true
|
i.BuildInvoked = true
|
||||||
return i.BuildFn(name, path)
|
return i.BuildFn(name, path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package mock
|
||||||
|
|
||||||
type Deployer struct {
|
type Deployer struct {
|
||||||
DeployInvoked bool
|
DeployInvoked bool
|
||||||
DeployFn func(name, path string) (address string, err error)
|
DeployFn func(name, image string) (address string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDeployer() *Deployer {
|
func NewDeployer() *Deployer {
|
||||||
|
@ -11,7 +11,7 @@ func NewDeployer() *Deployer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Deployer) Deploy(name, path string) (address string, err error) {
|
func (i *Deployer) Deploy(name, image string) (address string, err error) {
|
||||||
i.DeployInvoked = true
|
i.DeployInvoked = true
|
||||||
return i.DeployFn(name, path)
|
return i.DeployFn(name, image)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ func NewInitializer() *Initializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Initializer) Initialize(name, language, path string) error {
|
func (i *Initializer) Initialize(name, language, path string) error {
|
||||||
|
fmt.Printf("Validating language supported: %v\n", language)
|
||||||
i.InitializeInvoked = true
|
i.InitializeInvoked = true
|
||||||
if !i.supportsLanguage(language) {
|
if !i.supportsLanguage(language) {
|
||||||
return errors.New(fmt.Sprintf("unsupported language '%v'", language))
|
return errors.New(fmt.Sprintf("unsupported language '%v'", language))
|
||||||
|
|
Loading…
Reference in New Issue