Skip to content

Refactor request/response plumbing (RequestAgent/ResponseProxy/ResponseDeserializer) and update LoginServiceImpl and tests#2

Open
koder95 wants to merge 5 commits intomainfrom
codex/split-requesthandler-into-three-interfaces
Open

Refactor request/response plumbing (RequestAgent/ResponseProxy/ResponseDeserializer) and update LoginServiceImpl and tests#2
koder95 wants to merge 5 commits intomainfrom
codex/split-requesthandler-into-three-interfaces

Conversation

@koder95
Copy link
Copy Markdown
Contributor

@koder95 koder95 commented Mar 25, 2026

Motivation

  • Replace the old RequestHandler abstraction with a richer request/response model to support proxying and deserialization of HTTP responses.
  • Make LoginServiceImpl consume the new abstractions so that response bodies and errors can be handled uniformly.
  • Improve and extend unit tests for LoginServiceImpl to cover edge cases and correct authorization behavior.

Description

  • Added new interfaces RequestAgent, ResponseProxy, and ResponseDeserializer and a domain Response model to represent proxied responses and deserialization behavior.
  • Removed the RequestHandler interface and updated LoginServiceImpl to use RequestAgent to send requests and ResponseDeserializer to convert response bodies into Credentials objects.
  • Updated the README comment describing application.util to reflect the new interfaces.
  • Rewrote LoginServiceImplTest to use parameterized tests and helper factories, added success and failure scenarios, and added assertions that AuthorizationHolder is updated and cleared correctly.

Testing

  • Ran the unit test suite including LoginServiceImplTest via mvn test; all tests passed successfully.

Codex Task

Summary by CodeRabbit

  • Refactor

    • Request/response flow reworked: sending, response wrapping, and deserialization are separated to improve error handling and clarity in the login flow.
  • Tests

    • Login tests consolidated and strengthened with parameterized invalid-input cases, success-response helpers, and new deserialization-path tests; logout behavior still validated.
  • Documentation

    • Architecture docs updated to include the expanded util-layer interface types.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d4c5497-c400-475f-9045-1dbef1729e58

📥 Commits

Reviewing files that changed from the base of the PR and between 49a4092 and 67f1cee.

📒 Files selected for processing (4)
  • src/main/java/pl/vtt/wpi/core/application/exception/DeserializationException.java
  • src/main/java/pl/vtt/wpi/core/application/service/LoginService.java
  • src/main/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImpl.java
  • src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/pl/vtt/wpi/core/application/exception/DeserializationException.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java
  • src/main/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImpl.java

📝 Walkthrough

Walkthrough

Replaces the RequestHandler<T,R> contract with RequestAgent<T>, ResponseProxy, and ResponseDeserializer; adds a Response domain class; updates LoginService/LoginServiceImpl to use send → getResponse → deserialize flow; updates tests and README (docs only).

Changes

Cohort / File(s) Summary
Util Layer Interfaces
src/main/java/pl/vtt/wpi/core/application/util/RequestAgent.java, src/main/java/pl/vtt/wpi/core/application/util/ResponseProxy.java, src/main/java/pl/vtt/wpi/core/application/util/ResponseDeserializer.java, src/main/java/pl/vtt/wpi/core/application/util/RequestHandler.java
Removed RequestHandler<T,R>; added RequestAgent<T> (send(Request<T>) -> ResponseProxy), ResponseProxy (exposes Response), and ResponseDeserializer (deserialize(String, Class<R>)).
Domain Model
src/main/java/pl/vtt/wpi/core/domain/model/Response.java
Added Response class encapsulating body and exception; body() returns payload or throws stored exception.
Service API / Impl
src/main/java/pl/vtt/wpi/core/application/service/LoginService.java, src/main/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImpl.java
LoginService.login(...) now declares DeserializationException; LoginServiceImpl constructors updated to accept RequestAgent<Void> and ResponseDeserializer; request handling changed to send → getResponse → deserialize; deserialization failures wrapped as DeserializationException.
Exceptions
src/main/java/pl/vtt/wpi/core/application/exception/DeserializationException.java
Added new checked DeserializationException(String, Throwable).
Tests
src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java
Refactored and extended tests: success path adjusted for response-proxy flow; added deserialization-path tests; consolidated invalid input parameterized tests; replaced handler-failure test with agent-exception propagation test.
Docs
README.md
Architecture tree updated to list RequestAgent, ResponseProxy, and ResponseDeserializer under pl.vtt.wpi.core/application/service/util.

Sequence Diagram(s)

sequenceDiagram
    participant Client as LoginServiceImpl
    participant Agent as RequestAgent
    participant Proxy as ResponseProxy
    participant Deserializer as ResponseDeserializer
    participant Domain as Response

    Client->>Agent: send(Request<Void>)
    Agent-->>Client: ResponseProxy
    Client->>Proxy: getResponse()
    Proxy-->>Client: Response
    Client->>Domain: body()
    Domain-->>Client: String body / throws Exception
    Client->>Deserializer: deserialize(body, Credentials.class)
    Deserializer-->>Client: Credentials
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped in to tweak the flow,
Agent sends, the proxy shows,
Deserializer peels the string,
Credentials dance, tests sing,
A rabbit cheers — change on the go!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 summarizes the main change: refactoring request/response plumbing by introducing three new interfaces (RequestAgent, ResponseProxy, ResponseDeserializer) and updating LoginServiceImpl and tests accordingly.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/split-requesthandler-into-three-interfaces

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

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`:
- Around line 89-93: The lambda used for ResponseDeserializer in
instanceWithSuccessResponse cannot implement its generic method; replace the
lambda with an anonymous class that implements ResponseDeserializer and
overrides the deserialize(...) method to return deserializedCredentials. Keep
the RequestAgent lambda (RequestAgent<Void> requestAgent = _ ->
successResponseProxy()) as-is and construct the LoginServiceImpl with the new
anonymous ResponseDeserializer implementation so LoginServiceImpl(...) receives
a proper ResponseDeserializer instance.
- Around line 52-56: The lambda passed to ResponseDeserializer.deserialize
cannot implement its generic method; replace the lambda with an anonymous class
that explicitly implements ResponseDeserializer and overrides the generic method
signature (e.g. in LoginServiceImplTest replace the lambda block with new
ResponseDeserializer() { `@Override` public <R> R deserialize(Response response,
Class<R> type) { return null; } } ), keeping the thrown
IncorrectUsernameOrPasswordException path unchanged.
- Around line 99-101: The test helper method encoded(String value) uses
value.getBytes() which relies on the platform default charset; update encoded to
call value.getBytes(StandardCharsets.UTF_8) and add the
java.nio.charset.StandardCharsets import so the test matches the production
LoginServiceImpl charset handling and is portable across environments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7fe2f7a-4df1-40a7-b435-66b64097b205

📥 Commits

Reviewing files that changed from the base of the PR and between dc50110 and 4a6d1b1.

📒 Files selected for processing (8)
  • README.md
  • src/main/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImpl.java
  • src/main/java/pl/vtt/wpi/core/application/util/RequestAgent.java
  • src/main/java/pl/vtt/wpi/core/application/util/RequestHandler.java
  • src/main/java/pl/vtt/wpi/core/application/util/ResponseDeserializer.java
  • src/main/java/pl/vtt/wpi/core/application/util/ResponseProxy.java
  • src/main/java/pl/vtt/wpi/core/domain/model/Response.java
  • src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/pl/vtt/wpi/core/application/util/RequestHandler.java

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`:
- Around line 46-64: The test name implies verifying the "agent returns invalid
credentials" path but the provided RequestAgent lambda throws an
IncorrectUsernameOrPasswordException, so update the test to match the name by
making the agent return a successful Response and have the anonymous
ResponseDeserializer.deserialize return null (so
LoginServiceImpl.login(USERNAME, PASSWORD) sees null credentials), or
alternatively keep the agent-throwing lambda and rename the test method to
shouldThrowWhenAgentThrowsException; locate the setup in the LoginServiceImpl
constructor call (the RequestAgent lambda and the anonymous ResponseDeserializer
implementation) and change the agent to return a success Response or rename the
test accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 68d15184-3ea9-4538-81f4-eccf3c793274

📥 Commits

Reviewing files that changed from the base of the PR and between 4a6d1b1 and fa5cc75.

📒 Files selected for processing (1)
  • src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (1)
src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java (1)

65-66: Add cleanup assertion for the exception path.

After Line 65, assert that AuthorizationHolder is cleared. This directly verifies the failure cleanup behavior of login().

✅ Suggested assertion addition
 assertThrows(IncorrectUsernameOrPasswordException.class, () -> instance.login(USERNAME, PASSWORD));
+assertNull(AuthorizationHolder.get());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`
around lines 65 - 66, After the
assertThrows(IncorrectUsernameOrPasswordException.class, () ->
instance.login(USERNAME, PASSWORD)); add an assertion that AuthorizationHolder
is cleared to verify failure cleanup; specifically, in LoginServiceImplTest
assert after the exception that AuthorizationHolder (the static holder used by
the service) contains no credentials / is null/empty as your project convention
dictates, ensuring login() on error does not leave state behind.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`:
- Around line 86-94: The test should seed AuthorizationHolder before calling
LoginServiceImpl.logout() so it actually verifies state transition; update the
shouldClearAuthorizationOnLogout test to set a non-null value into
AuthorizationHolder (e.g., AuthorizationHolder.set(...) or equivalent) prior to
calling instance.logout(), then call instance.logout() and
assertNull(AuthorizationHolder.get()) to ensure logout() clears the holder;
reference LoginServiceImpl.logout() and AuthorizationHolder.get()/set() when
making the change.

---

Nitpick comments:
In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`:
- Around line 65-66: After the
assertThrows(IncorrectUsernameOrPasswordException.class, () ->
instance.login(USERNAME, PASSWORD)); add an assertion that AuthorizationHolder
is cleared to verify failure cleanup; specifically, in LoginServiceImplTest
assert after the exception that AuthorizationHolder (the static holder used by
the service) contains no credentials / is null/empty as your project convention
dictates, ensuring login() on error does not leave state behind.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7c66ced8-ea6e-460f-8511-76398a7c5aa1

📥 Commits

Reviewing files that changed from the base of the PR and between fa5cc75 and 49a4092.

📒 Files selected for processing (1)
  • src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java

Comment on lines 86 to 94
@Test
@DisplayName("Tests a logout")
void logout_ok() {
LoginServiceImpl instance = new LoginServiceImpl(null, null, null);
@DisplayName("Should clear authorization on logout")
void shouldClearAuthorizationOnLogout() {
LoginServiceImpl instance = new LoginServiceImpl(null, null, null, null);

instance.logout();

assertNull(AuthorizationHolder.get());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

logout() test is vacuous right now.

Because @BeforeEach already clears the holder, Line 93 passes even if logout() does nothing. Seed AuthorizationHolder first, then verify it transitions to null after logout.

✅ Proposed test fix
 `@Test`
 `@DisplayName`("Should clear authorization on logout")
 void shouldClearAuthorizationOnLogout() {
     LoginServiceImpl instance = new LoginServiceImpl(null, null, null, null);
+    AuthorizationHolder.authorize("Basic", "dummy");
+    assertNotNull(AuthorizationHolder.get());

     instance.logout();

     assertNull(AuthorizationHolder.get());
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/pl/vtt/wpi/core/application/service/impl/LoginServiceImplTest.java`
around lines 86 - 94, The test should seed AuthorizationHolder before calling
LoginServiceImpl.logout() so it actually verifies state transition; update the
shouldClearAuthorizationOnLogout test to set a non-null value into
AuthorizationHolder (e.g., AuthorizationHolder.set(...) or equivalent) prior to
calling instance.logout(), then call instance.logout() and
assertNull(AuthorizationHolder.get()) to ensure logout() clears the holder;
reference LoginServiceImpl.logout() and AuthorizationHolder.get()/set() when
making the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant