Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

clearcore-test-suite

Production-grade, multi-layer test framework for ClearCore — a Java 21 / Spring Boot 3.2 payment authorization and settlement engine.


What this tests

ClearCore exposes a payment API (POST /api/v1/transactions/authorize, capture, reverse) backed by PostgreSQL, Redis (rate limiting + velocity), and Kafka (event stream). This framework validates correctness, fraud rule enforcement, latency SLAs, and double-spend prevention under concurrent load.


Architecture

clearcore-test-suite/
├── python/                          # Primary suite
│   ├── tests/
│   │   ├── conftest.py              # Per-suite dedicated cards, client, fixtures
│   │   ├── test_authorization.py    # Happy path, all decline codes, idempotency
│   │   ├── test_lifecycle.py        # authorize → capture → reverse full flow
│   │   ├── test_contracts.py        # JSON schema validation on every endpoint
│   │   ├── test_fraud_rules.py      # Velocity, amount threshold, merchant rules
│   │   └── test_rate_limits.py      # 429 triggering, Retry-After, burst behavior
│   ├── schemas/
│   │   ├── authorize_response.json
│   │   ├── transaction.json
│   │   └── error_response.json
│   ├── pytest.ini
│   └── requirements.txt
│
├── java/                            # Concurrency + latency layer
│   └── src/test/
│       ├── java/com/clearcore/tests/
│       │   ├── TestConfig.java          # Shared base config, payload factories
│       │   ├── ConcurrencyTest.java     # 50-thread double-spend, concurrent capture/refund
│       │   └── LatencySlaTest.java      # p50/p95/p99 over 1000 requests
│       └── groovy/com/clearcore/tests/
│           └── AuthorizationSpec.groovy # Spock data-driven decline-code coverage
│
├── docker-compose.yml               # ClearCore + Postgres + Redis + Kafka
└── README.md

Test suites

Suite Layer Tests Status What it covers
Authorization Python 20 ✅ Passing Happy path, decline codes 51/54/82/14/61/62, idempotency deduplication
Lifecycle Python 15 ✅ Passing Full flow: authorize → capture → reverse. Partial capture, double-reverse rejection, state machine violations
Contracts Python 10 ✅ Passing JSON schema validation on every endpoint. Field types, required fields, enum values
Fraud rules Python 12 ✅ Passing Velocity limit (N txns/min), amount threshold (fraud score), merchant category rules
Rate limits Python 3 ✅ Passing Burst → 429, sequential rate limit verification
Concurrency Java 4 ⚠️ Environmental 50-thread overdraw via CountDownLatch, concurrent capture/refund deduplication
Latency SLA Java 5 ⚠️ Environmental p95 < 200ms, p99 < 500ms, p50 < 100ms over 1000 sequential requests
Authorization (Spock) Groovy 14 ⚠️ JDK compat Data-driven decline codes via @Unroll, idempotency, contract assertions

Stack

Python layer

  • pytest 8.3, requests, jsonschema, allure-pytest, pytest-xdist, pytest-timeout

Java layer

  • REST Assured 5.5, JUnit 5, AssertJ, Awaitility, Allure JUnit5

Groovy / Spock

  • Spock Framework 2.4-M4, GMavenPlus 3.0

Infrastructure

  • Docker Compose (ClearCore + PostgreSQL 16 + Redis 7 + Kafka)

Running locally

Prerequisites

  • Docker + Docker Compose
  • Python 3.12+
  • Java 21, Maven 3.9+
  • ClearCore cloned at ../ClearCore

Start the stack

# From this repo root
docker compose up -d --build

# Wait for ClearCore to be healthy (~30s)
curl -s http://localhost:8080/actuator/health

Seed test data

After each container restart, run:

# Fix VARCHAR column (ClearCore schema uses VARCHAR(10) — needs widening for test data)
docker exec clearcore-test-suite-postgres-1 psql -U clearcore -d clearcore \
  -c "ALTER TABLE transactions ALTER COLUMN response_code TYPE VARCHAR(50); \
      ALTER TABLE transactions ALTER COLUMN status TYPE VARCHAR(50);"

# Flush Redis velocity counters between runs
docker exec clearcore-test-suite-redis-1 redis-cli FLUSHALL

# Seed per-suite test cards
docker cp sql/insert_test_cards.sql clearcore-test-suite-postgres-1:/tmp/
docker exec clearcore-test-suite-postgres-1 psql -U clearcore -d clearcore -f /tmp/insert_test_cards.sql

Python suite (primary)

cd python
pip install -r requirements.txt

# Run all tests
pytest -v

# Run a single suite
pytest tests/test_authorization.py -v
pytest tests/test_fraud_rules.py -v

# With Allure report
pytest --alluredir=allure-results
allure serve allure-results

Java suite

# Requires JDK 21 (Groovy 4.0 incompatible with JDK 25+)
# Run via Docker to avoid local JDK version conflicts:
docker run --rm --network clearcore-test-suite_default \
  -v "$(pwd)/java:/app" -w /app eclipse-temurin:21-jdk-alpine \
  sh -c "apk add --no-cache maven && mvn test -Dgmavenplus.skip=true"

Key tests explained

ConcurrencyTest::noDoubleSpendUnder50Threads

The most important test in the framework — validates ClearCore's optimistic locking prevents double-spend under concurrent load.

CountDownLatch startGun = new CountDownLatch(1);
for (int i = 0; i < 50; i++) {
    pool.submit(() -> {
        startGun.await();  // synchronized start
        var response = jsonRequest().body(payload)
            .post("/api/v1/transactions/authorize");
        if ("00".equals(response.jsonPath().getString("data.responseCode")))
            approvals.incrementAndGet();
    });
}
startGun.countDown();  // release all 50 simultaneously
assertThat(approvals.get()).isEqualTo(1);  // exactly one wins

Without @Version optimistic locking on ClearCore's Transaction entity, multiple threads win the balance check simultaneously → double-spend. With it, only one thread wins the CAS on the DB row; all others get an optimistic lock exception → decline code 51.

LatencySlaTest::authP95Under200ms

// 1000 sequential requests after 50-request warmup
Arrays.sort(times);
long p95 = times[(int)(SAMPLE_SIZE * 0.95)];
assertThat(p95).isLessThan(P95_SLA_MS);  // 200ms

Percentile from a sorted array: index N * 0.95 is p95. Hard CI gate — catches slow queries, missing indexes, GC pressure before production.

TestFraudRules::test_velocity_limit_triggers_decline

# Fire 50 rapid transactions on a dedicated card
for _ in range(50):
    client.authorize(make_payload(card_id=CARD_VEL, amount=1000))

# Next request must decline — velocity limit exceeded
res = client.authorize(make_payload(card_id=CARD_VEL, amount=1000))
assert res.status_code == 422
assert res.json()["data"]["responseCode"] in ("62", "51")

Each suite uses a dedicated card UUID to avoid cross-suite velocity interference. The velocity counter lives in Redis; FLUSHALL between runs resets it.

TestContracts — JSON schema validation

def test_authorize_response_schema(self, client, valid_card, authorize_schema):
    res = client.authorize(valid_card)
    assert res.status_code == 201
    validate(instance=res.json()["data"], schema=authorize_schema)

Schema files in schemas/ define required fields, types, and enum values. Fails immediately on any structural regression in ClearCore's response format.


Known limitations / environmental notes

Issue Cause Status
AuthorizationSpec.groovyConnection refused Spock tests hardcode localhost; inside Docker container, localhostclearcore Fix requires editing .groovy file with JDK 21
Groovy compilation fails locally JDK 25 installed locally; Groovy 4.0 supports max JDK 21 (class file major version 69 error) Run via eclipse-temurin:21-jdk-alpine Docker container
response_code VARCHAR(10) ClearCore schema column too narrow for some response codes Run the ALTER TABLE command after each container restart (see setup above)
Velocity limit in concurrency tests 50 concurrent requests on one card exceed the 50/min velocity limit Known — requires a card exempted from velocity checks

Design decisions

Per-suite dedicated cards — each test suite has its own card UUID seeded in the DB. This prevents velocity counters in Redis from bleeding across suites. The conftest.py constants (CARD_AUTH, CARD_LIFECYCLE, etc.) map to UUIDs in sql/insert_test_cards.sql.

data envelope unwrapping — ClearCore wraps all responses in {"success": true, "data": {...}}. The unwrap() helper in conftest.py normalizes this so test assertions work directly on the business object.

Sequential rate limit test — the rate limit suite fires requests sequentially (not via pytest-xdist) to avoid thread-scheduling noise confusing the burst count.

VELOCITY_LIMIT=50 in ClearCore — the default application.yml velocity limit was raised from 5 to 50 to allow the fraud rule tests to exercise the threshold without hitting it in setup. This change lives in the ClearCore repo.

About

Multi-layer payment API test framework — pytest + REST Assured + Spock against a Spring Boot clearing engine. Fraud rules, concurrency, latency SLAs.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages