I run Windows. Most Go tutorials assume you don’t. This guide covers the full WSL2 setup so you can use Keploy without skipping the hard parts.
- A Go + Gin + Redis authentication API running locally
- Keploy recording your real API calls as test cases
- Those tests replaying without Redis running, using auto-generated mocks
Why Windows Users Need a Detour
Keploy doesn't run natively on Windows the way it does on Linux, eBPF is a Linux kernel feature. Your options:
| Option | The short version |
|---|---|
| WSL2 (what I used) | What every quickstart in Keploy's docs actually assumes; Go tooling just behaves better in a real Linux shell |
| Docker | Run everything containerized |
| Native Windows build | AMD-only, admin rights required |
I went with WSL2, and the four setup steps below get you from a bare Windows machine to a Keploy-ready Linux environment.
Setting up WSL2 + Ubuntu
wsl --install -d Ubuntu-22.04Run this in an elevated PowerShell window (right-click → Run as Administrator). It downloads Ubuntu, and on first launch asks you to create a Linux username and password, separate from your Windows login.
Once inside Ubuntu, don't work out of your Windows filesystem (/mnt/c/...), move to your
Linux home directory first:
cd ~This avoids permission weirdness and is noticeably faster for anything involving go build
or git.
Installing Go
Ubuntu's default apt package for Go is often years out of date (I got 1.18 when the
current stable was well past 1.23). Skip apt and install directly from Go's official
binary:
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
go versionInstalling Keploy
curl --silent -O -L https://keploy.io/install.sh && source install.sh
keploy --versionThen authenticate:
keploy loginThis opens a browser tab to sign in. You have about a minute before the auth code expires, if you're slow to switch tabs, it'll time out and you'll just need to re-run the command.
Running the Gin + Redis Sample
This is a small OTP-based authentication API, request a code, verify it, get a token back.
git clone https://github.com/keploy/samples-go.git && cd samples-go/gin-redis
go mod downloadStart Redis in the background:
docker compose up -d redisBuild the app:
go build -o gin-redisRecording Test Cases
This is the actual Keploy step. Everything before this was just getting a Linux environment ready.
sudo -E PATH="$PATH" keploy record -c "./gin-redis"With that running, open a second terminal and make real API calls. First, request a verification code:
curl --location 'localhost:3001/api/getVerificationCode?email=something@gmail.com&username=shivamsourav'Take the OTP from the response and verify it:
curl --location 'localhost:3001/api/verifyCode' \
--header 'Content-Type: application/json' \
--data-raw '{"otp":7454,"email":"something@gmail.com"}'Stop the recording with Ctrl+C. Keploy writes everything it saw into a keploy/ folder:
ls -R keploy/You'll find two things in there:
Your actual request/response pairs, each curl call you made, captured as a replayable test case.
The raw Redis protocol traffic that happened behind the scenes, SETs, GETs, EXPIREs, all captured verbatim.
Replaying Without Redis
This is the payoff. Stop your Redis container, or just trust that Keploy doesn't need it:
keploy test -c './gin-redis' --mappingsKeploy replays your exact curl calls against a fresh instance of the app, but instead of hitting real Redis, it serves back the exact Redis responses it recorded earlier. No live database dependency, no test data drifting between runs, no "works on my machine."
The Bug That Taught Me the Most
My first replay attempt failed with status_code expected=200 got=500. Here's the
debugging trail, because I think it's more useful than a clean success story.
The test report flagged SCHEMA_BROKEN, my replayed response was missing the token and
username fields entirely, meaning the verify call failed on replay even though it had
succeeded live. I checked the recorded mocks and found only 3 Redis mock entries, all
handshake/config traffic (CLIENT SETINFO, module discovery). The actual SET and GET
calls that store and retrieve the OTP were never captured.
The cause: I was running Redis via docker compose up redis, with Docker Desktop's WSL2
backend routing that traffic through its virtualized network layer. Keploy's eBPF hook,
which watches Linux kernel network calls directly, never saw those specific packets, they
were happening one layer removed from where it was looking.
Switching to native Redis fixed it immediately, mock count went from 3 to 5, now including
the real SET otp and GET otp commands. Re-running the tests got me a passing
getVerificationCode call, but verifyCode still flagged as failed: category: SCHEMA_UNCHANGED, with token as the only differing field.
That one wasn't a bug, it was expected. The JWT is signed fresh on every successful auth,
so its exact string will never match between record and replay, the same way the OTP itself
won't. Keploy's assertions.noise list is built exactly for this: fields you expect to
legitimately differ between runs, so the test focuses on the response shape being correct
rather than pinning volatile values.
assertions:
noise:
- body.token
- body.otp
- header.DateWith token added to that list, the suite goes fully green.
Quick Answers
A few questions I had to answer for myself along the way, collected in one place:
What This Actually Buys You
The interesting part isn't "look, tests pass." It's this:
Your integration tests no longer need a live Redis instance, database, or downstream service to run in CI.
The mocks are generated from real traffic, not hand-written stubs that quietly fall out of sync with what your API actually does.
You're not instrumenting handlers or writing fixtures, you're just calling your API normally while Keploy watches.
If you're evaluating Keploy for a Go service with any kind of database or cache dependency, this Gin+Redis quickstart is the fastest way to feel that difference yourself, WSL setup aside.
One last thing worth saying plainly: the debugging above wasn't a detour from learning Keploy, it was learning Keploy. Understanding why the mocks came up short taught me more about how the eBPF interception actually works than a clean first-try run ever would have.