Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Each config's `help:` line shows a concrete example. `-c key:"'value'"` injects

**Bridge bundles** each add a small set of tasks (`src/Task/`) plus a client/adapter concept wired in `config/services.yaml`:
- `doctrine-process-bundle` — DB & entity tasks: `Database/DatabaseReaderTask`, `DatabaseUpdaterTask`, and `EntityManager/*` (`DoctrineReaderTask`, `DoctrineWriterTask`, `DoctrineBatchWriterTask`, cleaner/detacher/refresher/remover/clearer).
- `rest-process-bundle` — `Task/RequestTask` driven by a tagged `cleverage.rest.client` (see `apicarto_ign` client in `services.yaml`).
- `rest-process-bundle` — `Task/RequestTask` driven by a tagged `cleverage.rest.client` (see `apicarto_ign` client in `services.yaml`). To mock an API, prefer the `wiremock` service and its `wiremock` / `wiremock_admin` clients (stubs in `.docker/wiremock/`, see `docs/wiremock.md` and the `demo.wiremock.*` processes).
- `soap-process-bundle` — `Task/RequestTask` driven by a tagged `cleverage.soap.client` (see `oorsprong_countryinfo` client).
- `flysystem-process-bundle` — `FileFetchTask`, `ListContentTask`, `RemoveFileTask` over Flysystem storages (config in `config/packages/flysystem.yaml`); the demo also uses SFTP.
- `archive-process-bundle` — `ZipTask` / `UnzipTask`.
Expand Down
12 changes: 12 additions & 0 deletions .docker/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,17 @@ services:
SFTP_MOCK_ROOT: /
SFTP_MOCK_IDLE: "4"

# WireMock (https://wiremock.org/): mocks the HTTP APIs called by the demo.wiremock.* processes.
# Stubs are loaded at startup from ./wiremock/mappings (bodies in ./wiremock/__files), response
# templating is enabled for every stub. Admin UI / API: http://localhost:${WIREMOCK_PORT:-8089}/__admin
wiremock:
image: wiremock/wiremock:3.13.2
tty: true
volumes:
- ./wiremock:/home/wiremock
command: [ "--global-response-templating", "--verbose" ]
ports:
- "${WIREMOCK_PORT:-8089}:8080"

volumes:
process_bundle_demo_data:
17 changes: 17 additions & 0 deletions .docker/wiremock/__files/books.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"id": 1,
"title": "It",
"author": "Stephen King"
},
{
"id": 2,
"title": "Salem",
"author": "Stephen King"
},
{
"id": 3,
"title": "Fahrenheit 451",
"author": "Ray Bradbury"
}
]
25 changes: 25 additions & 0 deletions .docker/wiremock/mappings/authors-authorized.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "Header matching: the authors are only returned with the expected bearer token",
"priority": 1,
"request": {
"method": "GET",
"urlPath": "/api/authors",
"headers": {
"Authorization": {
"equalTo": "Bearer demo-token"
}
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": [
{
"id": 1,
"name": "Stephen King"
}
]
}
}
17 changes: 17 additions & 0 deletions .docker/wiremock/mappings/authors-unauthorized.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Header matching fallback: any other request on the authors is unauthorized",
"priority": 10,
"request": {
"method": "GET",
"urlPath": "/api/authors"
},
"response": {
"status": 401,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"error": "Unauthorized"
}
}
}
17 changes: 17 additions & 0 deletions .docker/wiremock/mappings/books-create-invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "POST without title: validation error (lower priority than the matching stub)",
"priority": 10,
"request": {
"method": "POST",
"urlPath": "/api/books"
},
"response": {
"status": 422,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"error": "The title is required"
}
}
}
24 changes: 24 additions & 0 deletions .docker/wiremock/mappings/books-create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "POST with a JSON body: matching on the body, the created book echoes the sent title",
"request": {
"method": "POST",
"urlPath": "/api/books",
"headers": {
"Content-Type": {
"contains": "application/json"
}
},
"bodyPatterns": [
{
"matchesJsonPath": "$.title"
}
]
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"body": "{\"id\": {{randomInt lower=100 upper=999}}, \"title\": \"{{jsonPath request.body '$.title'}}\"}"
}
}
18 changes: 18 additions & 0 deletions .docker/wiremock/mappings/books-get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Path matching and response templating: a book built from the requested id",
"request": {
"method": "GET",
"urlPathPattern": "/api/books/[0-9]+"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"id": "{{request.pathSegments.[2]}}",
"title": "Book {{request.pathSegments.[2]}}",
"requestedAt": "{{now}}"
}
}
}
14 changes: 14 additions & 0 deletions .docker/wiremock/mappings/books-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Static JSON response: the list of books, read from a body file",
"request": {
"method": "GET",
"urlPath": "/api/books"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"bodyFileName": "books.json"
}
}
17 changes: 17 additions & 0 deletions .docker/wiremock/mappings/books-not-found.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Error status code: book 404 does not exist (higher priority than the generic book stub)",
"priority": 1,
"request": {
"method": "GET",
"urlPath": "/api/books/404"
},
"response": {
"status": 404,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"error": "Book not found"
}
}
}
17 changes: 17 additions & 0 deletions .docker/wiremock/mappings/books-server-error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Error status code: book 500 triggers a server error",
"priority": 1,
"request": {
"method": "GET",
"urlPath": "/api/books/500"
},
"response": {
"status": 500,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"error": "Internal error"
}
}
}
10 changes: 10 additions & 0 deletions .docker/wiremock/mappings/fault-connection-reset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Fault injection: the connection is reset, the client gets a transport error",
"request": {
"method": "GET",
"urlPath": "/api/unstable"
},
"response": {
"fault": "CONNECTION_RESET_BY_PEER"
}
}
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ SFTP_SHORT_HOST=sftp-short
# Mock SFTP server that injects a stray packet after idle (see .docker/sftp-mock/), to
# reproduce the verbatim issue #24 error. Serves /data as its root (SFTP root is empty).
SFTP_MOCK_HOST=sftp-mock
# WireMock service (see .docker/wiremock/): mocked HTTP APIs of the demo.wiremock.* processes.
WIREMOCK_URL=http://wiremock:8080
###< docker/atmoz-sftp ###

###> symfony/routing ###
Expand Down
40 changes: 40 additions & 0 deletions config/packages/process/demo.wiremock.authentication.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
clever_age_process:
configurations:
demo.wiremock.authentication:
description: >
WireMock: header matching (authors-authorized.json, authors-unauthorized.json): the authors are returned
with the expected bearer token, a request without token is unauthorized (401, error outputs)
help: >
Ex: bin/console cleverage:process:execute demo.wiremock.authentication
tasks:
requests:
service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask'
options:
output:
- headers: { }
- headers: { Authorization: 'Bearer demo-token' }
outputs: [ request ]

request:
service: '@CleverAge\RestProcessBundle\Task\RequestTask'
error_strategy: skip
options:
client: wiremock
url: '/authors'
method: 'GET'
outputs: [ decode ]
error_outputs: [ error ]

decode:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
json_decode: ~
outputs: [ debug ]

debug:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'

error:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
description: Receives the response body of the requests in error (error_outputs)
42 changes: 42 additions & 0 deletions config/packages/process/demo.wiremock.error_codes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
clever_age_process:
configurations:
demo.wiremock.error_codes:
description: >
WireMock: error status codes (books-not-found.json, books-server-error.json): with error_strategy skip,
the books 404 (404) and 500 (500) are sent to the error outputs, the other ones are output
help: >
Ex: bin/console cleverage:process:execute demo.wiremock.error_codes
tasks:
ids:
service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask'
options:
output:
- url_parameters: { id: '1' }
- url_parameters: { id: '404' }
- url_parameters: { id: '500' }
- url_parameters: { id: '2' }
outputs: [ request ]

request:
service: '@CleverAge\RestProcessBundle\Task\RequestTask'
error_strategy: skip
options:
client: wiremock
url: '/books/{id}'
method: 'GET'
outputs: [ decode ]
error_outputs: [ error ]

decode:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
json_decode: ~
outputs: [ debug ]

debug:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'

error:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
description: Receives the response body of the requests in error (error_outputs)
19 changes: 19 additions & 0 deletions config/packages/process/demo.wiremock.fault.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
clever_age_process:
configurations:
demo.wiremock.fault:
description: >
WireMock: fault injection (fault-connection-reset.json): the connection is reset by the mocked server,
the request fails with a transport error and the process fails
help: >
Ex: bin/console cleverage:process:execute demo.wiremock.fault -v
tasks:
request:
service: '@CleverAge\RestProcessBundle\Task\RequestTask'
options:
client: wiremock
url: '/unstable'
method: 'GET'
outputs: [ debug ]

debug:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
30 changes: 30 additions & 0 deletions config/packages/process/demo.wiremock.get_json.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
clever_age_process:
configurations:
demo.wiremock.get_json:
description: >
WireMock: GET a static JSON response, read from a body file (.docker/wiremock/mappings/books-list.json,
__files/books.json), decode it and iterate over the books
help: >
Ex: bin/console cleverage:process:execute demo.wiremock.get_json
tasks:
request:
service: '@CleverAge\RestProcessBundle\Task\RequestTask'
options:
client: wiremock
url: '/books'
method: 'GET'
outputs: [ decode ]

decode:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
json_decode: ~
outputs: [ iterate ]

iterate:
service: '@CleverAge\ProcessBundle\Task\InputIteratorTask'
outputs: [ debug ]

debug:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
34 changes: 34 additions & 0 deletions config/packages/process/demo.wiremock.path_templating.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
clever_age_process:
configurations:
demo.wiremock.path_templating:
description: >
WireMock: request matching on a path pattern and response templating (books-get.json): the mocked book
is built from the requested id, given by the input
help: >
Ex: bin/console cleverage:process:execute demo.wiremock.path_templating
tasks:
ids:
service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask'
options:
output:
- url_parameters: { id: '1' }
- url_parameters: { id: '42' }
outputs: [ request ]

request:
service: '@CleverAge\RestProcessBundle\Task\RequestTask'
options:
client: wiremock
url: '/books/{id}'
method: 'GET'
outputs: [ decode ]

decode:
service: '@CleverAge\ProcessBundle\Task\TransformerTask'
options:
transformers:
json_decode: ~
outputs: [ debug ]

debug:
service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
Loading
Loading