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
5 changes: 5 additions & 0 deletions java-dedup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/target/
/keploy/reports/
/dedupData.yaml
/duplicates.yaml
/*.log
16 changes: 16 additions & 0 deletions java-dedup/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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
COPY --chown=10001:10001 target/classes /app/target/classes

ENV KEPLOY_JAVA_CLASS_DIRS=/app/target/classes
EXPOSE 8080
USER 10001:10001
ENTRYPOINT ["java", "-javaagent:/app/jacocoagent.jar=address=127.0.0.1,port=36320,destfile=/tmp/jacoco-keploy.exec,output=tcpserver", "-jar", "/app/app.jar"]
48 changes: 48 additions & 0 deletions java-dedup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Java Dynamic Deduplication Sample

This sample is a Spring Boot application used by Keploy CI to validate Java dynamic deduplication in native and Docker runs. 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`.

Build the application after installing the Java SDK locally:

```bash
mvn -B -DskipTests package
```

Run it natively with JaCoCo TCP server mode:

```bash
java -javaagent:target/jacocoagent.jar=address=127.0.0.1,port=36320,destfile=target/jacoco-keploy.exec,output=tcpserver \
-jar target/java-dedup-0.0.1-SNAPSHOT.jar
```

To regenerate the committed fixtures locally, record high-volume traffic against the running app:

```bash
./run_random_1000.sh
```

When replaying with dynamic deduplication, pass the JaCoCo port through Keploy so the SDK can talk to the local JaCoCo TCP server:

```bash
keploy test \
-c "java -javaagent:target/jacocoagent.jar=address=127.0.0.1,port=36320,destfile=target/jacoco-keploy.exec,output=tcpserver -jar target/java-dedup-0.0.1-SNAPSHOT.jar" \
--dedup --pass-through-ports 36320
```

Run it with Docker Compose after the Maven package step has created `target/java-dedup-0.0.1-SNAPSHOT.jar`:

```bash
docker compose build
docker compose up
```

The Compose file supports `JAVA_DEDUP_IMAGE`, `JAVA_DEDUP_CONTAINER_NAME`, and `JAVA_DEDUP_HOST_PORT` so CI can isolate repeated replay runs without recording new tests.

The Compose app bind-mounts host `/tmp` into the container so Keploy and the Java SDK use the same Unix socket paths for `/tmp/coverage_control.sock` and `/tmp/coverage_data.sock`. The image runs as a non-root user. For a more restricted container run with a read-only root filesystem, dropped capabilities, `no-new-privileges`, and writable host `/tmp` bind-mounted for Keploy's Unix sockets:

```bash
docker compose -f docker-compose.yml -f docker-compose.restricted.yml build
docker compose -f docker-compose.yml -f docker-compose.restricted.yml up
```
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
17 changes: 17 additions & 0 deletions java-dedup/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
java-dedup:
image: ${JAVA_DEDUP_IMAGE:-java-dedup:local}
build:
context: .
dockerfile: Dockerfile
args:
JAVA_VERSION: ${JAVA_VERSION:-8}
container_name: ${JAVA_DEDUP_CONTAINER_NAME:-dedup-java}
ports:
- "${JAVA_DEDUP_HOST_PORT:-8080}:8080"
environment:
KEPLOY_JAVA_CLASS_DIRS: /app/target/classes
volumes:
- type: bind
source: /tmp
target: /tmp
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' \
39 changes: 39 additions & 0 deletions java-dedup/keploy/test-set-0/tests/test-102.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-102
spec:
metadata: {}
req:
method: GET
proto_major: 1
proto_minor: 1
url: http://127.0.0.1:8080/anybody
header:
Accept: '*/*'
Host: 127.0.0.1:8080
User-Agent: curl/8.19.0
body: ""
timestamp: 2026-04-24T12:48:16.322102113+05:30
resp:
status_code: 200
header:
Content-Type: application/json
Date: Fri, 24 Apr 2026 07:18:16 GMT
body: '{"message":"Anybody"}'
status_message: OK
proto_major: 0
proto_minor: 0
timestamp: 2026-04-24T12:48:16.324511112+05:30
objects: []
assertions:
noise:
header.Date: []
created: 1777015096
app_port: 8080
curl: |
curl --request GET \
--url http://127.0.0.1:8080/anybody \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
--header 'User-Agent: curl/8.19.0' \
Loading
Loading