Skip to content

Commit

Permalink
chore: refactor v2 codebase structure (#194)
Browse files Browse the repository at this point in the history
* fix: remove pkg and mock packages

Signed-off-by: charankamarapu <[email protected]>

* doc: update readme

Signed-off-by: charankamarapu <[email protected]>

* fix: add debug flag to keploy commands

Signed-off-by: charankamarapu <[email protected]>

* fix: delete mock file if mockName is same

Signed-off-by: charankamarapu <[email protected]>

---------

Signed-off-by: charankamarapu <[email protected]>
  • Loading branch information
charankamarapu authored Sep 12, 2023
1 parent c21ea44 commit bd2c4ea
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 157 deletions.
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,36 @@ These mocks/stubs are realistic and frees you up from writing them manually. Kep

```go
import(
"github.com/keploy/go-sdk/keploy"
"github.com/keploy/go-sdk/mock"
"github.com/keploy/go-sdk/v2/keploy"
)

// Inside your unit test
...
ctx := mock.NewContext(mock.Config{
err := keploy.New(keploy.Config{
Mode: keploy.MODE_RECORD, // It can be MODE_TEST or MODE_OFF. Default is MODE_TEST. Default MODE_TEST
TestSuite: "<test_suite_name>" // TestSuite name to record the mock or test the mocks
Path: "<local_path_for_saving_test_suite>", // optional. It can be relative(./internals) or absolute(/users/xyz/...)
Name: "<stub_name/mock_name>" // TestSuite name to record the mock or test the mocks
Path: "<local_path_for_saving_mock>", // optional. It can be relative(./internals) or absolute(/users/xyz/...)
EnableKeployLogs: false, // optional. It can be true or false. If it is true keploy logs will be shown in the unit test terminal. Default: false
delay: 10, // by default it is 5 . This delay is for running keploy
})
...
```

At the end of the test case you can add the following function which will terminate keploy if not keploy will be running even after unit test is run

```go
mock.KillProcessOnPort()
keploy.KillProcessOnPort()
```

3. **Mock**: To mock dependency as per the content of the generated file (during testing) - just set the `Mode` config to `keploy.MODE_TEST` eg:

```go
ctx := mock.NewContext(mock.Config{
err := keploy.New(keploy.Config{
Mode: keploy.MODE_TEST,
TestSuite: "<test_suite_name>"
Path: "<local_path_for_saving_test_suite>",
Name: "<stub_name/mock_name>"
Path: "<local_path_for_saving_mock>",
EnableKeployLogs: false,
delay: 10,
})
```

Expand All @@ -75,17 +76,19 @@ import (
"testing"

"github.com/gin-gonic/gin"
"github.com/keploy/go-sdk/keploy"
"github.com/keploy/go-sdk/v2/mock"
"github.com/keploy/go-sdk/v2/keploy"
)

func setup() {
mock.NewContext(mock.Config{
TestSuite: "test-set-5",
Mode: keploy.MODE_RECORD,
func setup(t *testing.T) {
err := keploy.New(keploy.Config{
Name: "test-set-5",
Mode: keploy.MODE_TEST,
Path: "/home/ubuntu/dont_touch/samples-go/gin-mongo",
EnableKeployLogs: true,
EnableKeployLogs: false,
})
if err != nil {
t.Fatalf("error while running keploy: %v", err)
}
dbName, collection := "keploy", "url-shortener"
client, err := New("localhost:27017", dbName)
if err != nil {
Expand All @@ -96,7 +99,7 @@ func setup() {
}

func TestGetURL(t *testing.T) {
setup()
setup(t)
// Setting up Gin and routes
r := gin.Default()
r.GET("/:param", getURL)
Expand All @@ -114,10 +117,10 @@ func TestGetURL(t *testing.T) {

// We're just checking if it can successfully redirect
if w.Code != http.StatusSeeOther {
t.Fatalf("Expected HTTP 303 See Other, but got %v", w.Code)
t.Fatalf("Expcd HTTP 303 See Other, but got %v", w.Code)
}

mock.KillProcessOnPort()
keploy.KillProcessOnPort()

}

Expand All @@ -132,7 +135,7 @@ func TestPutURL(t *testing.T) {
}
payload, err := json.Marshal(data)
if err != nil {
t.Fatalf("rre: %v\n", err)
t.Fatalf("rrdfe: %v\n", err)
}

req, err := http.NewRequest(http.MethodPost, "/url", bytes.NewBuffer(payload))
Expand Down
169 changes: 169 additions & 0 deletions keploy/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package keploy

import (
"errors"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"

"go.uber.org/zap"

"fmt"
"os"
)

var (
logger *zap.Logger
)

type Config struct {
Mode Mode // Keploy mode on which unit test will run. Possible values: MODE_TEST or MODE_RECORD. Default: MODE_TEST
Name string // Name to record the mock or test the mocks
Path string // Path in which Keploy "/mocks" will be generated. Default: current working directroy.
EnableKeployLogs bool
Delay int
}

func New(conf Config) error {

var (
mode = MODE_OFF
err error
path string = conf.Path
keployCmd string
delay int = 5
)

logger, _ = zap.NewDevelopment()
defer func() {
_ = logger.Sync()
}()

// killing keploy instance if it is running already
KillProcessOnPort()

if Mode(conf.Mode).Valid() {
mode = Mode(conf.Mode)
} else {
return errors.New("provided keploy mode is invalid, either use MODE_RECORD/MODE_TEST/MODE_OFF")
}

if conf.Delay > 5 {
delay = conf.Delay
}

if mode == MODE_OFF {
return nil
}

// use current directory, if path is not provided or relative in config
if path == "" {
path, err = os.Getwd()
if err != nil {
return fmt.Errorf("no specific path provided and failed to get current working directory %w", err)
}
logger.Info("no specific path provided; defaulting to the current working directory", zap.String("currentDirectoryPath", path))
} else if path[0] != '/' {
path, err = filepath.Abs(path)
if err != nil {
return fmt.Errorf("failed to get the absolute path from provided path %w", err)
}
} else {
if _, err := os.Stat(path); os.IsNotExist(err) {
return fmt.Errorf("provided path does not exist %w", err)
}
logger.Info("using provided path to store mocks", zap.String("providedPath", path))
}

if conf.Name == "" {
return errors.New("provided mock name is empty")
}

if mode == MODE_RECORD {
if _, err := os.Stat(path + "/stubs/" + conf.Name + "-mocks.yaml"); !os.IsNotExist(err) {
cmd := exec.Command("sudo", "rm", "-rf", path+"/stubs/"+conf.Name+"-mocks.yaml")
_, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to replace existing mock file %w", err)
}
}
if _, err := os.Stat(path + "/stubs/" + conf.Name + "-config.yaml"); !os.IsNotExist(err) {
cmd := exec.Command("sudo", "rm", "-rf", path+"/stubs/"+conf.Name+"-config.yaml")
_, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to replace existing mock file %w", err)
}
}
}

appPid := os.Getpid()

recordCmd := "sudo -E /usr/local/bin/keploy mockRecord --pid " + strconv.Itoa(appPid) + " --path " + path + " --mockName " + conf.Name + " --debug"
testCmd := "sudo -E /usr/local/bin/keploy mockTest --pid " + strconv.Itoa(appPid) + " --path " + path + " --mockName " + conf.Name + " --debug"

if mode == MODE_TEST {
keployCmd = testCmd
} else {
keployCmd = recordCmd
}

parts := strings.Fields(keployCmd)
cmd := exec.Command(parts[0], parts[1:]...)
if conf.EnableKeployLogs {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}

if _, err := exec.LookPath("keploy"); err != nil {
return fmt.Errorf("keploy binary not found, please ensure it is installed. Host OS: %s, Architecture: %s. For installing please follow instructions https://github.com/keploy/keploy#quick-installation", runtime.GOOS, runtime.GOARCH)
}

errChan := make(chan error)

go func() {
err := cmd.Run()
if err != nil {
errChan <- err
}
close(errChan)
}()

select {
case err := <-errChan:
if err != nil {
return err
}
return nil
case <-time.After(time.Duration(delay) * time.Second):
return nil
}
}

func KillProcessOnPort() {
port := 16789
cmd := exec.Command("sudo", "lsof", "-t", "-i:"+strconv.Itoa(port))
output, err := cmd.Output()
if _, ok := err.(*exec.ExitError); ok && len(output) == 0 {
return
} else if err != nil {
logger.Error("Failed to execute lsof: %v\n", zap.Error(err))
return
}
appPid := os.Getpid()
pids := strings.Split(strings.Trim(string(output), "\n"), "\n")
for _, pid := range pids {
if pid != strconv.Itoa(appPid) {
forceKillProcessByPID(pid)
}
}
}

func forceKillProcessByPID(pid string) {
cmd := exec.Command("sudo", "kill", "-9", pid)
if err := cmd.Run(); err != nil {
logger.Error(fmt.Sprintf("Failed to kill process with PID %s:", pid), zap.Error(err))
}
}
File renamed without changes.
Loading

0 comments on commit bd2c4ea

Please sign in to comment.