Skip to content

Commit bd2c4ea

Browse files
chore: refactor v2 codebase structure (#194)
* 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]>
1 parent c21ea44 commit bd2c4ea

File tree

4 files changed

+192
-157
lines changed

4 files changed

+192
-157
lines changed

README.md

+23-20
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,36 @@ These mocks/stubs are realistic and frees you up from writing them manually. Kep
2525

2626
```go
2727
import(
28-
"github.com/keploy/go-sdk/keploy"
29-
"github.com/keploy/go-sdk/mock"
28+
"github.com/keploy/go-sdk/v2/keploy"
3029
)
3130

3231
// Inside your unit test
3332
...
34-
ctx := mock.NewContext(mock.Config{
33+
err := keploy.New(keploy.Config{
3534
Mode: keploy.MODE_RECORD, // It can be MODE_TEST or MODE_OFF. Default is MODE_TEST. Default MODE_TEST
36-
TestSuite: "<test_suite_name>" // TestSuite name to record the mock or test the mocks
37-
Path: "<local_path_for_saving_test_suite>", // optional. It can be relative(./internals) or absolute(/users/xyz/...)
35+
Name: "<stub_name/mock_name>" // TestSuite name to record the mock or test the mocks
36+
Path: "<local_path_for_saving_mock>", // optional. It can be relative(./internals) or absolute(/users/xyz/...)
3837
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
38+
delay: 10, // by default it is 5 . This delay is for running keploy
3939
})
4040
...
4141
```
4242

4343
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
4444

4545
```go
46-
mock.KillProcessOnPort()
46+
keploy.KillProcessOnPort()
4747
```
4848

4949
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:
5050

5151
```go
52-
ctx := mock.NewContext(mock.Config{
52+
err := keploy.New(keploy.Config{
5353
Mode: keploy.MODE_TEST,
54-
TestSuite: "<test_suite_name>"
55-
Path: "<local_path_for_saving_test_suite>",
54+
Name: "<stub_name/mock_name>"
55+
Path: "<local_path_for_saving_mock>",
5656
EnableKeployLogs: false,
57+
delay: 10,
5758
})
5859
```
5960

@@ -75,17 +76,19 @@ import (
7576
"testing"
7677

7778
"github.com/gin-gonic/gin"
78-
"github.com/keploy/go-sdk/keploy"
79-
"github.com/keploy/go-sdk/v2/mock"
79+
"github.com/keploy/go-sdk/v2/keploy"
8080
)
8181

82-
func setup() {
83-
mock.NewContext(mock.Config{
84-
TestSuite: "test-set-5",
85-
Mode: keploy.MODE_RECORD,
82+
func setup(t *testing.T) {
83+
err := keploy.New(keploy.Config{
84+
Name: "test-set-5",
85+
Mode: keploy.MODE_TEST,
8686
Path: "/home/ubuntu/dont_touch/samples-go/gin-mongo",
87-
EnableKeployLogs: true,
87+
EnableKeployLogs: false,
8888
})
89+
if err != nil {
90+
t.Fatalf("error while running keploy: %v", err)
91+
}
8992
dbName, collection := "keploy", "url-shortener"
9093
client, err := New("localhost:27017", dbName)
9194
if err != nil {
@@ -96,7 +99,7 @@ func setup() {
9699
}
97100

98101
func TestGetURL(t *testing.T) {
99-
setup()
102+
setup(t)
100103
// Setting up Gin and routes
101104
r := gin.Default()
102105
r.GET("/:param", getURL)
@@ -114,10 +117,10 @@ func TestGetURL(t *testing.T) {
114117

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

120-
mock.KillProcessOnPort()
123+
keploy.KillProcessOnPort()
121124

122125
}
123126

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

138141
req, err := http.NewRequest(http.MethodPost, "/url", bytes.NewBuffer(payload))

keploy/mock.go

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package keploy
2+
3+
import (
4+
"errors"
5+
"os/exec"
6+
"path/filepath"
7+
"runtime"
8+
"strconv"
9+
"strings"
10+
"time"
11+
12+
"go.uber.org/zap"
13+
14+
"fmt"
15+
"os"
16+
)
17+
18+
var (
19+
logger *zap.Logger
20+
)
21+
22+
type Config struct {
23+
Mode Mode // Keploy mode on which unit test will run. Possible values: MODE_TEST or MODE_RECORD. Default: MODE_TEST
24+
Name string // Name to record the mock or test the mocks
25+
Path string // Path in which Keploy "/mocks" will be generated. Default: current working directroy.
26+
EnableKeployLogs bool
27+
Delay int
28+
}
29+
30+
func New(conf Config) error {
31+
32+
var (
33+
mode = MODE_OFF
34+
err error
35+
path string = conf.Path
36+
keployCmd string
37+
delay int = 5
38+
)
39+
40+
logger, _ = zap.NewDevelopment()
41+
defer func() {
42+
_ = logger.Sync()
43+
}()
44+
45+
// killing keploy instance if it is running already
46+
KillProcessOnPort()
47+
48+
if Mode(conf.Mode).Valid() {
49+
mode = Mode(conf.Mode)
50+
} else {
51+
return errors.New("provided keploy mode is invalid, either use MODE_RECORD/MODE_TEST/MODE_OFF")
52+
}
53+
54+
if conf.Delay > 5 {
55+
delay = conf.Delay
56+
}
57+
58+
if mode == MODE_OFF {
59+
return nil
60+
}
61+
62+
// use current directory, if path is not provided or relative in config
63+
if path == "" {
64+
path, err = os.Getwd()
65+
if err != nil {
66+
return fmt.Errorf("no specific path provided and failed to get current working directory %w", err)
67+
}
68+
logger.Info("no specific path provided; defaulting to the current working directory", zap.String("currentDirectoryPath", path))
69+
} else if path[0] != '/' {
70+
path, err = filepath.Abs(path)
71+
if err != nil {
72+
return fmt.Errorf("failed to get the absolute path from provided path %w", err)
73+
}
74+
} else {
75+
if _, err := os.Stat(path); os.IsNotExist(err) {
76+
return fmt.Errorf("provided path does not exist %w", err)
77+
}
78+
logger.Info("using provided path to store mocks", zap.String("providedPath", path))
79+
}
80+
81+
if conf.Name == "" {
82+
return errors.New("provided mock name is empty")
83+
}
84+
85+
if mode == MODE_RECORD {
86+
if _, err := os.Stat(path + "/stubs/" + conf.Name + "-mocks.yaml"); !os.IsNotExist(err) {
87+
cmd := exec.Command("sudo", "rm", "-rf", path+"/stubs/"+conf.Name+"-mocks.yaml")
88+
_, err := cmd.CombinedOutput()
89+
if err != nil {
90+
return fmt.Errorf("failed to replace existing mock file %w", err)
91+
}
92+
}
93+
if _, err := os.Stat(path + "/stubs/" + conf.Name + "-config.yaml"); !os.IsNotExist(err) {
94+
cmd := exec.Command("sudo", "rm", "-rf", path+"/stubs/"+conf.Name+"-config.yaml")
95+
_, err := cmd.CombinedOutput()
96+
if err != nil {
97+
return fmt.Errorf("failed to replace existing mock file %w", err)
98+
}
99+
}
100+
}
101+
102+
appPid := os.Getpid()
103+
104+
recordCmd := "sudo -E /usr/local/bin/keploy mockRecord --pid " + strconv.Itoa(appPid) + " --path " + path + " --mockName " + conf.Name + " --debug"
105+
testCmd := "sudo -E /usr/local/bin/keploy mockTest --pid " + strconv.Itoa(appPid) + " --path " + path + " --mockName " + conf.Name + " --debug"
106+
107+
if mode == MODE_TEST {
108+
keployCmd = testCmd
109+
} else {
110+
keployCmd = recordCmd
111+
}
112+
113+
parts := strings.Fields(keployCmd)
114+
cmd := exec.Command(parts[0], parts[1:]...)
115+
if conf.EnableKeployLogs {
116+
cmd.Stdout = os.Stdout
117+
cmd.Stderr = os.Stderr
118+
}
119+
120+
if _, err := exec.LookPath("keploy"); err != nil {
121+
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)
122+
}
123+
124+
errChan := make(chan error)
125+
126+
go func() {
127+
err := cmd.Run()
128+
if err != nil {
129+
errChan <- err
130+
}
131+
close(errChan)
132+
}()
133+
134+
select {
135+
case err := <-errChan:
136+
if err != nil {
137+
return err
138+
}
139+
return nil
140+
case <-time.After(time.Duration(delay) * time.Second):
141+
return nil
142+
}
143+
}
144+
145+
func KillProcessOnPort() {
146+
port := 16789
147+
cmd := exec.Command("sudo", "lsof", "-t", "-i:"+strconv.Itoa(port))
148+
output, err := cmd.Output()
149+
if _, ok := err.(*exec.ExitError); ok && len(output) == 0 {
150+
return
151+
} else if err != nil {
152+
logger.Error("Failed to execute lsof: %v\n", zap.Error(err))
153+
return
154+
}
155+
appPid := os.Getpid()
156+
pids := strings.Split(strings.Trim(string(output), "\n"), "\n")
157+
for _, pid := range pids {
158+
if pid != strconv.Itoa(appPid) {
159+
forceKillProcessByPID(pid)
160+
}
161+
}
162+
}
163+
164+
func forceKillProcessByPID(pid string) {
165+
cmd := exec.Command("sudo", "kill", "-9", pid)
166+
if err := cmd.Run(); err != nil {
167+
logger.Error(fmt.Sprintf("Failed to kill process with PID %s:", pid), zap.Error(err))
168+
}
169+
}

pkg/keploy/mode.go keploy/mode.go

File renamed without changes.

0 commit comments

Comments
 (0)