diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f89d566..543d8de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,35 @@ jobs: - name: Test and package run: ./mvnw --batch-mode --no-transfer-progress verify + - name: Validate API proof asset + run: | + test -s docs/library-api-error-proof.jpg + python3 - <<'PY' + from pathlib import Path + + proof = Path("docs/library-api-error-proof.jpg").read_bytes() + assert proof[:2] == b"\xff\xd8", "proof asset is not a JPEG" + + offset = 2 + dimensions = None + start_of_frame = {0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF} + while offset < len(proof): + assert proof[offset] == 0xFF, "invalid JPEG marker" + marker = proof[offset + 1] + offset += 2 + if marker in {0xD8, 0xD9}: + continue + length = int.from_bytes(proof[offset:offset + 2], "big") + if marker in start_of_frame: + height = int.from_bytes(proof[offset + 3:offset + 5], "big") + width = int.from_bytes(proof[offset + 5:offset + 7], "big") + dimensions = (width, height) + break + offset += length + + assert dimensions == (1280, 720), "proof asset must be 1280x720" + PY + - name: Validate Compose contract run: docker compose --env-file .env.example config --quiet diff --git a/README.md b/README.md index af59cd0..30699a1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ Kütüphaneler tarafından kullanılabilecek kayıt yönetimlerini, kitap ödün - Java 17'ye sabitlenmiş container build/runtime aşamaları ve PostgreSQL servis sağlık kontrolü. - Kaynakta parola tutmayan Compose yapılandırması ve Java 17/PostgreSQL CI doğrulaması. +## Canlı API Kanıtı + +![Swagger UI'da var olmayan kategori isteğinin global hata yönetimiyle 404 dönmesi](docs/library-api-error-proof.jpg) + +*Gerçek Java 17/PostgreSQL 16 container çalıştırmasından alınmıştır. Swagger UI, `DataLoader` tarafından üretilen sentetik yerel veriler üzerinde `GET /api/v1/categories/999999` isteğini çalıştırır; fork'ta eklenen global hata yönetimi de tam 404 yanıtını üretir. Bu, barındırılan bir demo değil, yerel ve tekrar üretilebilir bir çalışma kanıtıdır.* + ## Kullanılan Teknolojiler Java diff --git a/docs/library-api-error-proof.jpg b/docs/library-api-error-proof.jpg new file mode 100644 index 0000000..ea1e6b1 Binary files /dev/null and b/docs/library-api-error-proof.jpg differ diff --git a/src/test/java/com/alisimsek/LibraryManagementProject/CategoryErrorResponseIntegrationTests.java b/src/test/java/com/alisimsek/LibraryManagementProject/CategoryErrorResponseIntegrationTests.java new file mode 100644 index 0000000..f92fe36 --- /dev/null +++ b/src/test/java/com/alisimsek/LibraryManagementProject/CategoryErrorResponseIntegrationTests.java @@ -0,0 +1,26 @@ +package com.alisimsek.LibraryManagementProject; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +class CategoryErrorResponseIntegrationTests { + + @Autowired + private MockMvc mockMvc; + + @Test + void missingCategoryUsesTheForksGlobalErrorResponse() throws Exception { + mockMvc.perform(get("/api/v1/categories/{id}", 999999L)) + .andExpect(status().isNotFound()) + .andExpect(content().string("Category with ID 999999 not found in the system.")); + } +}