Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
72a98a3
feat: coverage initial set up
officialasishkumar Jul 11, 2025
82ad3f8
feat: update comments
officialasishkumar Jul 11, 2025
97c399b
feat: update dedupData.yaml with correct values
officialasishkumar Jul 11, 2025
bb44533
refactor: remove the old vendor
officialasishkumar Jul 11, 2025
70ce9c9
feat: add vendor
officialasishkumar Jul 11, 2025
f127770
fix: update comments
officialasishkumar Jul 11, 2025
6c9c869
feat: add clear counters after every test case run
officialasishkumar Jul 11, 2025
2b0838a
feat: update comments
officialasishkumar Jul 13, 2025
7535b0d
refactor: better comments
officialasishkumar Jul 13, 2025
0f4aa64
feat: update go mod file
officialasishkumar Jul 14, 2025
bf077d9
feat: skip reporting in case of mismatched test id
officialasishkumar Jul 14, 2025
507a7ae
fix: bump go version
officialasishkumar Jul 14, 2025
0e5164e
fix: bump go version
officialasishkumar Jul 14, 2025
e336519
fix: bump go version
officialasishkumar Jul 14, 2025
02871c3
fix: add install command in workflow
officialasishkumar Jul 14, 2025
1361064
fix: bump go version
officialasishkumar Jul 14, 2025
016e97a
fix: bump go version in workflow
officialasishkumar Jul 14, 2025
b1f7d07
feat: add an ack in end command
officialasishkumar Jul 28, 2025
fb5e49c
fix: block.count continue
officialasishkumar Jul 28, 2025
87a23a7
feat: bump sdk version
officialasishkumar Jul 28, 2025
b4c5457
refactor: better file name for sock
officialasishkumar Jul 28, 2025
bc82e36
fix: early return and new coverage folder name
officialasishkumar Jul 29, 2025
3243cb1
feat: change socket name
officialasishkumar Jul 29, 2025
99c1c6a
fix: dir creation error
officialasishkumar Jul 30, 2025
67dc6bf
feat: add more instruction for coverage
officialasishkumar Jul 31, 2025
7673905
feat: add golang ci lint
officialasishkumar Jul 31, 2025
333499d
feat: add golang ci lint
officialasishkumar Jul 31, 2025
108b37c
feat: add golang ci lint
officialasishkumar Jul 31, 2025
6c6c3f0
feat: add golang ci lint
officialasishkumar Jul 31, 2025
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
5 changes: 4 additions & 1 deletion .github/workflows/build-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.16
go-version: 1.24

- name: Install dependencies
run: go mod tidy

- name: Build
run: go build -v ./...
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: golangci-lint

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read

# Cancel the in-progress workflow when PR is refreshed.
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
env:
CGO_ENABLED: "1"
permissions:
contents: read
packages: write
id-token: write

steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v4
with:
go-version: "1.24"
cache: false
- name: Installing build Essentials and gcc
run: |
sudo apt -y update
sudo apt -y install build-essential gcc libc-dev \
pkg-config \
libgl1-mesa-dev \
libxi-dev libxcursor-dev \
libxrandr-dev libxinerama-dev \
libxxf86vm-dev libx11-dev libx11-xcb-dev

- name: golangci-lint
uses: golangci/golangci-lint-action@v7
with:
only-new-issues: true
args: --timeout=7m
203 changes: 21 additions & 182 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,203 +1,42 @@
# Keploy Go-SDK
# Keploy Go Coverage Agent

This is the client SDK for the [Keploy](https://github.com/keploy/keploy) testing platform. You can use this to generate realistic mock/stub files for your applications.
This package enables native Go coverage reporting for tests generated by Keploy enterprise. It works by listening for commands from the Keploy binary to start and stop coverage collection for each test case.

## Contents
## How to Use

1. [Installation](#installation)
2. [Usage](#usage)
3. [Mocking/Stubbing for unit tests](#mockingstubbing-for-unit-tests)
4. [Code coverage by the API tests](#code-coverage-by-the-api-tests)
To integrate the coverage agent into your Go application, follow these two steps:

## Installation
### 1. Activate the Agent

```bash
go get -u github.com/keploy/go-sdk/v2
```

## Usage

### Get coverage for keploy automated tests
The code coverage for the keploy API tests using the `go-test` integration.
Keploy can be integrated in your CI pipeline which can add the coverage of your keploy test.

### Create mocks/stubs for your unit-test

These mocks/stubs are realistic and frees you up from writing them manually. Keploy creates `readable/editable` mocks/stubs yaml files which can be referenced in any of your unit-tests tests. An example is mentioned in [Mocking/Stubbing for unit tests](#mockingstubbing-for-unit-tests) section

1. Install [keploy](https://github.com/keploy/keploy#quick-installation) binary
2. **Record**: To record you can import the keploy mocking library and set the mode to record mode and run you databases. This should generate a file containing the mocks/stubs.
Add a blank import for the package in your application's main entry point (e.g., in your `main.go` file). This import's side effects will automatically initialize and run the coverage agent in the background.

```go
import(
"github.com/keploy/go-sdk/v2/keploy"
import (
// ... other imports
_ "github.com/keploy/go-sdk/v3/keploy"
)

// Inside your unit test
...
err := keploy.New(keploy.Config{
Mode: keploy.MODE_RECORD, // It can be MODE_TEST or MODE_OFF. Default is MODE_TEST. Default MODE_TEST
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/...)
MuteKeployLogs: false, // optional. It can be true or false. If it is true keploy logs will be not 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
### 2. Build with Coverage Flags

```go
keploy.KillProcessOnPort()
```
Compile your application using the `-cover` and `-covermode=atomic` flags. These are required for the agent to access and clear coverage data for each test run according to https://pkg.go.dev/runtime/coverage@go1.25rc2#ClearCounters

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
err := keploy.New(keploy.Config{
Mode: keploy.MODE_TEST,
Name: "<stub_name/mock_name>"
Path: "<local_path_for_saving_mock>",
MubeKeployLogs: false,
delay: 10,
})
```bash
go build -cover -covermode=atomic -o your-app .
```

## Mocking/Stubbing for unit tests

Mocks/Stubs can be generated for external dependency calls of go unit tests as `readable/editable` yaml files using Keploy.

### Example

```go
package main

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"

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

func setup(t *testing.T) {
err := keploy.New(keploy.Config{
Name: "TestPutURL",
Mode: keploy.MODE_RECORD, // change to MODE_TEST when you run in test mode
Path: "/home/ubuntu/dont_touch/samples-go/gin-mongo",
MuteKeployLogs: false,
Delay: 15,
})
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 {
panic("Failed to initialize MongoDB: " + err.Error())
}
db := client.Database(dbName)
col = db.Collection(collection)
}

func TestPutURL(t *testing.T) {

defer keploy.KillProcessOnPort()
setup(t)

r := gin.Default()
r.GET("/:param", getURL)
r.POST("/url", putURL)

data := map[string]string{
"url": "https://www.example.com",
}
payload, err := json.Marshal(data)
if err != nil {
t.Fatalf("rfe: %v\n", err)
}
### 3. Run tests with Keploy enterprise version

req, err := http.NewRequest(http.MethodPost, "/url", bytes.NewBuffer(payload))
if err != nil {
t.Fatalf("Couldn't create request: %v\n", err)
}
req.Header.Set("Content-Type", "application/json")

w := httptest.NewRecorder()
r.ServeHTTP(w, req)

// Checking if the URL was successfully shortened and stored
if w.Code != http.StatusOK {
t.Fatalf("Expected HTTP 200 OK, but got %v", w.Code)
}

var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v\n", err)
}
fmt.Println("response-url" + response["url"].(string))

if response["url"] == nil || response["ts"] == nil {
t.Fatalf("Response did not contain expected fields")
}
}
```bash
sudo -E keploy-enterprise test -c "./your-app" --dedup
```

## Code coverage by the API tests
Now you will see `dedupData.yaml` getting created.

The percentage of code covered by the recorded tests is logged if the test cmd is ran with the go binary and `withCoverage` flag. The conditions for the coverage is:
1. The go binary should be built with `-cover` flag.
2. The application should have a graceful shutdown to stop the API server on `SIGTERM` or `SIGINT` signals. Or if not call the **GracefulShutdown** from the main function of your go program. Ex:
```go
func main() {
Run `sudo -E keploy-enterprise dedup` to get the tests which are duplicate in `duplicates.yaml` file

port := "8080"
In order to remove the duplicate tests, run the following command:

r := gin.Default()

r.GET("/:param", getURL)
r.POST("/url", putURL)
// should be called before starting the API server from main()
keploy.GracefulShutdown()

r.Run()
}
```
The keploy test cmd will look like:
```sh
keploy test -c "PATH_TO_GO_COVER_BIANRY" --withCoverage
```
The coverage files will be stored in the directory.
```
keploy
├── coverage-reports
│ ├── covcounters.befc2fe88a620bbd45d85aa09517b5e7.305756.1701767439933176870
│ ├── covmeta.befc2fe88a620bbd45d85aa09517b5e7
│ └── total-coverage.txt
├── test-set-0
│ ├── mocks.yaml
│ └── tests
│ ├── test-1.yaml
│ ├── test-2.yaml
│ ├── test-3.yaml
│ └── test-4.yaml
```
Coverage percentage log in the cmd will be:
```sh
🐰 Keploy: 2023-12-07T08:53:14Z INFO test/test.go:261
test-app-url-shortener coverage: 78.4% of statements
```bash
sudo -E keploy-enterprise dedup --rm
```

Also the go-test coverage can be merged along the recorded tests coverage by following the steps:
```sh
go test -cover ./... -args -test.gocoverdir="PATH_TO_UNIT_COVERAGE_FILES"

go tool covdata textfmt -i="PATH_TO_UNIT_COVERAGE_FILES","./keploy/coverage-reports" -o coverage-profile

go tool cover -func coverage-profile
```
13 changes: 3 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
module github.com/keploy/go-sdk/v2
module github.com/keploy/go-sdk/v3

go 1.16
go 1.24

//replace go.keploy.io/server => ../keploy

require go.uber.org/zap v1.22.0

require (
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.7.1 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
)
require golang.org/x/tools v0.1.5
60 changes: 1 addition & 59 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,60 +1,2 @@
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading