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: make docker compose startup time configurable #1166

Merged
merged 17 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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
13 changes: 10 additions & 3 deletions cmd/examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,15 @@ Docker
-v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/keploy/keploy'

Record:
keploy record -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage"
keploy record -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --buildDelay 35s
or
keploy record -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --buildDelay 1m

Test:
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1 --buildDelay 35s
or
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1 --buildDelay 1m

`

var exampleOneClickInstall = `
Expand Down Expand Up @@ -90,7 +95,9 @@ Docker
keploy record -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage"

Test:
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1 --buildDelay 35s
or
keploy test -c "docker run -p 8080:8080 --name myContainerName --network myNetworkName myApplicationImage" --delay 1 --buildDelay 1m
`

type Example struct {
Expand Down
31 changes: 26 additions & 5 deletions cmd/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/spf13/cobra"
"go.keploy.io/server/pkg/models"
Expand Down Expand Up @@ -40,7 +41,7 @@ func readRecordConfig(configPath string) (*models.Record, error) {

var filters = *&models.Filters{}

func (t *Record) GetRecordConfig(path *string, proxyPort *uint32, appCmd *string, appContainer, networkName *string, Delay *uint64, passThroughPorts *[]uint, configPath string) error {
func (t *Record) GetRecordConfig(path *string, proxyPort *uint32, appCmd *string, appContainer, networkName *string, Delay *uint64, buildDelay *time.Duration, passThroughPorts *[]uint, configPath string) error {
configFilePath := filepath.Join(configPath, "keploy-config.yaml")
if isExist := utils.CheckFileExists(configFilePath); !isExist {
return errFileNotFound
Expand Down Expand Up @@ -68,6 +69,9 @@ func (t *Record) GetRecordConfig(path *string, proxyPort *uint32, appCmd *string
if *Delay == 5 {
*Delay = confRecord.Delay
}
if *buildDelay == 30*time.Second && confRecord.BuildDelay != 0 {
*buildDelay = confRecord.BuildDelay
}
if len(*passThroughPorts) == 0 {
*passThroughPorts = confRecord.PassThroughPorts
}
Expand Down Expand Up @@ -118,6 +122,12 @@ func (r *Record) GetCmd() *cobra.Command {
return err
}

buildDelay, err := cmd.Flags().GetDuration("buildDelay")
if err != nil {
r.logger.Error("Failed to get the build-delay flag", zap.Error((err)))
return err
}

ports, err := cmd.Flags().GetUintSlice("passThroughPorts")
if err != nil {
r.logger.Error("failed to read the ports of outgoing calls to be ignored")
Expand All @@ -136,7 +146,7 @@ func (r *Record) GetCmd() *cobra.Command {
return err
}

err = r.GetRecordConfig(&path, &proxyPort, &appCmd, &appContainer, &networkName, &delay, &ports, configPath)
err = r.GetRecordConfig(&path, &proxyPort, &appCmd, &appContainer, &networkName, &delay, &buildDelay, &ports, configPath)
if err != nil {
if err == errFileNotFound {
r.logger.Info("continuing without configuration file because file not found")
Expand All @@ -148,7 +158,7 @@ func (r *Record) GetCmd() *cobra.Command {
if appCmd == "" {
fmt.Println("Error: missing required -c flag or appCmd in config file")
if isDockerCmd {
fmt.Println("Example usage:\n", `keploy record -c "docker run -p 8080:808 --network myNetworkName myApplicationImageName" --delay 6\n`)
fmt.Println("Example usage:\n", `keploy record -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6\n`)
} else {
fmt.Println("Example usage:\n", cmd.Example)
}
Expand All @@ -172,6 +182,15 @@ func (r *Record) GetCmd() *cobra.Command {
// user provided the absolute path
}

if buildDelay <= 30*time.Second {
Copy link
Member

@gouravkrosx gouravkrosx Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the other example here also. And have you tested your changes with the config file as well?

fmt.Printf("Warning: buildDelay is set to %d, incase your docker container takes more time to build use --buildDelay to set custom delay\n", buildDelay)
if isDockerCmd {
fmt.Println("Example usage:\n", `keploy record -c "docker-compose up --build" --buildDelay 35s\n`, "\nor\n", `keploy record -c "docker-compose up --build" --buildDelay 1m\n`)
} else {
fmt.Println("Example usage:\n", cmd.Example)
}
}

path += "/keploy"

r.logger.Info("", zap.Any("keploy test and mock path", path))
Expand All @@ -183,13 +202,13 @@ func (r *Record) GetCmd() *cobra.Command {
}
if !hasContainerName && appContainer == "" {
fmt.Println("Error: missing required --containerName flag or containerName in config file")
fmt.Println("\nExample usage:\n", `keploy record -c "docker run -p 8080:808 --network myNetworkName myApplicationImageName" --delay 6`)
fmt.Println("\nExample usage:\n", `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")
}
}

r.logger.Debug("the ports are", zap.Any("ports", ports))
r.recorder.CaptureTraffic(path, proxyPort, appCmd, appContainer, networkName, delay, ports, &filters)
r.recorder.CaptureTraffic(path, proxyPort, appCmd, appContainer, networkName, delay, buildDelay, ports, &filters)
return nil
},
}
Expand All @@ -206,6 +225,8 @@ func (r *Record) GetCmd() *cobra.Command {

recordCmd.Flags().Uint64P("delay", "d", 5, "User provided time to run its application")

recordCmd.Flags().DurationP("buildDelay", "", 30*time.Second, "User provided time to wait docker container build")

recordCmd.Flags().UintSlice("passThroughPorts", []uint{}, "Ports of Outgoing dependency calls to be ignored as mocks")

recordCmd.Flags().String("config-path", ".", "Path to the local directory where keploy configuration file is stored")
Expand Down
32 changes: 18 additions & 14 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package cmd

import (
"bytes"
"errors"
"log"
"net/http"
_ "net/http/pprof"
"os"
"time"
"errors"
"bytes"

"github.com/TheZeroSlave/zapsentry"
sentry "github.com/getsentry/sentry-go"
"github.com/spf13/cobra"
"go.keploy.io/server/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
)

var Emoji = "\U0001F430" + " Keploy:"
Expand All @@ -34,20 +34,20 @@ type colorConsoleEncoder struct {
*zapcore.EncoderConfig
zapcore.Encoder
}

func NewColorConsole(cfg zapcore.EncoderConfig) (enc zapcore.Encoder) {
return colorConsoleEncoder{
EncoderConfig: &cfg,
// Using the default ConsoleEncoder can avoid rewriting interfaces such as ObjectEncoder
Encoder: zapcore.NewConsoleEncoder(cfg),
}
}

// EncodeEntry overrides ConsoleEncoder's EncodeEntry
func (c colorConsoleEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (buf *buffer.Buffer, err error) {
buff, err := c.Encoder.EncodeEntry(ent, fields) // Utilize the existing implementation of zap
if err != nil {
return nil, err
return nil, err
}

bytesArr := bytes.Replace(buff.Bytes(), []byte("\\u001b"), []byte("\u001b"), -1)
Expand All @@ -61,30 +61,30 @@ func (c colorConsoleEncoder) Clone() zapcore.Encoder {
clone := c.Encoder.Clone()
return colorConsoleEncoder{
EncoderConfig: c.EncoderConfig,
Encoder: clone,
Encoder: clone,
}
}

func init() {
_ = zap.RegisterEncoder("colorConsole", func(config zapcore.EncoderConfig) (zapcore.Encoder, error) {
return NewColorConsole(config), nil
})
return NewColorConsole(config), nil
})
}

func setupLogger() *zap.Logger {
logCfg := zap.NewDevelopmentConfig()

logCfg.Encoding = "colorConsole"

// Customize the encoder config to put the emoji at the beginning.
logCfg.EncoderConfig.EncodeTime = customTimeEncoder
logCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
logCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder

logCfg.OutputPaths = []string{
"stdout",
"./keploy-logs.txt",
}

if debugMode {
go func() {
defer utils.HandlePanic()
Expand Down Expand Up @@ -171,10 +171,14 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e

var rootExamples = `
Record:
keploy record -c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --containerName "<containerName>" --delay 1
keploy record -c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --containerName "<containerName>" --delay 1 --buildDelay 35s
or
keploy record -c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --containerName "<containerName>" --delay 1 --buildDelay 1m

Test:
keploy test --c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --delay 1
keploy test --c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --delay 1 --buildDelay 35s
or
keploy test --c "docker run -p 8080:8080 --name <containerName> --network keploy-network <applicationImage>" --delay 1 --buildDelay 1m

Generate-Config:
keploy generate-config -p "/path/to/localdir"
Expand Down
10 changes: 7 additions & 3 deletions cmd/serve.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package cmd

import (
"os"
"path/filepath"

"github.com/spf13/cobra"
"go.keploy.io/server/pkg/service/serve"
"go.uber.org/zap"
"os"
"path/filepath"
)

func NewCmdServe(logger *zap.Logger) *Serve {
Expand Down Expand Up @@ -66,6 +65,11 @@ func (s *Serve) GetCmd() *cobra.Command {
return
}

if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this code since there is no build-delay in the serve command. So no need to check for this error.

s.logger.Error("Failed to get the build-delay flag", zap.Error((err)))
return
}

pid, err := cmd.Flags().GetUint32("pid")

if err != nil {
Expand Down
32 changes: 27 additions & 5 deletions cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/spf13/cobra"
"go.keploy.io/server/pkg/models"
Expand Down Expand Up @@ -38,7 +39,7 @@ func readTestConfig(configPath string) (*models.Test, error) {
return &doc.Test, nil
}

func (t *Test) getTestConfig(path *string, proxyPort *uint32, appCmd *string, testsets *[]string, appContainer, networkName *string, Delay *uint64, passThorughPorts *[]uint, apiTimeout *uint64, globalNoise *models.GlobalNoise, testSetNoise *models.TestsetNoise, coverageReportPath *string, withCoverage *bool, configPath string) error {
func (t *Test) getTestConfig(path *string, proxyPort *uint32, appCmd *string, testsets *[]string, appContainer, networkName *string, Delay *uint64, buildDelay *time.Duration, passThorughPorts *[]uint, apiTimeout *uint64, globalNoise *models.GlobalNoise, testSetNoise *models.TestsetNoise, coverageReportPath *string, withCoverage *bool, configPath string) error {
configFilePath := filepath.Join(configPath, "keploy-config.yaml")
if isExist := utils.CheckFileExists(configFilePath); !isExist {
return errFileNotFound
Expand Down Expand Up @@ -68,6 +69,9 @@ func (t *Test) getTestConfig(path *string, proxyPort *uint32, appCmd *string, te
if *Delay == 5 {
*Delay = confTest.Delay
}
if *buildDelay == 30*time.Second && confTest.BuildDelay != 0 {
*buildDelay = confTest.BuildDelay
}
if len(*passThorughPorts) == 0 {
*passThorughPorts = confTest.PassThroughPorts
}
Expand Down Expand Up @@ -188,6 +192,12 @@ func (t *Test) GetCmd() *cobra.Command {
return err
}

buildDelay, err := cmd.Flags().GetDuration("buildDelay")
if err != nil {
t.logger.Error("Failed to get the build-delay flag", zap.Error((err)))
return err
}

apiTimeout, err := cmd.Flags().GetUint64("apiTimeout")
if err != nil {
t.logger.Error("Failed to get the apiTimeout flag", zap.Error((err)))
Expand Down Expand Up @@ -215,7 +225,7 @@ func (t *Test) GetCmd() *cobra.Command {
globalNoise := make(models.GlobalNoise)
testsetNoise := make(models.TestsetNoise)

err = t.getTestConfig(&path, &proxyPort, &appCmd, &testSets, &appContainer, &networkName, &delay, &ports, &apiTimeout, &globalNoise, &testsetNoise, &coverageReportPath, &withCoverage, configPath)
err = t.getTestConfig(&path, &proxyPort, &appCmd, &testSets, &appContainer, &networkName, &delay, &buildDelay, &ports, &apiTimeout, &globalNoise, &testsetNoise, &coverageReportPath, &withCoverage, configPath)
if err != nil {
if err == errFileNotFound {
t.logger.Info("continuing without configuration file because file not found")
Expand All @@ -227,7 +237,7 @@ func (t *Test) GetCmd() *cobra.Command {
if appCmd == "" {
fmt.Println("Error: missing required -c flag or appCmd in config file")
if isDockerCmd {
fmt.Println("Example usage:\n", `keploy test -c "docker run -p 8080:808 --network myNetworkName myApplicationImageName" --delay 6\n`)
fmt.Println("Example usage:\n", `keploy test -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6\n`)
}
fmt.Println("Example usage:\n", cmd.Example)

Expand All @@ -237,7 +247,16 @@ func (t *Test) GetCmd() *cobra.Command {
if delay <= 5 {
fmt.Printf("Warning: delay is set to %d seconds, incase your app takes more time to start use --delay to set custom delay\n", delay)
if isDockerCmd {
fmt.Println("Example usage:\n", `keploy test -c "docker run -p 8080:808 --network myNetworkName myApplicationImageName" --delay 6\n`)
fmt.Println("Example usage:\n", `keploy test -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6\n`)
} else {
fmt.Println("Example usage:\n", cmd.Example)
}
}

if buildDelay <= 30*time.Second {
fmt.Printf("Warning: buildDelay is set to %d, incase your docker container takes more time to build use --buildDelay to set custom delay\n", buildDelay)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warning should be printed only when there is docker command because we don't need the build-delay flag in case of native integration.

if isDockerCmd {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check for isDockerCmd again.

fmt.Println("Example usage:\n", `keploy test -c "docker-compose up --build" --buildDelay 35s\n`, "\nor\n", `keploy test -c "docker-compose up --build" --buildDelay 1m\n`)
} else {
Copy link
Member

@gouravkrosx gouravkrosx Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only mention test command usage here. And the port forwarding in the docker command should have port -p 8080:8080, please fix this if any other place also has this incorrect port.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion, what does 'Only mention test command usage here. ' mean , Shall I remove the warning message 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't notice. You don't need to remove the command or any warning message. Just fix the port forwarding.

fmt.Println("Example usage:\n", cmd.Example)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this buildDelay flag is only in the case of the docker command, there is no need to add this example here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this buildDelay flag is only in the case of the docker command, there is no need to add this example here.

By default, do we assume that the docker environment is built when the user uses the record command? Do we consider the situation where the user needs to rebuild when running the test command? Then the buildDelay parameter still needs to be checked

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IllTamer Whenever there is a docker env the isDockerCmd is true since the keploy Dockerfile contains this as an environment variable. So if you've checked that it is dockerCmd & the buildDelay is <=30 then just show the warning as the usage rather than showing another example.

}
Expand Down Expand Up @@ -273,7 +292,7 @@ func (t *Test) GetCmd() *cobra.Command {
}
if !hasContainerName && appContainer == "" {
fmt.Println("Error: missing required --containerName flag or containerName in config file")
fmt.Println("\nExample usage:\n", `keploy test -c "docker run -p 8080:808 --network myNetworkName myApplicationImageName" --delay 6`)
fmt.Println("\nExample usage:\n", `keploy test -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 @@ -293,6 +312,7 @@ func (t *Test) GetCmd() *cobra.Command {
AppNetwork: networkName,
MongoPassword: mongoPassword,
Delay: delay,
BuildDelay: buildDelay,
PassThroughPorts: ports,
ApiTimeout: apiTimeout,
ProxyPort: proxyPort,
Expand All @@ -319,6 +339,8 @@ func (t *Test) GetCmd() *cobra.Command {
testCmd.Flags().StringP("networkName", "n", "", "Name of the application's docker network")
testCmd.Flags().Uint64P("delay", "d", 5, "User provided time to run its application")

testCmd.Flags().DurationP("buildDelay", "", 30*time.Second, "User provided time to wait docker container build")

testCmd.Flags().Uint64("apiTimeout", 5, "User provided timeout for calling its application")

testCmd.Flags().UintSlice("passThroughPorts", []uint{}, "Ports of Outgoing dependency calls to be ignored as mocks")
Expand Down
1 change: 1 addition & 0 deletions pkg/hooks/keploy/keploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ package keploy
// Host string `default:"0.0.0.0"`
// Port string `validate:"required"`
// Delay time.Duration `default:"5s"`
// BuildDelay time.Duration `default:"30s"`
// Timeout time.Duration `default:"60s"`
// Filter Filter
// TestPath string `default:""`
Expand Down
Loading
Loading