Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): Implementing trigger preprocessor #3990

Merged
merged 4 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading