Skip to content

Commit

Permalink
fix: go coverage in native (keploy#1814)
Browse files Browse the repository at this point in the history
* fix:go coverage

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

* fix: nil pointer exception in http parser

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

* fix: logs in decodeHttp

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

* restored umask even if err

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

* chore: format

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

---------

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>
  • Loading branch information
gouravkrosx authored Apr 12, 2024
1 parent 9f240e3 commit 6328642
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 42 deletions.
31 changes: 23 additions & 8 deletions cli/provider/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ func (c *CmdConfigurator) AddFlags(cmd *cobra.Command) error {
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().String("cmdType", c.cfg.CommandType, "Type of command to start the user application (native/docker/docker-compose)")
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")
Expand Down Expand Up @@ -323,6 +324,10 @@ func (c CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command)
}
return errors.New("missing required -c flag or appCmd in config file")
}

// set the command type
c.cfg.CommandType = string(utils.FindDockerCmd(c.cfg.Command))

if c.cfg.GenerateGithubActions {
defer utils.GenerateGithubActions(c.logger, c.cfg.Command)
}
Expand All @@ -336,12 +341,12 @@ func (c CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command)
return errors.New(errMsg)
}
if strings.Contains(c.cfg.Path, "..") {
c.cfg.Path, err = filepath.Abs(filepath.Clean(c.cfg.Path))

c.cfg.Path, err = utils.GetAbsPath(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)
return fmt.Errorf("failed to get the absolute path from relative path: %w", err)
}

relativePath, err := filepath.Rel(curDir, c.cfg.Path)
if err != nil {
errMsg := "failed to get the relative path from absolute path"
Expand Down Expand Up @@ -374,12 +379,12 @@ func (c CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command)
return err
}

absPath, err := filepath.Abs(c.cfg.Path)
absPath, err := utils.GetAbsPath(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)
utils.LogError(c.logger, err, "error while getting absolute path")
return errors.New("failed to get the absolute path")
}

c.cfg.Path = absPath + "/keploy"
if cmd.Name() == "test" {
testSets, err := cmd.Flags().GetStringSlice("testsets")
Expand All @@ -389,6 +394,16 @@ func (c CmdConfigurator) ValidateFlags(ctx context.Context, cmd *cobra.Command)
return errors.New(errMsg)
}
config.SetSelectedTests(c.cfg, testSets)

if utils.CmdType(c.cfg.CommandType) == utils.Native && c.cfg.Test.GoCoverage {
goCovPath, err := utils.SetCoveragePath(c.logger, c.cfg.Test.CoverageReportPath)
if err != nil {
utils.LogError(c.logger, err, "failed to set go coverage path")
return errors.New("failed to set go coverage path")
}
c.cfg.Test.CoverageReportPath = goCovPath
}

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 {
Expand Down
10 changes: 10 additions & 0 deletions cli/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"context"
"os"

"go.keploy.io/server/v2/pkg/graph"
"go.keploy.io/server/v2/utils"
Expand Down Expand Up @@ -44,6 +45,15 @@ func Test(ctx context.Context, logger *zap.Logger, cfg *config.Config, serviceFa
return nil
}
}

cmdType := utils.FindDockerCmd(cfg.Command)
if cmdType == utils.Native && cfg.Test.GoCoverage {
err := os.Setenv("GOCOVERDIR", cfg.Test.CoverageReportPath)
if err != nil {
utils.LogError(logger, err, "failed to set GOCOVERDIR")
return nil
}
}
err = replay.Start(ctx)
if err != nil {
utils.LogError(logger, err, "failed to replay")
Expand Down
5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Package config provides configuration structures for the application.
package config

import "time"
import (
"time"
)

type Config struct {
Path string `json:"path" yaml:"path" mapstructure:"path" `
Expand All @@ -23,6 +25,7 @@ type Config struct {
GenerateGithubActions bool `json:"generateGithubActions" yaml:"generateGithubActions" mapstructure:"generateGithubActions"`
KeployContainer string `json:"keployContainer" yaml:"keployContainer" mapstructure:"keployContainer"`
KeployNetwork string `json:"keployNetwork" yaml:"keployNetwork" mapstructure:"keployNetwork"`
CommandType string `json:"cmdType" yaml:"cmdType" mapstructure:"cmdType"`
}

type Record struct {
Expand Down
1 change: 1 addition & 0 deletions config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enableTesting: false
keployContainer: "keploy-v2"
keployNetwork: "keploy-network"
inDocker: false
cmdType: "native"
`

var config = &Config{}
Expand Down
6 changes: 4 additions & 2 deletions pkg/service/replay/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,10 @@ func (r *Replayer) printSummary(ctx context.Context, testRunResult bool) {
return
}
r.logger.Info("test run completed", zap.Bool("passed overall", testRunResult))
if r.config.Test.GoCoverage {
r.logger.Info("there is a opportunity to get the coverage here")

if utils.CmdType(r.config.CommandType) == utils.Native && r.config.Test.GoCoverage {
r.logger.Info("there is an opportunity to get the coverage here")

coverCmd := exec.CommandContext(ctx, "go", "tool", "covdata", "percent", "-i="+os.Getenv("GOCOVERDIR"))
output, err := coverCmd.Output()
if err != nil {
Expand Down
93 changes: 62 additions & 31 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,37 +383,6 @@ const (
Native CmdType = "native"
)

type RecordFlags struct {
Path string
Command string
ContainerName string
Proxyport uint32
NetworkName string
Delay uint64
BuildDelay time.Duration
PassThroughPorts []uint
ConfigPath string
EnableTele bool
}

type TestFlags struct {
Path string
Proxyport uint32
Command string
Testsets []string
ContainerName string
NetworkName string
Delay uint64
BuildDelay time.Duration
APITimeout uint64
PassThroughPorts []uint
ConfigPath string
MongoPassword string
CoverageReportPath string
EnableTele bool
WithCoverage bool
}

func getAlias(ctx context.Context, logger *zap.Logger) (string, error) {
// Get the name of the operating system.
osName := runtime.GOOS
Expand Down Expand Up @@ -536,6 +505,68 @@ func SentryInit(logger *zap.Logger, dsn string) {
// return os.Getenv("HOME") + configFolder
//}

func GetAbsPath(path string) (string, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return "", err
}
return absPath, nil
}

// makeDirectory creates a directory if not exists with all user access
func makeDirectory(path string) error {
oldUmask := syscall.Umask(0)
defer syscall.Umask(oldUmask)
err := os.MkdirAll(path, 0777)
if err != nil {
return err
}
return nil
}

// SetCoveragePath takes a goCovPath and sets the coverage path accordingly.
// It returns an error if the path is a file or if the path does not exist.
func SetCoveragePath(logger *zap.Logger, goCovPath string) (string, error) {
if goCovPath == "" {
// Calculate the current path and create a coverage-reports directory
currentPath, err := GetAbsPath("")
if err != nil {
LogError(logger, err, "failed to get the current working directory")
return "", err
}
goCovPath = currentPath + "/coverage-reports"
if err := makeDirectory(goCovPath); err != nil {
LogError(logger, err, "failed to create coverage-reports directory", zap.String("CoverageReportPath", goCovPath))
return "", err
}
return goCovPath, nil
}

goCovPath, err := GetAbsPath(goCovPath)
if err != nil {
LogError(logger, err, "failed to get the absolute path for the coverage report path", zap.String("CoverageReportPath", goCovPath))
return "", err
}
// Check if the path is a directory
dirInfo, err := os.Stat(goCovPath)
if err != nil {
if os.IsNotExist(err) {
LogError(logger, err, "the provided path does not exist", zap.String("CoverageReportPath", goCovPath))
return "", err
}
LogError(logger, err, "failed to check the coverage report path", zap.String("CoverageReportPath", goCovPath))
return "", err
}
if !dirInfo.IsDir() {
msg := "the coverage report path is not a directory. Please provide a valid path to a directory for go coverage reports"

LogError(logger, nil, msg, zap.String("CoverageReportPath", goCovPath))
return "", errors.New("the path provided is not a directory")
}

return goCovPath, nil
}

// InterruptProcessTree interrupts an entire process tree using the given signal
func InterruptProcessTree(logger *zap.Logger, ppid int, sig syscall.Signal) error {
// Find all descendant PIDs of the given PID & then signal them.
Expand Down

0 comments on commit 6328642

Please sign in to comment.