Skip to content

Commit

Permalink
feat(cli): Implementing trigger preprocessor (kubeshop#3990)
Browse files Browse the repository at this point in the history
* feat(cli): Implementing trigger preprocessor

* feat(cli): Implementing trigger preprocessor

* fixing logger bug
  • Loading branch information
xoscar authored Aug 28, 2024
1 parent 3af9524 commit 6946b7d
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 75 deletions.
Binary file added agent/workers/trigger/trace.zip
Binary file not shown.
9 changes: 8 additions & 1 deletion cli/cmd/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"github.com/kubeshop/tracetest/cli/pkg/resourcemanager"
"github.com/kubeshop/tracetest/cli/processor"
"github.com/kubeshop/tracetest/cli/processor/trigger_preprocessor"
"github.com/kubeshop/tracetest/cli/runner"
)

Expand Down Expand Up @@ -117,7 +118,13 @@ var (
resourcemanager.WithApplyPostProcessor(environmentPostproessor.Postprocess),
)

testPreprocessor = processor.Test(cliLogger, func(ctx context.Context, input fileutil.File) (fileutil.File, error) {
triggerPreprocessorRegistry = trigger_preprocessor.NewRegistry(cliLogger).
Register(trigger_preprocessor.GRPC(cliLogger)).
Register(trigger_preprocessor.PLAYWRIGHTENGINE(cliLogger)).
Register(trigger_preprocessor.GRAPHQL(cliLogger)).
Register(trigger_preprocessor.HTTP(cliLogger))

testPreprocessor = processor.Test(cliLogger, triggerPreprocessorRegistry, func(ctx context.Context, input fileutil.File) (fileutil.File, error) {
updated, err := pollingProfileClient.Apply(ctx, input, resourcemanager.Formats.Get(resourcemanager.FormatYAML))
if err != nil {
return input, fmt.Errorf("cannot apply polling profile: %w", err)
Expand Down
84 changes: 10 additions & 74 deletions cli/processor/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ import (
"github.com/kubeshop/tracetest/cli/cmdutil"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"github.com/kubeshop/tracetest/cli/processor/trigger_preprocessor"
"go.uber.org/zap"
)

type test struct {
logger *zap.Logger
applyPollingProfileFunc applyResourceFunc
logger *zap.Logger
applyPollingProfileFunc applyResourceFunc
triggerProcessorRegistry trigger_preprocessor.Registry
}

func Test(logger *zap.Logger, applyPollingProfileFunc applyResourceFunc) test {
func Test(logger *zap.Logger, triggerProcessorRegistry trigger_preprocessor.Registry, applyPollingProfileFunc applyResourceFunc) test {
return test{
logger: cmdutil.GetLogger(),
applyPollingProfileFunc: applyPollingProfileFunc,
logger: cmdutil.GetLogger(),
applyPollingProfileFunc: applyPollingProfileFunc,
triggerProcessorRegistry: triggerProcessorRegistry,
}
}

Expand All @@ -37,14 +40,9 @@ func (t test) Preprocess(ctx context.Context, input fileutil.File) (fileutil.Fil
return input, fmt.Errorf("could not map polling profiles referenced in test yaml: %w", err)
}

test, err = t.consolidateGRPCFile(input, test)
test, err = t.triggerProcessorRegistry.Preprocess(input, test)
if err != nil {
return input, fmt.Errorf("could not consolidate grpc file: %w", err)
}

test, err = t.consolidateScriptFile(input, test)
if err != nil {
return input, fmt.Errorf("could not consolidate playwrightengine script file: %w", err)
return input, fmt.Errorf("could not preprocess trigger: %w", err)
}

marshalled, err := yaml.Marshal(test)
Expand Down Expand Up @@ -89,65 +87,3 @@ func (t test) mapPollingProfiles(ctx context.Context, input fileutil.File, test

return test, nil
}

func (t test) consolidateGRPCFile(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
if test.Spec.Trigger.GetType() != "grpc" {
t.logger.Debug("test does not use grpc", zap.String("triggerType", test.Spec.Trigger.GetType()))
return test, nil
}

definedPBFile := test.Spec.Trigger.Grpc.GetProtobufFile()
if !t.isValidGrpcFilePath(definedPBFile, input.AbsDir()) {
t.logger.Debug("protobuf file is not a file path", zap.String("protobufFile", definedPBFile))
return test, nil
}

pbFilePath := input.RelativeFile(definedPBFile)
t.logger.Debug("protobuf file", zap.String("path", pbFilePath))

pbFile, err := fileutil.Read(pbFilePath)
if err != nil {
return test, fmt.Errorf(`cannot read protobuf file: %w`, err)
}
t.logger.Debug("protobuf file contents", zap.String("contents", string(pbFile.Contents())))

test.Spec.Trigger.Grpc.SetProtobufFile(string(pbFile.Contents()))

return test, nil
}

func (t test) consolidateScriptFile(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
if test.Spec.Trigger.GetType() != "playwrightengine" {
t.logger.Debug("test does not use playwrightengine", zap.String("triggerType", test.Spec.Trigger.GetType()))
return test, nil
}

definedScriptFile := test.Spec.Trigger.PlaywrightEngine.GetScript()
if !t.isValidGrpcFilePath(definedScriptFile, input.AbsDir()) {
t.logger.Debug("script file is not a file path", zap.String("protobufFile", definedScriptFile))
return test, nil
}

scriptFilePath := input.RelativeFile(definedScriptFile)
t.logger.Debug("script file", zap.String("path", scriptFilePath))

scriptFile, err := fileutil.Read(scriptFilePath)
if err != nil {
return test, fmt.Errorf(`cannot read script file: %w`, err)
}
t.logger.Debug("script file contents", zap.String("contents", string(scriptFile.Contents())))

test.Spec.Trigger.PlaywrightEngine.SetScript(string(scriptFile.Contents()))

return test, nil
}

func (t test) isValidGrpcFilePath(grpcFilePath, testFile string) bool {
if fileutil.LooksLikeRelativeFilePath(grpcFilePath) {
// if looks like a relative file path, test if it exists
return fileutil.IsFilePathToRelativeDir(grpcFilePath, testFile)
}

// it could be an absolute file path, test it
return fileutil.IsFilePath(grpcFilePath)
}
51 changes: 51 additions & 0 deletions cli/processor/trigger_preprocessor/graphql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package trigger_preprocessor

import (
"github.com/kubeshop/tracetest/agent/workers/trigger"
"github.com/kubeshop/tracetest/cli/cmdutil"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"go.uber.org/zap"
)

type graphql struct {
logger *zap.Logger
}

func GRAPHQL(logger *zap.Logger) graphql {
return graphql{logger: cmdutil.GetLogger()}
}

func (g graphql) Type() trigger.TriggerType {
return trigger.TriggerTypeGraphql
}

func (g graphql) Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
// query can be defined separately in a file like: query: ./query.graphql
rawQuery := test.Spec.Trigger.Graphql.Body.GetQuery()
if isValidFilePath(rawQuery, input.AbsDir()) {
queryFilePath := input.RelativeFile(rawQuery)
g.logger.Debug("script file", zap.String("path", queryFilePath))

queryFile, err := fileutil.Read(queryFilePath)
if err == nil {
g.logger.Debug("script file contents", zap.String("contents", string(queryFile.Contents())))
test.Spec.Trigger.Graphql.Body.SetQuery(string(queryFile.Contents()))
}
}

// schema can be defined separately in a file like: schema: ./schema.graphql
rawSchema := test.Spec.Trigger.Graphql.GetSchema()
if isValidFilePath(rawSchema, input.AbsDir()) {
schemaFilePath := input.RelativeFile(rawSchema)
g.logger.Debug("script file", zap.String("path", schemaFilePath))

schemaFile, err := fileutil.Read(schemaFilePath)
if err == nil {
g.logger.Debug("script file contents", zap.String("contents", string(schemaFile.Contents())))
test.Spec.Trigger.Graphql.SetSchema(string(schemaFile.Contents()))
}
}

return test, nil
}
55 changes: 55 additions & 0 deletions cli/processor/trigger_preprocessor/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package trigger_preprocessor

import (
"fmt"

"github.com/kubeshop/tracetest/agent/workers/trigger"
"github.com/kubeshop/tracetest/cli/cmdutil"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"go.uber.org/zap"
)

type grpc struct {
logger *zap.Logger
}

func GRPC(logger *zap.Logger) grpc {
return grpc{logger: cmdutil.GetLogger()}
}

func (g grpc) Type() trigger.TriggerType {
return trigger.TriggerTypeGRPC
}

func (g grpc) Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
// protobuf file can be defined separately in a file like: protobufFile: ./file.proto
definedPBFile := test.Spec.Trigger.Grpc.GetProtobufFile()
if !isValidFilePath(definedPBFile, input.AbsDir()) {
g.logger.Debug("protobuf file is not a file path", zap.String("protobufFile", definedPBFile))
return test, nil
}

pbFilePath := input.RelativeFile(definedPBFile)
g.logger.Debug("protobuf file", zap.String("path", pbFilePath))

pbFile, err := fileutil.Read(pbFilePath)
if err != nil {
return test, fmt.Errorf(`cannot read protobuf file: %w`, err)
}
g.logger.Debug("protobuf file contents", zap.String("contents", string(pbFile.Contents())))

test.Spec.Trigger.Grpc.SetProtobufFile(string(pbFile.Contents()))

return test, nil
}

func isValidFilePath(filePath, testFile string) bool {
if fileutil.LooksLikeRelativeFilePath(filePath) {
// if looks like a relative file path, test if it exists
return fileutil.IsFilePathToRelativeDir(filePath, testFile)
}

// it could be an absolute file path, test it
return fileutil.IsFilePath(filePath)
}
45 changes: 45 additions & 0 deletions cli/processor/trigger_preprocessor/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package trigger_preprocessor

import (
"fmt"

"github.com/kubeshop/tracetest/agent/workers/trigger"
"github.com/kubeshop/tracetest/cli/cmdutil"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"go.uber.org/zap"
)

type http struct {
logger *zap.Logger
}

func HTTP(logger *zap.Logger) http {
return http{logger: cmdutil.GetLogger()}
}

func (g http) Type() trigger.TriggerType {
return trigger.TriggerTypeHTTP
}

func (g http) Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
// body can be defined separately in a file like: body: ./body.json
definedBodyFile := test.Spec.Trigger.HttpRequest.GetBody()
if !isValidFilePath(definedBodyFile, input.AbsDir()) {
g.logger.Debug("body file is not a file path", zap.String("protobufFile", definedBodyFile))
return test, nil
}

bodyFilePath := input.RelativeFile(definedBodyFile)
g.logger.Debug("http body file", zap.String("path", bodyFilePath))

bodyFile, err := fileutil.Read(definedBodyFile)
if err != nil {
return test, fmt.Errorf(`cannot read protobuf file: %w`, err)
}
g.logger.Debug("http body file contents", zap.String("contents", string(bodyFile.Contents())))

test.Spec.Trigger.HttpRequest.SetBody(string(bodyFile.Contents()))

return test, nil
}
45 changes: 45 additions & 0 deletions cli/processor/trigger_preprocessor/playwrightengine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package trigger_preprocessor

import (
"fmt"

"github.com/kubeshop/tracetest/agent/workers/trigger"
"github.com/kubeshop/tracetest/cli/cmdutil"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"go.uber.org/zap"
)

type playwrightengine struct {
logger *zap.Logger
}

func PLAYWRIGHTENGINE(logger *zap.Logger) playwrightengine {
return playwrightengine{logger: cmdutil.GetLogger()}
}

func (g playwrightengine) Type() trigger.TriggerType {
return trigger.TriggerTypePlaywrightEngine
}

func (g playwrightengine) Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
// script can be defined separately in a file like: script: ./script.js
definedScriptFile := test.Spec.Trigger.PlaywrightEngine.GetScript()
if !isValidFilePath(definedScriptFile, input.AbsDir()) {
g.logger.Debug("script file is not a file path", zap.String("protobufFile", definedScriptFile))
return test, nil
}

scriptFilePath := input.RelativeFile(definedScriptFile)
g.logger.Debug("script file", zap.String("path", scriptFilePath))

scriptFile, err := fileutil.Read(scriptFilePath)
if err != nil {
return test, fmt.Errorf(`cannot read script file: %w`, err)
}
g.logger.Debug("script file contents", zap.String("contents", string(scriptFile.Contents())))

test.Spec.Trigger.PlaywrightEngine.SetScript(string(scriptFile.Contents()))

return test, nil
}
43 changes: 43 additions & 0 deletions cli/processor/trigger_preprocessor/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package trigger_preprocessor

import (
"fmt"

"github.com/kubeshop/tracetest/agent/workers/trigger"
"github.com/kubeshop/tracetest/cli/openapi"
"github.com/kubeshop/tracetest/cli/pkg/fileutil"
"go.uber.org/zap"
)

type TriggerPreprocessor interface {
Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error)
Type() trigger.TriggerType
}

type Registry struct {
processors map[trigger.TriggerType]TriggerPreprocessor
}

func NewRegistry(logger *zap.Logger) Registry {
return Registry{
processors: map[trigger.TriggerType]TriggerPreprocessor{},
}
}

func (r Registry) Register(processor TriggerPreprocessor) Registry {
r.processors[processor.Type()] = processor
return r
}

var ErrNotFound = fmt.Errorf("preprocessor not found")

func (r Registry) Preprocess(input fileutil.File, test openapi.TestResource) (openapi.TestResource, error) {
triggerType := test.Spec.Trigger.GetType()

processor, ok := r.processors[trigger.TriggerType(triggerType)]
if ok {
return processor.Preprocess(input, test)
}

return test, nil
}

0 comments on commit 6946b7d

Please sign in to comment.