Skip to content

Commit

Permalink
fix(cli): adds config as a field in cmdConfigurator and serviceProvid…
Browse files Browse the repository at this point in the history
…er (keploy#1718)

* fix(cli): adds config as a field in cmdConfigurator and serviceProvider

the config is present in the function signature due to which different implementations of the
interface is restricted to use the oss config type. This makes a challenge in the enterprise to add
its own config type for enterprise flags. Thats why the config is now a member field of the struct
that implements cmdConfigurator and serviceProvider interfaces.

Signed-off-by: re-Tick <[email protected]>

* style: removes linting errors

Signed-off-by: re-Tick <[email protected]>

---------

Signed-off-by: re-Tick <[email protected]>
  • Loading branch information
re-Tick authored Mar 21, 2024
1 parent fd210aa commit e359091
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 74 deletions.
6 changes: 3 additions & 3 deletions cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func Config(ctx context.Context, logger *zap.Logger, cfg *config.Config, service
Short: "manage keploy configuration file",
Example: "keploy config --generate --path /path/to/localdir",
PreRunE: func(cmd *cobra.Command, _ []string) error {
return cmdConfigurator.ValidateFlags(ctx, cmd, cfg)
return cmdConfigurator.ValidateFlags(ctx, cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {

Expand All @@ -46,7 +46,7 @@ func Config(ctx context.Context, logger *zap.Logger, cfg *config.Config, service
return nil
}
}
svc, err := servicefactory.GetService(ctx, cmd.Name(), *cfg)
svc, err := servicefactory.GetService(ctx, cmd.Name())
if err != nil {
utils.LogError(logger, err, "failed to get service")
return err
Expand All @@ -66,7 +66,7 @@ func Config(ctx context.Context, logger *zap.Logger, cfg *config.Config, service
return errors.New("only generate flag is supported in the config command")
},
}
if err := cmdConfigurator.AddFlags(cmd, cfg); err != nil {
if err := cmdConfigurator.AddFlags(cmd); err != nil {
utils.LogError(logger, err, "failed to add flags")
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions cli/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func Mock(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa
return errors.New("both --record and --replay flags are set")
}
if record {
svc, err := serviceFactory.GetService(ctx, "record", *cfg)
svc, err := serviceFactory.GetService(ctx, "record")
if err != nil {
utils.LogError(logger, err, "failed to get service")
return err
Expand All @@ -54,7 +54,7 @@ func Mock(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa

}
if replay {
svc, err := serviceFactory.GetService(ctx, "replay", *cfg)
svc, err := serviceFactory.GetService(ctx, "replay")
if err != nil {
utils.LogError(logger, err, "failed to get service")
return err
Expand All @@ -71,7 +71,7 @@ func Mock(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa

},
}
if err := cmdConfigurator.AddFlags(cmd, cfg); err != nil {
if err := cmdConfigurator.AddFlags(cmd); err != nil {
utils.LogError(logger, err, "failed to add flags")
return nil
}
Expand Down
90 changes: 46 additions & 44 deletions cli/provider/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,17 @@ var VersionTemplate = `{{with .Version}}{{printf "Keploy %s" .}}{{end}}{{"\n"}}`

type CmdConfigurator struct {
logger *zap.Logger
cfg *config.Config
}

func NewCmdConfigurator(logger *zap.Logger) *CmdConfigurator {
func NewCmdConfigurator(logger *zap.Logger, config *config.Config) *CmdConfigurator {
return &CmdConfigurator{
logger: logger,
cfg: config,
}
}

func (c *CmdConfigurator) AddFlags(cmd *cobra.Command, cfg *config.Config) error {
func (c *CmdConfigurator) AddFlags(cmd *cobra.Command) error {
var err error
switch cmd.Name() {
case "update":
Expand All @@ -159,7 +161,7 @@ func (c *CmdConfigurator) AddFlags(cmd *cobra.Command, cfg *config.Config) error
cmd.Flags().StringP("path", "p", ".", "Path to local directory where generated config is stored")
cmd.Flags().Bool("generate", false, "Generate a new keploy configuration file")
case "mock":
cmd.Flags().StringP("path", "p", cfg.Path, "Path to local directory where generated testcases/mocks are stored")
cmd.Flags().StringP("path", "p", c.cfg.Path, "Path to local directory where generated testcases/mocks are stored")
cmd.Flags().Bool("record", false, "Record all outgoing network traffic")
cmd.Flags().Bool("replay", false, "Intercept all outgoing network traffic and replay the recorded traffic")
cmd.Flags().StringP("name", "n", "mocks", "Name of the mock")
Expand All @@ -173,36 +175,36 @@ func (c *CmdConfigurator) AddFlags(cmd *cobra.Command, cfg *config.Config) error
case "record", "test":
cmd.Flags().String("configPath", ".", "Path to the local directory where keploy configuration file is stored")
cmd.Flags().StringP("path", "p", ".", "Path to local directory where generated testcases/mocks are stored")
cmd.Flags().Uint32("port", cfg.Port, "GraphQL server port used for executing testcases in unit test library integration")
cmd.Flags().Uint32("proxyPort", cfg.ProxyPort, "Port used by the Keploy proxy server to intercept the outgoing dependency calls")
cmd.Flags().Uint32("dnsPort", cfg.DNSPort, "Port used by the Keploy DNS server to intercept the DNS queries")
cmd.Flags().StringP("command", "c", cfg.Command, "Command to start the user application")
cmd.Flags().DurationP("buildDelay", "b", cfg.BuildDelay, "User provided time to wait docker container build")
cmd.Flags().String("containerName", cfg.ContainerName, "Name of the application's docker container")
cmd.Flags().StringP("networkName", "n", cfg.NetworkName, "Name of the application's docker network")
cmd.Flags().UintSlice("passThroughPorts", config.GetByPassPorts(cfg), "Ports to bypass the proxy server and ignore the traffic")
cmd.Flags().Uint32("port", c.cfg.Port, "GraphQL server port used for executing testcases in unit test library integration")
cmd.Flags().Uint32("proxyPort", c.cfg.ProxyPort, "Port used by the Keploy proxy server to intercept the outgoing dependency calls")
cmd.Flags().Uint32("dnsPort", c.cfg.DNSPort, "Port used by the Keploy DNS server to intercept the DNS queries")
cmd.Flags().StringP("command", "c", c.cfg.Command, "Command to start the user application")
cmd.Flags().DurationP("buildDelay", "b", c.cfg.BuildDelay, "User provided time to wait docker container build")
cmd.Flags().String("containerName", c.cfg.ContainerName, "Name of the application's docker container")
cmd.Flags().StringP("networkName", "n", c.cfg.NetworkName, "Name of the application's docker network")
cmd.Flags().UintSlice("passThroughPorts", config.GetByPassPorts(c.cfg), "Ports to bypass the proxy server and ignore the traffic")
err = cmd.Flags().MarkHidden("port")
if err != nil {
errMsg := "failed to mark port as hidden flag"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
if cmd.Name() == "test" {
cmd.Flags().StringSliceP("testsets", "t", utils.Keys(cfg.Test.SelectedTests), "Testsets to run e.g. --testsets \"test-set-1, test-set-2\"")
cmd.Flags().StringSliceP("testsets", "t", utils.Keys(c.cfg.Test.SelectedTests), "Testsets to run e.g. --testsets \"test-set-1, test-set-2\"")
cmd.Flags().Uint64P("delay", "d", 5, "User provided time to run its application")
cmd.Flags().Uint64("apiTimeout", cfg.Test.APITimeout, "User provided timeout for calling its application")
cmd.Flags().String("mongoPassword", cfg.Test.MongoPassword, "Authentication password for mocking MongoDB conn")
cmd.Flags().String("coverageReportPath", cfg.Test.CoverageReportPath, "Write a go coverage profile to the file in the given directory.")
cmd.Flags().StringP("language", "l", cfg.Test.Language, "application programming language")
cmd.Flags().Bool("ignoreOrdering", cfg.Test.IgnoreOrdering, "Ignore ordering of array in response")
cmd.Flags().Bool("coverage", cfg.Test.Coverage, "Enable coverage reporting for the testcases. for golang please set language flag to golang, ref https://keploy.io/docs/server/sdk-installation/go/")
cmd.Flags().Uint64("apiTimeout", c.cfg.Test.APITimeout, "User provided timeout for calling its application")
cmd.Flags().String("mongoPassword", c.cfg.Test.MongoPassword, "Authentication password for mocking MongoDB conn")
cmd.Flags().String("coverageReportPath", c.cfg.Test.CoverageReportPath, "Write a go coverage profile to the file in the given directory.")
cmd.Flags().StringP("language", "l", c.cfg.Test.Language, "application programming language")
cmd.Flags().Bool("ignoreOrdering", c.cfg.Test.IgnoreOrdering, "Ignore ordering of array in response")
cmd.Flags().Bool("coverage", c.cfg.Test.Coverage, "Enable coverage reporting for the testcases. for golang please set language flag to golang, ref https://keploy.io/docs/server/sdk-installation/go/")
cmd.Flags().Bool("removeUnusedMocks", false, "Clear the unused mocks for the passed test-sets")
} else {
cmd.Flags().Uint64("recordTimer", 0, "User provided time to record its application")
}
case "keploy":
cmd.PersistentFlags().Bool("debug", cfg.Debug, "Run in debug mode")
cmd.PersistentFlags().Bool("disableTele", cfg.DisableTele, "Run in telemetry mode")
cmd.PersistentFlags().Bool("debug", c.cfg.Debug, "Run in debug mode")
cmd.PersistentFlags().Bool("disableTele", c.cfg.DisableTele, "Run in telemetry mode")
err = cmd.PersistentFlags().MarkHidden("disableTele")
if err != nil {
errMsg := "failed to mark telemetry as hidden flag"
Expand All @@ -215,7 +217,7 @@ func (c *CmdConfigurator) AddFlags(cmd *cobra.Command, cfg *config.Config) error
return nil
}

func (c *CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command, cfg *config.Config) error {
func (c CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command) error {
// used to bind common flags for commands like record, test. For eg: PATH, PORT, COMMAND etc.
err := viper.BindPFlags(cmd.Flags())
if err != nil {
Expand Down Expand Up @@ -250,12 +252,12 @@ func (c *CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command,
c.logger.Info("config file not found; proceeding with flags only")
}
}
if err := viper.Unmarshal(cfg); err != nil {
if err := viper.Unmarshal(c.cfg); err != nil {
errMsg := "failed to unmarshal the config"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
if cfg.Debug {
if c.cfg.Debug {
logger, err := log.ChangeLogLevel(zap.DebugLevel)
*c.logger = *logger
if err != nil {
Expand All @@ -264,7 +266,7 @@ func (c *CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command,
return errors.New(errMsg)
}
}
c.logger.Debug("config has been initialised", zap.Any("for cmd", cmd.Name()), zap.Any("config", cfg))
c.logger.Debug("config has been initialised", zap.Any("for cmd", cmd.Name()), zap.Any("config", c.cfg))

switch cmd.Name() {
case "record", "test":
Expand All @@ -274,52 +276,52 @@ func (c *CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command,
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
config.SetByPassPorts(cfg, bypassPorts)
config.SetByPassPorts(c.cfg, bypassPorts)

if cfg.Command == "" {
if c.cfg.Command == "" {
utils.LogError(c.logger, nil, "missing required -c flag or appCmd in config file")
if cfg.InDocker {
if c.cfg.InDocker {
c.logger.Info(`Example usage: keploy test -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6`)
} else {
c.logger.Info(LogExample(RootExamples))
}
return errors.New("missing required -c flag or appCmd in config file")
}

if cfg.InDocker {
if len(cfg.Path) > 0 {
if c.cfg.InDocker {
if len(c.cfg.Path) > 0 {
curDir, err := os.Getwd()
if err != nil {
errMsg := "failed to get current working directory"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
if strings.Contains(cfg.Path, "..") {
cfg.Path, err = filepath.Abs(filepath.Clean(cfg.Path))
if strings.Contains(c.cfg.Path, "..") {
c.cfg.Path, err = filepath.Abs(filepath.Clean(c.cfg.Path))
if err != nil {
errMsg := "failed to get the absolute path from relative path"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
relativePath, err := filepath.Rel(curDir, cfg.Path)
relativePath, err := filepath.Rel(curDir, c.cfg.Path)
if err != nil {
errMsg := "failed to get the relative path from absolute path"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
if relativePath == ".." || strings.HasPrefix(relativePath, "../") {
errMsg := "path provided is not a subdirectory of current directory. Keploy only supports recording testcases in the current directory or its subdirectories"
utils.LogError(c.logger, err, errMsg, zap.String("path:", cfg.Path))
utils.LogError(c.logger, err, errMsg, zap.String("path:", c.cfg.Path))
return errors.New(errMsg)
}
}
}
if cfg.BuildDelay <= 30*time.Second {
c.logger.Warn(fmt.Sprintf("buildDelay is set to %v, incase your docker container takes more time to build use --buildDelay to set custom delay", cfg.BuildDelay))
if c.cfg.BuildDelay <= 30*time.Second {
c.logger.Warn(fmt.Sprintf("buildDelay is set to %v, incase your docker container takes more time to build use --buildDelay to set custom delay", c.cfg.BuildDelay))
c.logger.Info(`Example usage: keploy record -c "docker-compose up --build" --buildDelay 35s`)
}
if strings.Contains(cfg.Command, "--name") {
if cfg.ContainerName == "" {
if strings.Contains(c.cfg.Command, "--name") {
if c.cfg.ContainerName == "" {
utils.LogError(c.logger, nil, "Couldn't find containerName")
c.logger.Info(`Example usage: keploy record -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6`)
return errors.New("missing required --containerName flag or containerName in config file")
Expand All @@ -328,29 +330,29 @@ func (c *CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command,

}

err = utils.StartInDocker(ctx, c.logger, cfg)
err = utils.StartInDocker(ctx, c.logger, c.cfg)
if err != nil {
return err
}

absPath, err := filepath.Abs(cfg.Path)
absPath, err := filepath.Abs(c.cfg.Path)
if err != nil {
errMsg := "failed to get the absolute path from relative path"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
cfg.Path = absPath + "/keploy"
c.cfg.Path = absPath + "/keploy"
if cmd.Name() == "test" {
testSets, err := cmd.Flags().GetStringSlice("testsets")
if err != nil {
errMsg := "failed to get the testsets"
utils.LogError(c.logger, err, errMsg)
return errors.New(errMsg)
}
config.SetSelectedTests(cfg, testSets)
if cfg.Test.Delay <= 5 {
c.logger.Warn(fmt.Sprintf("Delay is set to %d seconds, incase your app takes more time to start use --delay to set custom delay", cfg.Test.Delay))
if cfg.InDocker {
config.SetSelectedTests(c.cfg, testSets)
if c.cfg.Test.Delay <= 5 {
c.logger.Warn(fmt.Sprintf("Delay is set to %d seconds, incase your app takes more time to start use --delay to set custom delay", c.cfg.Test.Delay))
if c.cfg.InDocker {
c.logger.Info(`Example usage: keploy test -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6`)
} else {
c.logger.Info("Example usage: " + cmd.Example)
Expand Down
14 changes: 8 additions & 6 deletions cli/provider/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type ServiceProvider struct {
logger *zap.Logger
configDb *configdb.ConfigDb
cfg *config.Config
}

type CommonInternalService struct {
Expand All @@ -33,10 +34,11 @@ type CommonInternalService struct {
Instrumentation *core.Core
}

func NewServiceProvider(logger *zap.Logger, configDb *configdb.ConfigDb) *ServiceProvider {
func NewServiceProvider(logger *zap.Logger, configDb *configdb.ConfigDb, cfg *config.Config) *ServiceProvider {
return &ServiceProvider{
logger: logger,
configDb: configDb,
cfg: cfg,
}
}

Expand Down Expand Up @@ -69,8 +71,8 @@ func (n *ServiceProvider) GetCommonServices(config config.Config) *CommonInterna
}
}

func (n *ServiceProvider) GetService(ctx context.Context, cmd string, config config.Config) (interface{}, error) {
tel, err := n.GetTelemetryService(ctx, config)
func (n *ServiceProvider) GetService(ctx context.Context, cmd string) (interface{}, error) {
tel, err := n.GetTelemetryService(ctx, *n.cfg)
if err != nil {
return nil, err
}
Expand All @@ -80,12 +82,12 @@ func (n *ServiceProvider) GetService(ctx context.Context, cmd string, config con
return tools.NewTools(n.logger, tel), nil
// TODO: add case for mock
case "record", "test", "mock":
commonServices := n.GetCommonServices(config)
commonServices := n.GetCommonServices(*n.cfg)
if cmd == "record" {
return record.New(n.logger, commonServices.YamlTestDB, commonServices.YamlMockDb, tel, commonServices.Instrumentation, config), nil
return record.New(n.logger, commonServices.YamlTestDB, commonServices.YamlMockDb, tel, commonServices.Instrumentation, *n.cfg), nil
}
if cmd == "test" {
return replay.NewReplayer(n.logger, commonServices.YamlTestDB, commonServices.YamlMockDb, commonServices.YamlReportDb, tel, commonServices.Instrumentation, config), nil
return replay.NewReplayer(n.logger, commonServices.YamlTestDB, commonServices.YamlMockDb, commonServices.YamlReportDb, tel, commonServices.Instrumentation, *n.cfg), nil
}
return nil, errors.New("invalid command")
default:
Expand Down
6 changes: 3 additions & 3 deletions cli/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ func Record(ctx context.Context, logger *zap.Logger, cfg *config.Config, service
Short: "record the keploy testcases from the API calls",
Example: `keploy record -c "/path/to/user/app"`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
return cmdConfigurator.ValidateFlags(ctx, cmd, cfg)
return cmdConfigurator.ValidateFlags(ctx, cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {
svc, err := serviceFactory.GetService(ctx, cmd.Name(), *cfg)
svc, err := serviceFactory.GetService(ctx, cmd.Name())
if err != nil {
utils.LogError(logger, err, "failed to get service")
return nil
Expand All @@ -44,7 +44,7 @@ func Record(ctx context.Context, logger *zap.Logger, cfg *config.Config, service
},
}

err := cmdConfigurator.AddFlags(cmd, cfg)
err := cmdConfigurator.AddFlags(cmd)
if err != nil {
utils.LogError(logger, err, "failed to add record flags")
return nil
Expand Down
2 changes: 1 addition & 1 deletion cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Root(ctx context.Context, logger *zap.Logger, svcFactory ServiceFactory, cm

rootCmd.SetVersionTemplate(provider.VersionTemplate)

err := cmdConfigurator.AddFlags(rootCmd, conf)
err := cmdConfigurator.AddFlags(rootCmd)
if err != nil {
utils.LogError(logger, err, "failed to set flags")
return nil
Expand Down
7 changes: 3 additions & 4 deletions cli/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import (
"context"

"github.com/spf13/cobra"
"go.keploy.io/server/v2/config"
)

type ServiceFactory interface {
GetService(ctx context.Context, cmd string, config config.Config) (interface{}, error)
GetService(ctx context.Context, cmd string) (interface{}, error)
}

type CmdConfigurator interface {
AddFlags(cmd *cobra.Command, config *config.Config) error
ValidateFlags(ctx context.Context, cmd *cobra.Command, config *config.Config) error
AddFlags(cmd *cobra.Command) error
ValidateFlags(ctx context.Context, cmd *cobra.Command) error
}
6 changes: 3 additions & 3 deletions cli/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ func Test(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa
Short: "run the recorded testcases and execute assertions",
Example: `keploy test -c "/path/to/user/app" --delay 6`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
return cmdConfigurator.ValidateFlags(ctx, cmd, cfg)
return cmdConfigurator.ValidateFlags(ctx, cmd)
},
RunE: func(cmd *cobra.Command, _ []string) error {

svc, err := serviceFactory.GetService(ctx, cmd.Name(), *cfg)
svc, err := serviceFactory.GetService(ctx, cmd.Name())
if err != nil {
utils.LogError(logger, err, "failed to get service")
return nil
Expand Down Expand Up @@ -55,7 +55,7 @@ func Test(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa
},
}

err := cmdConfigurator.AddFlags(testCmd, cfg)
err := cmdConfigurator.AddFlags(testCmd)
if err != nil {
utils.LogError(logger, err, "failed to add test flags")
return nil
Expand Down
Loading

0 comments on commit e359091

Please sign in to comment.