Skip to content

Conversation

@addee1
Copy link
Collaborator

@addee1 addee1 commented Nov 16, 2025

This PR adds eight unit tests for the HelloModel class.
The tests cover the following behaviors:

  • Verifies that sendMessage() calls the connection with the correct message
  • Ensures sending a message triggers the correct POST request to the server
  • Confirms that sendFile() forwards the file to the connection
  • Ensures sending a file triggers the correct PUT request to the server
  • Validates that incoming messages are added to the model's message list
  • Verifies that the constructor registers a receive handler on the connection
  • Ensures the messageToSend property updates correctly
  • Checks that getGreeting() returns the expected greeting text

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling for message reception with automatic fallback mechanism to ensure messages are processed even when platform-specific operations fail.
  • Tests

    • Enhanced test coverage for file uploads and message handling.
    • Added tests verifying proper message reception and handler registration.

@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Walkthrough

The changes introduce error handling for message reception with a fallback mechanism, convert file upload from asynchronous to synchronous HTTP communication, update test endpoints, add comprehensive test coverage for file operations and message handling, and enhance test spies with file tracking and message simulation capabilities.

Changes

Cohort / File(s) Summary
Main implementation
src/main/java/com/example/HelloModel.java, src/main/java/com/example/NtfyConnectionImpl.java
HelloModel: Added try-catch block around Platform.runLater() to catch IllegalStateException with fallback to direct message append. NtfyConnectionImpl: Replaced http.sendAsync() with synchronous http.send() in sendFile method, converting non-blocking to blocking behavior.
Test spy utilities
src/test/java/com/example/NtfyConnectionSpy.java
Added sendFile(File) method to capture sent files. Added simulateIncoming(NtfyMessageDto) method and handler field to spy on and simulate incoming messages.
Test code
src/test/java/com/example/HelloModelTest.java
Updated POST endpoint from /mytopic to /adam. Added six new test cases: sendFileCallConnectionSendFile, sendFileToFakeServer, receiveMessageShouldAddToModelViewHandler, constructorShouldRegisterHandler, messagePropertyShouldUpdate, greetingShouldBeCorrect. Added File and IOException imports.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Client
    participant NtfyConnectionImpl
    participant HTTP
    
    rect rgba(200, 150, 100, 0.2)
    Note over NtfyConnectionImpl,HTTP: Before: Async File Upload
    Client->>NtfyConnectionImpl: sendFile(file)
    NtfyConnectionImpl->>HTTP: http.sendAsync(request)
    HTTP-->>NtfyConnectionImpl: CompletableFuture returned
    NtfyConnectionImpl-->>Client: true (returns immediately)
    HTTP->>HTTP: Upload continues asynchronously
    end
    
    rect rgba(100, 150, 200, 0.2)
    Note over NtfyConnectionImpl,HTTP: After: Sync File Upload
    Client->>NtfyConnectionImpl: sendFile(file)
    NtfyConnectionImpl->>HTTP: http.send(request)
    HTTP->>HTTP: Upload completes
    HTTP-->>NtfyConnectionImpl: Response received
    NtfyConnectionImpl-->>Client: true (returns after completion)
    end
Loading
sequenceDiagram
    autonumber
    participant Model as HelloModel
    participant JavaFX as Platform
    participant MessageList as messages
    
    rect rgba(150, 200, 100, 0.2)
    Note over Model,MessageList: receiveMessage() with Error Handling
    Model->>Model: receiveMessage(msg) called
    Model->>JavaFX: try { Platform.runLater(...) }
    alt Platform.runLater succeeds
        JavaFX->>MessageList: append message
        MessageList-->>JavaFX: success
    else IllegalStateException caught
        rect rgba(255, 150, 100, 0.2)
        Note over Model,MessageList: Fallback path
        Model->>MessageList: directly append message
        MessageList-->>Model: fallback executed
        end
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • NtfyConnectionImpl.java: Verify the async-to-sync conversion doesn't introduce threading issues or performance regressions; confirm blocking behavior is intentional for the use case.
  • HelloModel.java: Review the try-catch logic for Platform.runLater() to ensure the fallback behavior correctly handles UI thread constraints and doesn't mask other exceptions.
  • HelloModelTest.java: Validate test endpoint changes are consistent across all tests; verify new test cases properly exercise file operations and message handling with the spy utilities.

Poem

🐰 Files now flow with steady care,
No more waiting in the air—
Sync replaces async's dance,
While error handlers catch each glance,
Tests abound with spy's new sight! 🎉

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Adds Unit tests for HelloModel' is directly related to the main focus of the changeset, which adds comprehensive test coverage for the HelloModel class.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tests

Tip

📝 Customizable high-level summaries are now available!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide custom instructions to shape the summary (bullet lists, tables, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example:

"Create a concise high-level summary as a bullet-point list. Then include a Markdown table showing lines added and removed by each contributing author."


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@addee1 addee1 merged commit f175e86 into main Nov 16, 2025
1 of 2 checks passed
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

🧹 Nitpick comments (1)
src/test/java/com/example/HelloModelTest.java (1)

10-10: Remove unused import.

The IOException import is not used in the test code.

-import java.io.IOException;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a206aeb and 00bdec2.

📒 Files selected for processing (4)
  • src/main/java/com/example/HelloModel.java (1 hunks)
  • src/main/java/com/example/NtfyConnectionImpl.java (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (2 hunks)
  • src/test/java/com/example/NtfyConnectionSpy.java (1 hunks)
🔇 Additional comments (4)
src/test/java/com/example/NtfyConnectionSpy.java (1)

3-32: LGTM! Test spy enhancements are well-implemented.

The additions to the spy properly support the new test scenarios:

  • sendFile captures the file reference for verification
  • receive stores the handler enabling message simulation
  • simulateIncoming safely invokes the handler with null-check

The implementation is clean and follows good testing practices.

src/test/java/com/example/HelloModelTest.java (3)

39-39: Endpoint update looks correct.

The change from /mytopic to /adam properly aligns with the updated endpoint in the production code.

Also applies to: 44-44


48-74: File upload tests are well-structured.

Both tests properly verify the file sending behavior:

  • sendFileCallConnectionSendFile validates the model-to-connection interaction via spy
  • sendFileToFakeServer validates the HTTP PUT request using WireMock

The use of temporary files and appropriate assertions make these robust tests.


97-126: Excellent test coverage for model properties and initialization.

The three tests comprehensively verify:

  • Handler registration during construction
  • Property binding and updates for messageToSend
  • Greeting text accuracy

These tests follow good practices with clear naming and appropriate assertions.

Comment on lines +55 to +62
connection.receive(m-> {
try {
Platform.runLater(()->messages.add(m));
} catch (IllegalStateException e) {
messages.add(m);
}

});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fallback bypasses JavaFX thread safety and can cause concurrency issues.

The catch block that directly adds messages to the ObservableList violates JavaFX threading requirements. ObservableList modifications must occur on the JavaFX Application Thread, but this fallback executes on whatever thread invokes the handler (likely a background HTTP thread from NtfyConnectionImpl.receive).

If Platform.runLater throws IllegalStateException (JavaFX toolkit not initialized), the correct approach is to either:

  1. Ensure JavaFX is initialized before creating HelloModel, or
  2. Queue the message for later processing once JavaFX is ready

The current fallback can cause ConcurrentModificationException or corrupt the observable list if UI components are bound to it.

Consider removing the catch block entirely and ensuring JavaFX is properly initialized:

-        connection.receive(m-> {
-            try {
-                Platform.runLater(()->messages.add(m));
-            } catch (IllegalStateException e) {
-                messages.add(m);
-            }
-
-        });
+        connection.receive(m -> Platform.runLater(() -> messages.add(m)));
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around lines 55 to 62, the current
catch block directly adds to the ObservableList off the JavaFX thread which
breaks thread-safety; remove the fallback that calls messages.add(m) inside the
catch and instead either (A) ensure the JavaFX toolkit is initialized before
constructing HelloModel so Platform.runLater never throws, or (B) enqueue
incoming messages into a thread-safe queue when Platform.runLater fails and
drain that queue on the JavaFX Application Thread once initialized (e.g.,
schedule a Platform.runLater to flush queued messages). Ensure all
ObservableList modifications happen only via Platform.runLater on the FX thread.

.build();

http.sendAsync(request, HttpResponse.BodyHandlers.discarding());
http.send(request, HttpResponse.BodyHandlers.discarding());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Blocking HTTP call can freeze the JavaFX UI thread.

Changing from sendAsync to send makes this a synchronous blocking operation. If sendFile is invoked from the JavaFX Application Thread (e.g., triggered by a UI button click), the UI will freeze until the HTTP request completes. File uploads can take seconds or longer, resulting in poor user experience.

The TODO comment at lines 36-38 acknowledges the same issue for the send() method. Consider applying the same fix here—either use sendAsync or execute on a background thread.

Revert to the asynchronous approach:

-            http.send(request, HttpResponse.BodyHandlers.discarding());
+            http.sendAsync(request, HttpResponse.BodyHandlers.discarding());

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +76 to +95
@Test
@DisplayName("Model should receive messages when connection invokes handler")
void receiveMessageShouldAddToModelViewHander(){
var spy = new NtfyConnectionSpy();
var model = new HelloModel(spy);

NtfyMessageDto incoming = new NtfyMessageDto(
"123",
1000,
0,
"message",
"adam",
"this is a test hehehe",
null
);

spy.simulateIncoming(incoming);

assertThat(model.getMessages()).containsExactly(incoming);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Test may not properly verify JavaFX threading behavior.

The test calls simulateIncoming which triggers Platform.runLater in the model, but the test immediately asserts without waiting for the JavaFX thread to execute. This test likely only passes because of the IllegalStateException catch block in HelloModel.receiveMessage that bypasses JavaFX threading (which itself is problematic).

In a proper JavaFX test environment, you should either:

  1. Use WaitForAsyncUtils.waitForFxEvents() from TestFX library to ensure JavaFX thread processes the event, or
  2. Initialize the JavaFX toolkit properly for testing

Consider verifying whether JavaFX is properly initialized in the test environment:

Additionally, search for TestFX or similar JavaFX testing utilities:


🏁 Script executed:

#!/bin/bash
# Check if JavaFX test dependencies or initialization are present in the test setup
rg -n "Platform\.startup|FxToolkit|ApplicationTest|@BeforeAll.*Platform" --type=java

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for JavaFX testing frameworks in dependencies
rg -n "testfx|WaitForAsyncUtils" 

Length of output: 0


I need to gather more information about the actual implementation to verify the review concern. Let me search for the relevant source code:


🏁 Script executed:

#!/bin/bash
# Find HelloModel class and check receiveMessage implementation
rg -n "class HelloModel" --type=java -A 20

Length of output: 3266


🏁 Script executed:

#!/bin/bash
# Find the receiveMessage method in HelloModel
rg -n "receiveMessage" --type=java -B 2 -A 10

Length of output: 2816


🏁 Script executed:

#!/bin/bash
# Find NtfyConnectionSpy and simulateIncoming implementation
rg -n "class NtfyConnectionSpy|simulateIncoming" --type=java -B 2 -A 10

Length of output: 2522


🏁 Script executed:

#!/bin/bash
# Check for pom.xml to see dependencies
fd -n "pom.xml|build.gradle" -x cat {}

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Look for test setup or configuration methods in the test file
rg -n "@BeforeEach|@Before|@BeforeAll|static.*{|setUp" src/test/java/com/example/HelloModelTest.java -B 1 -A 5

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Check imports and class declaration at top of HelloModelTest
head -20 src/test/java/com/example/HelloModelTest.java

Length of output: 688


🏁 Script executed:

#!/bin/bash
# Check HelloModel imports for JavaFX
head -15 src/main/java/com/example/HelloModel.java

Length of output: 360


🏁 Script executed:

#!/bin/bash
# Search for any Platform or javafx usage in the codebase
rg -n "import.*Platform|import.*javafx" --type=java

Length of output: 1882


🏁 Script executed:

#!/bin/bash
# Fix the fd command to list pom.xml and build.gradle files
fd "pom.xml|build.gradle"

Length of output: 7


🏁 Script executed:

#!/bin/bash
# Check pom.xml for dependencies
cat pom.xml

Length of output: 3194


Test relies on IllegalStateException fallback instead of verifying actual JavaFX threading.

The test passes because:

  1. JavaFX toolkit is never initialized (no imports, no @beforeeach setup, no TestFX)
  2. Platform.runLater() in HelloModel.receiveMessage() throws IllegalStateException
  3. The catch block at line 58-60 executes messages.add(m) directly, bypassing threading entirely
  4. Immediate assertion succeeds on this fallback path, not on proper JavaFX thread execution

The production code's try-catch (lines 56-60 in src/main/java/com/example/HelloModel.java) is a code smell—it couples production logic to test environment state.

Fix options:

  1. Add TestFX dependency and use WaitForAsyncUtils.waitForFxEvents() to properly wait for JavaFX thread execution
  2. Initialize JavaFX toolkit with @BeforeEach using Platform.startup() or com.sun.javafx.application.PlatformImpl.startup()
  3. Remove the try-catch workaround once proper JavaFX testing is in place
🤖 Prompt for AI Agents
In src/test/java/com/example/HelloModelTest.java around lines 76-95 the test is
passing due to HelloModel.receiveMessage() falling back to catching
IllegalStateException from Platform.runLater(), so update the test to run
against a real JavaFX toolkit rather than relying on that fallback: initialize
the JavaFX platform before tests (e.g., with a @BeforeEach that calls
Platform.startup(...) or use TestFX/TestApplication setup), then use a proper
sync/wait mechanism (e.g., WaitForAsyncUtils.waitForFxEvents() or an explicit
wait) after spy.simulateIncoming(...) before asserting model.getMessages(); once
tests are updated, remove the try-catch fallback in
src/main/java/com/example/HelloModel.java (lines ~56-60) so production code no
longer depends on IllegalStateException from missing JavaFX initialization.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants