Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
chore(tests): Add python layer contributor tests
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Meyer <[email protected]>
  • Loading branch information
menehune23 committed Oct 5, 2022
1 parent dec81bf commit db88bc7
Show file tree
Hide file tree
Showing 20 changed files with 735 additions and 53 deletions.
2 changes: 1 addition & 1 deletion buildpacks/python/cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ func main() {
logger := bard.NewLogger(os.Stdout)
libpak.Main(
python.Detect{Logger: logger},
python.Build{Logger: logger},
python.Build{Logger: logger, CommandRunner: python.NewDefaultCommandRunner()},
)
}
1 change: 1 addition & 0 deletions buildpacks/python/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.19

require (
github.com/buildpacks/libcnb v1.26.0
github.com/golang/mock v1.6.0
github.com/onsi/gomega v1.20.2
github.com/paketo-buildpacks/libpak v1.61.0
github.com/sclevine/spec v1.4.0
Expand Down
50 changes: 50 additions & 0 deletions buildpacks/python/mock_python/command_runner.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions buildpacks/python/mock_python/layer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions buildpacks/python/python/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (
)

type Build struct {
Logger bard.Logger
Logger bard.Logger
CommandRunner CommandRunner
}

func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
Expand Down Expand Up @@ -49,12 +50,12 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err)
}

invokerDepCacheLayer := NewInvokerDependencyCache(invokerDeps, dependencyCache)
invokerDepCacheLayer := NewInvokerDependencyCache(invokerDeps, dependencyCache, b.CommandRunner)
invokerDepCacheLayer.Logger = b.Logger
result.Layers = append(result.Layers, &invokerDepCacheLayer)
result.Layers = append(result.Layers, invokerDepCacheLayer)

invokerLayer := NewInvoker(invoker, dependencyCache)
result.Layers = append(result.Layers, &invokerLayer)
result.Layers = append(result.Layers, invokerLayer)

functionPlan, ok, err := planResolver.Resolve("python-function")
if err != nil {
Expand All @@ -74,8 +75,9 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {

validationLayer := NewFunctionValidationLayer(
context.Application.Path,
&invokerLayer,
&invokerDepCacheLayer,
invokerLayer,
invokerDepCacheLayer,
b.CommandRunner,
WithValidationLogger(b.Logger),
WithValidationFunctionClass(functionClass, isFuncDefDefault),
WithValidationFunctionEnvs(functionPlan.Metadata["func_yaml_envs"].(map[string]any)),
Expand Down
24 changes: 24 additions & 0 deletions buildpacks/python/python/command_runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2021-2022 VMware, Inc.
// SPDX-License-Identifier: BSD-2-Clause

package python

import (
"os/exec"
)

//go:generate mockgen -destination ../mock_python/command_runner.go . CommandRunner
type CommandRunner interface {
Run(cmd *exec.Cmd) (output string, err error)
}

type DefaultCommandRunner struct{}

func NewDefaultCommandRunner() *DefaultCommandRunner {
return &DefaultCommandRunner{}
}

func (dcr *DefaultCommandRunner) Run(cmd *exec.Cmd) (output string, err error) {
buff, err := cmd.CombinedOutput()
return string(buff), err
}
10 changes: 5 additions & 5 deletions buildpacks/python/python/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ type Function struct {
funcYamlEnvs map[string]string
}

func NewFunction(opts ...FunctionOpt) Function {
f := Function{}
func NewFunction(opts ...FunctionOpt) *Function {
f := &Function{}
meta := map[string]string{}

for _, opt := range opts {
opt(&f, meta)
opt(f, meta)
}

f.layerContributor = libpak.NewLayerContributor(
Expand All @@ -46,7 +46,7 @@ func NewFunction(opts ...FunctionOpt) Function {
return f
}

func (f Function) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
func (f *Function) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
f.layerContributor.Logger = f.logger

return f.layerContributor.Contribute(layer, func() (libcnb.Layer, error) {
Expand All @@ -70,7 +70,7 @@ func (f Function) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
})
}

func (f Function) Name() string {
func (f *Function) Name() string {
return f.layerContributor.Name
}

Expand Down
4 changes: 2 additions & 2 deletions buildpacks/python/python/invoker.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ type Invoker struct {
pythonPath string
}

func NewInvoker(dependency libpak.BuildpackDependency, cache libpak.DependencyCache) Invoker {
func NewInvoker(dependency libpak.BuildpackDependency, cache libpak.DependencyCache) *Invoker {
contributor := libpak.NewDependencyLayerContributor(dependency, cache, libcnb.LayerTypes{
Launch: true,
Cache: true,
})
return Invoker{LayerContributor: contributor}
return &Invoker{LayerContributor: contributor}
}

func (i *Invoker) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
Expand Down
23 changes: 14 additions & 9 deletions buildpacks/python/python/invoker_dependency_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package python

import (
"bytes"
"fmt"
"os"
"os/exec"
Expand All @@ -20,16 +19,24 @@ type InvokerDependencyCache struct {
LayerContributor libpak.DependencyLayerContributor
Logger bard.Logger

pythonPath string
pythonPath string
commandRunner CommandRunner
}

func NewInvokerDependencyCache(dependency libpak.BuildpackDependency, cache libpak.DependencyCache) InvokerDependencyCache {
func NewInvokerDependencyCache(
dependency libpak.BuildpackDependency,
cache libpak.DependencyCache,
commandRunner CommandRunner,
) *InvokerDependencyCache {
contributor := libpak.NewDependencyLayerContributor(dependency, cache, libcnb.LayerTypes{
Launch: true,
Cache: true,
})

return InvokerDependencyCache{LayerContributor: contributor}
return &InvokerDependencyCache{
LayerContributor: contributor,
commandRunner: commandRunner,
}
}

func (i *InvokerDependencyCache) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
Expand All @@ -53,7 +60,7 @@ func (i *InvokerDependencyCache) Contribute(layer libcnb.Layer) (libcnb.Layer, e

args := []string{
"install",
"--target=" + i.PythonPath(),
"--target", i.PythonPath(),
"--no-index",
"--find-links", depsDir,
"--compile",
Expand All @@ -69,12 +76,10 @@ func (i *InvokerDependencyCache) Contribute(layer libcnb.Layer) (libcnb.Layer, e

args = append(args, files...)

var stderr bytes.Buffer
cmd := exec.Command("pip", args...)
cmd.Stderr = &stderr

if err := cmd.Run(); err != nil {
i.Logger.Body("failed to install dependencies: %s", stderr.String())
if output, err := i.commandRunner.Run(cmd); err != nil {
i.Logger.Body("failed to install dependencies: %s", output)
return layer, err
}

Expand Down
44 changes: 21 additions & 23 deletions buildpacks/python/python/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package python

import (
"bytes"
"fmt"
"os"
"os/exec"
Expand All @@ -18,6 +17,7 @@ import (
type FunctionValidationLayer struct {
layerContributor libpak.LayerContributor
logger bard.Logger
commandRunner CommandRunner

module string
function string
Expand All @@ -31,20 +31,22 @@ type FunctionValidationLayer struct {

type FunctionValidationOpts func(*FunctionValidationLayer, map[string]string)

//go:generate mockgen -destination ../mock_python/layer.go . Layer
type Layer interface {
PythonPath() string
}

func NewFunctionValidationLayer(appPath string, invoker Layer, InvokerDepLayer Layer, opts ...FunctionValidationOpts) FunctionValidationLayer {
fvl := FunctionValidationLayer{
func NewFunctionValidationLayer(appPath string, invoker Layer, InvokerDepLayer Layer, commandRunner CommandRunner, opts ...FunctionValidationOpts) *FunctionValidationLayer {
fvl := &FunctionValidationLayer{
applicationPath: appPath,
Invoker: invoker,
InvokerDep: InvokerDepLayer,
commandRunner: commandRunner,
}
meta := map[string]string{}

for _, opt := range opts {
opt(&fvl, meta)
opt(fvl, meta)
}

fvl.layerContributor = libpak.NewLayerContributor("validation", meta, libcnb.LayerTypes{
Expand All @@ -54,44 +56,40 @@ func NewFunctionValidationLayer(appPath string, invoker Layer, InvokerDepLayer L
return fvl
}

func (i FunctionValidationLayer) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
i.layerContributor.Logger = i.logger
func (f *FunctionValidationLayer) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
f.layerContributor.Logger = f.logger

return i.layerContributor.Contribute(layer, func() (libcnb.Layer, error) {
i.logger.Body("Validating function")
return f.layerContributor.Contribute(layer, func() (libcnb.Layer, error) {
f.logger.Body("Validating function")

var pythonPath []string
if i.Invoker.PythonPath() != "" {
pythonPath = append(pythonPath, i.Invoker.PythonPath())
if f.Invoker.PythonPath() != "" {
pythonPath = append(pythonPath, f.Invoker.PythonPath())
}

if i.InvokerDep.PythonPath() != "" {
pythonPath = append(pythonPath, i.InvokerDep.PythonPath())
if f.InvokerDep.PythonPath() != "" {
pythonPath = append(pythonPath, f.InvokerDep.PythonPath())
}

if env, found := os.LookupEnv("PYTHONPATH"); found {
pythonPath = append(pythonPath, env)
}

buffer := bytes.NewBuffer(nil)
cmd := exec.Command("python", "-m", "pyfunc", "check", "-s", i.applicationPath)
// cmd := exec.Command("env")
cmd := exec.Command("python", "-m", "pyfunc", "check", "-s", f.applicationPath)
cmd.Env = append(os.Environ(), fmt.Sprintf("PYTHONPATH=%s", strings.Join(pythonPath, string(os.PathListSeparator))))
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvModuleName, i.module), fmt.Sprintf("%s=%s", EnvFunctionName, i.function))
cmd.Stderr = buffer
cmd.Stdout = buffer
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvModuleName, f.module), fmt.Sprintf("%s=%s", EnvFunctionName, f.function))

if err := cmd.Run(); err != nil {
return layer, fmt.Errorf("%v: %v", buffer.String(), err)
if output, err := f.commandRunner.Run(cmd); err != nil {
return layer, fmt.Errorf("%v: %v", output, err)
}

i.logger.Debug("Function was successfully parsed")
f.logger.Debug("Function was successfully parsed")
return layer, nil
})
}

func (i FunctionValidationLayer) Name() string {
return i.layerContributor.Name
func (f *FunctionValidationLayer) Name() string {
return f.layerContributor.Name
}

func WithValidationLogger(logger bard.Logger) FunctionValidationOpts {
Expand Down
Loading

0 comments on commit db88bc7

Please sign in to comment.