Skip to content

Added functional test suite with optimizations for bundle#15

Merged
stixx merged 2 commits intomainfrom
functional-tests
Mar 1, 2026
Merged

Added functional test suite with optimizations for bundle#15
stixx merged 2 commits intomainfrom
functional-tests

Conversation

@stixx
Copy link
Owner

@stixx stixx commented Mar 1, 2026

Summary by CodeRabbit

  • New Features

    • Added Symfony 8 support and property-access capability.
  • Bug Fixes

    • Improved robustness in response resolution and route/query attribute handling.
    • Adjusted exception handling order to ensure API exceptions are processed earlier.
  • Tests

    • Added comprehensive functional test suite (CRUD, validation, OpenAPI schema) and test scripts for unit/functional runs.

@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

Walkthrough

This PR expands Symfony compatibility to ^7.3 || ^8.0, replaces autowire/autoconfigure defaults with explicit DI wiring across configs, adjusts several service constructor arguments and priorities, adds defensive checks, and introduces a full functional test suite with fixtures, kernel, and OpenAPI spec.

Changes

Cohort / File(s) Summary
Dependency Management
composer.json
Support Symfony `^7.3
Controller & Value Resolver Wiring
config/controller.php, src/Controller/ArgumentResolver/CommandValueResolver.php
Made CommandController public and wired explicit dependencies (MessageBusInterface, ValidatorInterface, StatusResolverInterface, ResponderInterface, validation flags). CommandValueResolver now receives serializer service; removed is_string($key) guard in route/query extraction (possible runtime risk).
Responder & Response Config
config/response.php, src/Response/ResponseStatusResolver.php
Replaced autowire/autoconfigure defaults with explicit private/default service wiring; individually register and tag responders (JsonResponder, JsonSerializedResponder with serializer, NullableResponder). Added defensive iterable check in ResponseStatusResolver::first2xxFromOperation.
Routing & OpenAPI Describers
config/routing.php, config/openapi.php, src/DependencyInjection/StixxOpenApiCommandExtension.php
Removed autowire/autoconfigure defaults; CommandRouteClassLoader receives env, controller classes param and loader tag. CommandRouteDescriber gets an $attributesCache arg. Extension now sets stixx_openapi_command.controller_classes param and loads routing/subscribers configs.
Subscribers & Validators DI
config/subscribers.php, config/validators.php
Switched defaults to explicit private(), added new constructor dependencies (NelmioAreaRoutesChecker, RequestValidatorChain, exception transformer) for subscribers, removed global instanceof tagging and instead tag RequestValidator explicitly.
Serializer config
config/serializer.php
Replaced literal %kernel.debug% arg with param('kernel.debug') and imported param() helper; removed autowire/autoconfigure defaults.
Extension & Test Config
phpunit.xml, src/DependencyInjection/...
Added SYMFONY_DEPRECATIONS_HELPER env for tests and replaced coverage block with source include. Extension changes to pass ContainerBuilder to registerCommonConfiguration and load additional configs.
Functional Test Infrastructure
tests/Functional/AbstractKernelTestCase.php, tests/Functional/App/Kernel.php, tests/Functional/Resources/config/*
Added test kernel and base test case with teardown and helpers, plus default/custom/scenario DI configs for functional tests.
Test Fixtures (Commands, Handlers, Models)
tests/Functional/App/Command/*, tests/Functional/App/Handler/*, tests/Functional/App/Model/*
Added Create/Update/Delete command classes annotated for OpenAPI and validation, their handlers implementing __invoke, BookRequest and BookResource models with OpenAPI schemas and validation.
Functional Tests & Specs
tests/Functional/*, tests/Functional/Resources/specifications/openapi.json
Added BundleInitializationTest, ScenarioTest, OpenApiSchemaTest and OpenAPI JSON spec; tests cover bundle wiring, CRUD flows, validation errors, and schema output.
sequenceDiagram
    actor Client
    participant Kernel
    participant Controller as CommandController
    participant Validator
    participant CommandBus as MessageBus
    participant Handler
    participant Responder
    participant Serializer

    Client->>Kernel: HTTP request (e.g. POST /api/books)
    Kernel->>Controller: route -> invoke CommandController
    Controller->>Serializer: deserialize request -> command object
    Controller->>Validator: validate(command)
    Validator-->>Controller: validation result
    Controller->>CommandBus: dispatch(command)
    CommandBus->>Handler: deliver command to handler (__invoke)
    Handler-->>CommandBus: result (BookResource)
    Controller->>Responder: create Response from result
    Responder->>Serializer: serialize payload (if needed)
    Responder-->>Controller: Response
    Controller-->>Client: HTTP response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
Hops through configs, wires explicit and neat,
Tests and handlers bounce on eager feet,
Symfony seven and eight both take the stage,
OpenAPI blooms across the page,
A rabbit cheers — the suite is now complete.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary changes: comprehensive functional test suite additions (AbstractKernelTestCase, multiple test classes, test handlers, models, and configuration files) and dependency injection optimizations across config files (removing autowire/autoconfigure, adding explicit wiring).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch functional-tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Controller/ArgumentResolver/CommandValueResolver.php (1)

113-121: ⚠️ Potential issue | 🟠 Major

Potential TypeError when array key is an integer.

The filter callback accesses $key[0] without verifying that $key is a string. While $request->attributes->all() typically returns string keys, PHP arrays can have integer keys. If a non-string key exists, $key[0] will throw a TypeError in PHP 8.x.

🛡️ Proposed fix to add string type guard
         $routeData = array_filter(
             $attributes,
             static function ($value, $key): bool {
-                return $key !== ''
+                return is_string($key)
+                    && $key !== ''
                     && $key[0] !== '_'
                     && (is_scalar($value) || $value === null);
             },
             ARRAY_FILTER_USE_BOTH
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Controller/ArgumentResolver/CommandValueResolver.php` around lines 113 -
121, The callback used to build $routeData in CommandValueResolver.php assumes
$key is a string and uses $key[0], which can throw a TypeError for integer keys;
update the closure (the static function used with ARRAY_FILTER_USE_BOTH that
filters $attributes) to first check is_string($key) and that $key !== '' before
accessing $key[0] (i.e., require is_string($key) && $key !== '' && $key[0] !==
'_' && (is_scalar($value) || $value === null)).
🧹 Nitpick comments (4)
tests/Functional/App/Kernel.php (2)

40-52: PHPDoc is redundant with parameter type.

The @param RoutingConfigurator $routes annotation duplicates the type information that's already available from the type check on line 47. Consider removing the docblock or relying solely on the instanceof check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/App/Kernel.php` around lines 40 - 52, The PHPDoc above
configureRoutes duplicates the type information and is redundant; remove the
docblock comment containing "@param RoutingConfigurator $routes" and rely on the
existing method signature and the instanceof check inside configureRoutes (refer
to the configureRoutes method and the RoutingConfigurator type check, and the
route imports for CreateBookCommand, UpdateBookCommand, DeleteBookCommand) so
the file no longer contains the redundant annotation.

23-23: Consider making the Kernel class final.

Per coding guidelines, classes not intended for extension (especially tests) should be final. If this test kernel isn't extended elsewhere, adding the final keyword would align with the project standards.

-class Kernel extends TestKernel
+final class Kernel extends TestKernel

As per coding guidelines: "Classes not intended for extension (especially tests) must be final."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/App/Kernel.php` at line 23, The Kernel class should be
marked final since it's not intended for extension; update the class declaration
for Kernel (which currently extends TestKernel) to add the final keyword (i.e.,
declare final class Kernel extends TestKernel) so it follows the project's
guideline that test-only classes are final.
tests/Functional/Resources/specifications/openapi.json (1)

1-6: Consider adding meaningful info metadata.

The empty title and placeholder version "0.0.0" work for tests but could be more descriptive for documentation purposes.

The Checkov warnings about missing global security definitions (CKV_OPENAPI_4, CKV_OPENAPI_5) can be safely ignored for this test fixture since authentication is not part of the functional test scope.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/Resources/specifications/openapi.json` around lines 1 - 6,
The OpenAPI document's info block has an empty "title" and a placeholder
"version"; update the "info" object so "title" contains a meaningful name (e.g.
describing this test API) and "version" reflects a proper semantic version (not
"0.0.0"), keeping the rest of the spec unchanged; reference the "openapi"
top-level field and the "info" object's "title" and "version" keys when making
the change (you can ignore Checkov warnings CKV_OPENAPI_4/5 for this test
fixture).
tests/Functional/ScenarioTest.php (1)

109-170: Consolidate duplicated validation-error scenarios with #[DataProvider].

These two tests are identical except for the HTTP method and URI; parameterizing them will keep assertions in one place and reduce drift. Per the coding guidelines, use #[DataProvider] for multiple similar scenarios.

Note: The DataProvider attribute will need to be imported from PHPUnit\Framework\Attributes.

♻️ Proposed refactor
+use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\Attributes\WithoutErrorHandler;
 
-    #[WithoutErrorHandler]
-    public function testCreateBookValidationError(): void
-    {
-        // Arrange
-        $kernel = $this->createKernelWithConfig(static function (Kernel $kernel): void {
-            $kernel->addTestConfig(__DIR__.'/Resources/config/scenario.php');
-        });
-
-        $payload = [
-            'title' => '', // NotBlank
-        ];
-
-        $request = Request::create(
-            uri: '/api/books',
-            method: 'POST',
-            content: json_encode($payload, JSON_THROW_ON_ERROR)
-        );
-        $request->headers->set('Content-Type', 'application/json');
-
-        // Act
-        $response = $kernel->handle($request);
-
-        // Assert
-        self::assertSame(400, $response->getStatusCode());
-        self::assertSame('application/problem+json', $response->headers->get('Content-Type'));
-        $data = json_decode($response->getContent() ?: 'null', true, 512, JSON_THROW_ON_ERROR);
-        self::assertIsArray($data);
-        self::assertSame(400, $data['status'] ?? null);
-        self::assertSame('Validation failed', $data['detail'] ?? null);
-        self::assertArrayHasKey('violations', $data);
-    }
-
-    #[WithoutErrorHandler]
-    public function testUpdateBookValidationError(): void
+    #[WithoutErrorHandler]
+    #[DataProvider('validationErrorProvider')]
+    public function testValidationError(string $uri, string $method): void
     {
         // Arrange
         $kernel = $this->createKernelWithConfig(static function (Kernel $kernel): void {
             $kernel->addTestConfig(__DIR__.'/Resources/config/scenario.php');
         });
@@
-            uri: '/api/books/1',
-            method: 'PUT',
+            uri: $uri,
+            method: $method,
             content: json_encode($payload, JSON_THROW_ON_ERROR)
         );
@@
         self::assertSame('Validation failed', $data['detail'] ?? null);
         self::assertArrayHasKey('violations', $data);
     }
+
+    public static function validationErrorProvider(): array
+    {
+        return [
+            'create' => ['/api/books', 'POST'],
+            'update' => ['/api/books/1', 'PUT'],
+        ];
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/ScenarioTest.php` around lines 109 - 170, The two tests
testCreateBookValidationError and testUpdateBookValidationError are duplicated;
replace them with a single parameterized test (e.g., testValidationError) that
accepts method and URI from a DataProvider (e.g., validationErrorProvider) and
add the PHPUnit\Framework\Attributes\DataProvider import; keep the
#[WithoutErrorHandler] attribute on the test, move the shared Arrange/Act/Assert
logic into the single test that builds the Request using the provided method and
URI, and implement validationErrorProvider to yield the two cases
(['POST','/api/books'] and ['PUT','/api/books/1']) so all assertions remain in
one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/Functional/BundleInitializationTest.php`:
- Around line 89-95: Add an explicit "Arrange" comment above the setup block in
testBundleWithCustomConfiguration: mark the initial kernel/config creation (the
call to $this->createKernelWithConfig(...) and the Kernel->addTestConfig(...)
invocation) with a comment "// Arrange" so the test follows the AAA convention
before the existing Act/Assert comments.

In `@tests/Functional/Resources/specifications/openapi.json`:
- Around line 27-51: The PUT operation with operationId
"put_command_updatebookcommand" (PUT /api/books/{id}) is missing a requestBody
definition; add a required requestBody object describing the update payload and
reference the appropriate schema (e.g., "#/components/schemas/BookResource" or a
dedicated UpdateBook schema) under content "application/json", and ensure
requestBody.required is true so the API expects the payload for the update.
- Around line 8-24: The POST operation for "/api/books" (operationId:
post_command_createbookcommand) is missing a requestBody; add a requestBody
object with "required": true and "content": { "application/json": { "schema": {
"$ref": "#/components/schemas/BookCreateRequest" } } } (or reference an
appropriate existing schema such as BookResource if creation and response share
the same shape) so the OpenAPI spec documents the payload expected by create
book and satisfies validation in tests.

---

Outside diff comments:
In `@src/Controller/ArgumentResolver/CommandValueResolver.php`:
- Around line 113-121: The callback used to build $routeData in
CommandValueResolver.php assumes $key is a string and uses $key[0], which can
throw a TypeError for integer keys; update the closure (the static function used
with ARRAY_FILTER_USE_BOTH that filters $attributes) to first check
is_string($key) and that $key !== '' before accessing $key[0] (i.e., require
is_string($key) && $key !== '' && $key[0] !== '_' && (is_scalar($value) ||
$value === null)).

---

Nitpick comments:
In `@tests/Functional/App/Kernel.php`:
- Around line 40-52: The PHPDoc above configureRoutes duplicates the type
information and is redundant; remove the docblock comment containing "@param
RoutingConfigurator $routes" and rely on the existing method signature and the
instanceof check inside configureRoutes (refer to the configureRoutes method and
the RoutingConfigurator type check, and the route imports for CreateBookCommand,
UpdateBookCommand, DeleteBookCommand) so the file no longer contains the
redundant annotation.
- Line 23: The Kernel class should be marked final since it's not intended for
extension; update the class declaration for Kernel (which currently extends
TestKernel) to add the final keyword (i.e., declare final class Kernel extends
TestKernel) so it follows the project's guideline that test-only classes are
final.

In `@tests/Functional/Resources/specifications/openapi.json`:
- Around line 1-6: The OpenAPI document's info block has an empty "title" and a
placeholder "version"; update the "info" object so "title" contains a meaningful
name (e.g. describing this test API) and "version" reflects a proper semantic
version (not "0.0.0"), keeping the rest of the spec unchanged; reference the
"openapi" top-level field and the "info" object's "title" and "version" keys
when making the change (you can ignore Checkov warnings CKV_OPENAPI_4/5 for this
test fixture).

In `@tests/Functional/ScenarioTest.php`:
- Around line 109-170: The two tests testCreateBookValidationError and
testUpdateBookValidationError are duplicated; replace them with a single
parameterized test (e.g., testValidationError) that accepts method and URI from
a DataProvider (e.g., validationErrorProvider) and add the
PHPUnit\Framework\Attributes\DataProvider import; keep the
#[WithoutErrorHandler] attribute on the test, move the shared Arrange/Act/Assert
logic into the single test that builds the Request using the provided method and
URI, and implement validationErrorProvider to yield the two cases
(['POST','/api/books'] and ['PUT','/api/books/1']) so all assertions remain in
one place.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 492ae2c and e6502b8.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • composer.json
  • config/controller.php
  • config/openapi.php
  • config/response.php
  • config/routing.php
  • config/serializer.php
  • config/subscribers.php
  • config/validators.php
  • phpunit.xml
  • src/Controller/ArgumentResolver/CommandValueResolver.php
  • src/DependencyInjection/StixxOpenApiCommandExtension.php
  • src/EventSubscriber/ApiExceptionSubscriber.php
  • src/Response/ResponseStatusResolver.php
  • tests/Functional/.gitignore
  • tests/Functional/AbstractKernelTestCase.php
  • tests/Functional/App/Command/CreateBookCommand.php
  • tests/Functional/App/Command/DeleteBookCommand.php
  • tests/Functional/App/Command/UpdateBookCommand.php
  • tests/Functional/App/Handler/CreateBookHandler.php
  • tests/Functional/App/Handler/DeleteBookHandler.php
  • tests/Functional/App/Handler/UpdateBookHandler.php
  • tests/Functional/App/Kernel.php
  • tests/Functional/App/Model/BookResource.php
  • tests/Functional/BundleInitializationTest.php
  • tests/Functional/OpenApiSchemaTest.php
  • tests/Functional/Resources/config/custom.php
  • tests/Functional/Resources/config/default.php
  • tests/Functional/Resources/config/scenario.php
  • tests/Functional/Resources/specifications/openapi.json
  • tests/Functional/ScenarioTest.php

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
tests/Functional/BundleInitializationTest.php (1)

34-86: Consider adding explicit // Act comment for AAA consistency.

The test follows the Arrange-Assert pattern (which is valid for state verification tests), but the coding guidelines require explicit AAA comments. The "act" here is implicitly the kernel boot. For consistency with testBundleWithCustomConfiguration, consider adding a brief // Act section.

📝 Suggested adjustment
     public function testInitBundle(): void
     {
         // Arrange
         $this->bootKernel();
+
+        // Act
         $container = self::getContainer();

         // Assert

As per coding guidelines, "Tests must follow the AAA (Arrange, Act, Assert) pattern with explicit comments."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/BundleInitializationTest.php` around lines 34 - 86, The
testInitBundle method currently mixes Arrange and the implicit action (kernel
boot); add an explicit "// Act" comment and move or place the call to
bootKernel() (the action) under that comment so the test follows Arrange
(setup), Act (bootKernel()), Assert (the container assertions) explicitly—mirror
the pattern used in testBundleWithCustomConfiguration and keep the method name
testInitBundle and calls like $this->bootKernel() and self::getContainer()
unchanged.
tests/Functional/Resources/specifications/openapi.json (2)

1-144: Note: Missing global security definitions (static analysis).

Checkov flags missing global security field (CKV_OPENAPI_4, CKV_OPENAPI_5). For a functional test fixture, omitting security is likely intentional to simplify testing. If this spec is also used to validate security-aware behavior, consider adding a placeholder security definition.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/Resources/specifications/openapi.json` around lines 1 - 144,
The OpenAPI spec lacks a global security declaration which triggers
CKV_OPENAPI_4/5; add a top-level "security" field (e.g., an empty array if you
want no enforced schemes for tests, or a placeholder like [{"ApiKeyAuth": []}])
and, if using a placeholder, add a matching entry under
"components.securitySchemes" (e.g., "ApiKeyAuth" with type and name) so tools
recognize global security; update the root object to include "security" and,
when adding a scheme, modify "components" -> "securitySchemes" to include the
referenced scheme name.

3-6: Consider populating API info metadata.

The title is empty and version is "0.0.0". While acceptable for a test fixture, adding meaningful values would improve test documentation and could help catch regressions if schema generation is being validated.

📝 Suggested improvement
     "info": {
-        "title": "",
-        "version": "0.0.0"
+        "title": "Book API",
+        "version": "1.0.0"
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Functional/Resources/specifications/openapi.json` around lines 3 - 6,
The OpenAPI fixture has empty/placeholder metadata: the "info" object's "title"
is empty and "version" is "0.0.0"; update the "info.title" to a meaningful
string (e.g., a short API name) and set "info.version" to a realistic semantic
version (e.g., "1.0.0") to improve test documentation and schema validation;
ensure you update the "info" object where "title" and "version" are defined so
tests using the openapi.json pick up the new metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/Functional/BundleInitializationTest.php`:
- Around line 34-86: The testInitBundle method currently mixes Arrange and the
implicit action (kernel boot); add an explicit "// Act" comment and move or
place the call to bootKernel() (the action) under that comment so the test
follows Arrange (setup), Act (bootKernel()), Assert (the container assertions)
explicitly—mirror the pattern used in testBundleWithCustomConfiguration and keep
the method name testInitBundle and calls like $this->bootKernel() and
self::getContainer() unchanged.

In `@tests/Functional/Resources/specifications/openapi.json`:
- Around line 1-144: The OpenAPI spec lacks a global security declaration which
triggers CKV_OPENAPI_4/5; add a top-level "security" field (e.g., an empty array
if you want no enforced schemes for tests, or a placeholder like [{"ApiKeyAuth":
[]}]) and, if using a placeholder, add a matching entry under
"components.securitySchemes" (e.g., "ApiKeyAuth" with type and name) so tools
recognize global security; update the root object to include "security" and,
when adding a scheme, modify "components" -> "securitySchemes" to include the
referenced scheme name.
- Around line 3-6: The OpenAPI fixture has empty/placeholder metadata: the
"info" object's "title" is empty and "version" is "0.0.0"; update the
"info.title" to a meaningful string (e.g., a short API name) and set
"info.version" to a realistic semantic version (e.g., "1.0.0") to improve test
documentation and schema validation; ensure you update the "info" object where
"title" and "version" are defined so tests using the openapi.json pick up the
new metadata.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6502b8 and 7628247.

📒 Files selected for processing (5)
  • tests/Functional/App/Command/CreateBookCommand.php
  • tests/Functional/App/Command/UpdateBookCommand.php
  • tests/Functional/App/Model/BookRequest.php
  • tests/Functional/BundleInitializationTest.php
  • tests/Functional/Resources/specifications/openapi.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Functional/App/Command/UpdateBookCommand.php

@stixx stixx merged commit 20ce59a into main Mar 1, 2026
3 checks passed
@stixx stixx deleted the functional-tests branch March 1, 2026 16:12
@stixx stixx added the enhancement New feature or request label Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant