Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This repo contains the sample for [Keploy's](https://keploy.io) Java Application
4. [Springboot Postgres GraphQL](https://github.com/keploy/samples-java/tree/main/spring-boot-postgres-graphql) - This is a Spring Boot application implementing a GraphQL service to handle requests related to books and authors.
5. [Springboot PetClinic](https://github.com/keploy/samples-java/tree/main/spring-petclinic) - This is a Pet Clinic app where you can record testcases and mocks by interacting with the UI, and then test them using Keploy.
6. [SAP Demo (Customer 360)](https://github.com/keploy/samples-java/tree/main/sap-demo-java) - A Spring Boot "Customer 360" API that fronts SAP S/4HANA Cloud (Business Partner + Sales Order OData) and a local PostgreSQL store. Includes docker-compose, a kind-based k8s deploy, and Tosca-style flow scripts suitable for recording end-to-end Keploy testcases against PostgreSQL + outbound SAP HTTPS.
7. [Java Dynamic Deduplication](https://github.com/keploy/samples-java/tree/main/java-dedup) - A Spring Boot sample used by CI to validate Enterprise Java dynamic dedup in native, Docker, and restricted Docker replay runs. CI uses checked-in fixtures and does not record this sample in the pipeline.

## Community Support ❤️

Expand Down
9 changes: 9 additions & 0 deletions java-dedup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/target/
/keploy/reports/
/dedupData.yaml
/duplicates.yaml
/docker-compose-tmp.yaml
/jacoco.exec
/.java-sdk-installed
/java-sdk/
/*.log
13 changes: 13 additions & 0 deletions java-dedup/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ARG JAVA_VERSION=8
FROM eclipse-temurin:${JAVA_VERSION}-jre

WORKDIR /app

RUN groupadd --gid 10001 appuser \
&& useradd --uid 10001 --gid 10001 --home-dir /home/appuser --create-home --shell /usr/sbin/nologin appuser

COPY --chown=10001:10001 target/java-dedup-0.0.1-SNAPSHOT.jar /app/app.jar
COPY --chown=10001:10001 target/jacocoagent.jar /app/jacocoagent.jar
EXPOSE 8080
USER 10001:10001
ENTRYPOINT ["java", "-javaagent:/app/jacocoagent.jar=destfile=/tmp/jacoco.exec", "-jar", "/app/app.jar"]
17 changes: 17 additions & 0 deletions java-dedup/Dockerfile.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
ARG JAVA_VERSION=8
FROM eclipse-temurin:${JAVA_VERSION}-jre

WORKDIR /app

RUN groupadd --gid 10001 appuser \
&& useradd --uid 10001 --gid 10001 --home-dir /home/appuser --create-home --shell /usr/sbin/nologin appuser

COPY --chown=10001:10001 target/classes /app/classes
COPY --chown=10001:10001 target/dependency /app/libs
COPY --chown=10001:10001 target/jacocoagent.jar /app/jacocoagent.jar

ENV KEPLOY_JAVA_CLASS_DIRS=/app/classes

EXPOSE 8080
USER 10001:10001
ENTRYPOINT ["java", "-javaagent:/app/jacocoagent.jar=destfile=/tmp/jacoco.exec", "-cp", "/app/classes:/app/libs/*", "io.keploy.samples.javadedup.JavaDedupApplication"]
10 changes: 10 additions & 0 deletions java-dedup/Dockerfile.distroless
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM gcr.io/distroless/java17-debian12:nonroot

WORKDIR /app

COPY --chown=10001:10001 target/java-dedup-0.0.1-SNAPSHOT.jar /app/app.jar
COPY --chown=10001:10001 target/jacocoagent.jar /app/jacocoagent.jar

EXPOSE 8080
USER 10001:10001
ENTRYPOINT ["java", "-javaagent:/app/jacocoagent.jar=destfile=/tmp/jacoco.exec", "-jar", "/app/app.jar"]
68 changes: 68 additions & 0 deletions java-dedup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Java Dynamic Deduplication Sample

A Spring Boot application used by Keploy CI to validate Java dynamic deduplication. It mirrors the Go dedup sample by exposing a broad set of endpoints and committing 1000 replay fixtures across four testsets.

CI does not record this sample. The `keploy/` directory is checked in so the pipeline only builds the app and runs replay with `--dedup`.

The Java SDK reads JaCoCo coverage in-process via `org.jacoco.agent.rt.RT.getAgent().getExecutionData(...)`, so attaching the JaCoCo Java agent is enough — no TCP server, no port choice, no `--pass-through-ports`.

## Setup

```bash
(cd ../../java-sdk && mvn -B -DskipTests -Dgpg.skip=true clean install -pl keploy-sdk -am)
mvn -B -DskipTests clean package
```

This installs the sibling SDK snapshot locally, builds the sample, produces `target/java-dedup-0.0.1-SNAPSHOT.jar`, and copies `target/jacocoagent.jar` next to it.

## Run dedup natively

```bash
keploy test \
-c "java -javaagent:target/jacocoagent.jar -jar target/java-dedup-0.0.1-SNAPSHOT.jar" \
--dedup --language java --delay 1 \
--health-url "http://127.0.0.1:8080/healthz" \
--health-poll-timeout 30s \
--disableMockUpload --disableReportUpload

keploy dedup --path .
```

## Run dedup with Docker

```bash
docker compose build
keploy test \
-c "docker compose up" \
--container-name "dedup-java" \
--host "127.0.0.1" \
--dedup --language java --delay 1 \
--health-url "http://127.0.0.1:8080/healthz" \
--health-poll-timeout 30s \
--disableMockUpload --disableReportUpload

keploy dedup --path .
```

During `keploy test`, Enterprise rewrites the Compose file and injects its own shared `/tmp` volume for the dedup control/data sockets. The base sample Compose file does not need a host `/tmp` bind mount.
Re-run `docker compose build` whenever the jar, JaCoCo agent, or Dockerfile changes so replay uses the current image.

## Run dedup with direct Docker

```bash
docker compose build
keploy test \
-c "docker run --rm --name dedup-java -p 8080:8080 java-dedup:local" \
--container-name "dedup-java" \
--host "127.0.0.1" \
--dedup --language java --delay 1 \
--health-url "http://127.0.0.1:8080/healthz" \
--health-poll-timeout 30s \
--disableMockUpload --disableReportUpload

keploy dedup --path .
```

During direct `docker run`, Enterprise injects the same shared `/tmp` volume into the app container. Do not pass your own `/tmp` mount in the app command.

The CI pipeline also validates additional production-style Docker layouts for the same app, including direct Docker run, exploded classpath, restricted runtime, and distroless packaging.
4 changes: 4 additions & 0 deletions java-dedup/docker-compose.classpath.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
java-dedup:
build:
dockerfile: Dockerfile.classpath
4 changes: 4 additions & 0 deletions java-dedup/docker-compose.distroless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
java-dedup:
build:
dockerfile: Dockerfile.distroless
7 changes: 7 additions & 0 deletions java-dedup/docker-compose.restricted.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
java-dedup:
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
13 changes: 13 additions & 0 deletions java-dedup/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
java-dedup:
image: ${JAVA_DEDUP_IMAGE:-java-dedup:local}
build:
context: .
dockerfile: Dockerfile
args:
JAVA_VERSION: ${JAVA_VERSION:-8}
environment:
KEPLOY_JAVA_DEDUP_DIAGNOSTICS: ${KEPLOY_JAVA_DEDUP_DIAGNOSTICS:-}
container_name: dedup-java
ports:
- "${JAVA_DEDUP_HOST_PORT:-8080}:8080"
104 changes: 104 additions & 0 deletions java-dedup/keploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Generated by Keploy (3-dev)
path: ""
appId: 0
appName: ""
command: ""
templatize:
testSets: []
port: 0
proxyPort: 16789
incomingProxyPort: 36789
dnsPort: 26789
debug: false
disableANSI: false
disableTele: false
generateGithubActions: false
containerName: ""
networkName: ""
buildDelay: 30
test:
selectedTests: {}
ignoredTests: {}
globalNoise:
global: {"body": {"current_time":[]}}
test-sets: {}
replaceWith:
global: {}
test-sets: {}
delay: 5
host: "localhost"
port: 0
grpcPort: 0
ssePort: 0
protocol:
http:
port: 0
sse:
port: 0
grpc:
port: 0
apiTimeout: 5
skipCoverage: false
coverageReportPath: ""
ignoreOrdering: true
mongoPassword: "default@123"
language: ""
removeUnusedMocks: false
fallBackOnMiss: false
jacocoAgentPath: ""
basePath: ""
mocking: true
disableLineCoverage: false
disableMockUpload: false
useLocalMock: false
updateTemplate: false
mustPass: false
maxFailAttempts: 5
maxFlakyChecks: 1
protoFile: ""
protoDir: ""
protoInclude: []
compareAll: false
updateTestMapping: false
disableAutoHeaderNoise: false
# strictMockWindow enforces cross-test bleed prevention. Per-test
# (LifetimePerTest) mocks whose request timestamp falls outside the
# outer test window are dropped rather than promoted across tests.
#
# Default TRUE now that every stateful-protocol recorder classifies
# mocks finely enough (per-connection data mocks, session vs per-test
# distinction for connection-alive commands) that legitimate cross-
# test sharing is encoded as session/connection lifetime rather than
# implicit out-of-window reuse. If an older recording relies on the
# legacy lax behaviour, opt out with strictMockWindow: false here or
# export KEPLOY_STRICT_MOCK_WINDOW=0 — the env var wins.
strictMockWindow: true
dedup: false
freezeTime: false
fuzzyMatch: false
record:
recordTimer: 0s
filters: []
sync: false
memoryLimit: 0
configPath: ""
bypassRules: []
disableMapping: true
contract:
driven: "consumer"
mappings:
servicesMapping: {}
self: "s1"
services: []
tests: []
path: ""
download: false
generate: false
inCi: false
cmdType: "native"
enableTesting: false
inDocker: false
keployContainer: "keploy-v3"
keployNetwork: "keploy-network"

# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file.
2 changes: 2 additions & 0 deletions java-dedup/keploy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

/reports/
39 changes: 39 additions & 0 deletions java-dedup/keploy/test-set-0/tests/test-10.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Keploy (3-dev)
version: api.keploy.io/v1beta1
kind: Http
name: test-10
spec:
metadata: {}
req:
method: GET
proto_major: 1
proto_minor: 1
url: http://127.0.0.1:8080/items
header:
Accept: '*/*'
Host: 127.0.0.1:8080
User-Agent: curl/8.19.0
body: ""
timestamp: 2026-04-24T12:48:15.246997938+05:30
resp:
status_code: 200
header:
Content-Type: application/json
Date: Fri, 24 Apr 2026 07:18:15 GMT
body: '[{"id":"item1","name":"Laptop","price":1200.00},{"id":"item2","name":"Mouse","price":25.50},{"id":"item3","name":"Keyboard","price":75.00}]'
status_message: OK
proto_major: 0
proto_minor: 0
timestamp: 2026-04-24T12:48:15.25057105+05:30
objects: []
assertions:
noise:
header.Date: []
created: 1777015095
app_port: 8080
curl: |
curl --request GET \
--url http://127.0.0.1:8080/items \
--header 'Host: 127.0.0.1:8080' \
--header 'User-Agent: curl/8.19.0' \
--header 'Accept: */*' \
39 changes: 39 additions & 0 deletions java-dedup/keploy/test-set-0/tests/test-100.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Keploy (3-dev)
version: api.keploy.io/v1beta1
kind: Http
name: test-100
spec:
metadata: {}
req:
method: GET
proto_major: 1
proto_minor: 1
url: http://127.0.0.1:8080/healthz
header:
Accept: '*/*'
Host: 127.0.0.1:8080
User-Agent: curl/8.19.0
body: ""
timestamp: 2026-04-24T12:48:16.301192216+05:30
resp:
status_code: 200
header:
Content-Type: application/json
Date: Fri, 24 Apr 2026 07:18:16 GMT
body: '{"healthy":true}'
status_message: OK
proto_major: 0
proto_minor: 0
timestamp: 2026-04-24T12:48:16.303821826+05:30
objects: []
assertions:
noise:
header.Date: []
created: 1777015096
app_port: 8080
curl: |
curl --request GET \
--url http://127.0.0.1:8080/healthz \
--header 'User-Agent: curl/8.19.0' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
39 changes: 39 additions & 0 deletions java-dedup/keploy/test-set-0/tests/test-101.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Keploy (3-dev)
version: api.keploy.io/v1beta1
kind: Http
name: test-101
spec:
metadata: {}
req:
method: GET
proto_major: 1
proto_minor: 1
url: http://127.0.0.1:8080/status
header:
Accept: '*/*'
Host: 127.0.0.1:8080
User-Agent: curl/8.19.0
body: ""
timestamp: 2026-04-24T12:48:16.312328831+05:30
resp:
status_code: 200
header:
Content-Type: application/json
Date: Fri, 24 Apr 2026 07:18:16 GMT
body: '{"service":"user-api","status":"active"}'
status_message: OK
proto_major: 0
proto_minor: 0
timestamp: 2026-04-24T12:48:16.314716531+05:30
objects: []
assertions:
noise:
header.Date: []
created: 1777015096
app_port: 8080
curl: |
curl --request GET \
--url http://127.0.0.1:8080/status \
--header 'User-Agent: curl/8.19.0' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
Loading
Loading