-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ECO-5193] Support message edits and deletes #1059
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe pull request introduces support for message edits and deletes in the Ably library by extending the Changes
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
f8401c3
to
9c14592
Compare
1. Added missing fields for refSerial, refType and Operation 2. Added serialization and deserialization for above fields using msgpack 3. Added serialization and deserialization for above fields using gson
9c14592
to
96ee57d
Compare
1. Added serializer test for fields refSerial, refType and Operation 2. Added deserializer test for fields refSerial, refType and Operation 3. Added msgpack unit test for Message class
96ee57d
to
e8fe70b
Compare
0545e67
to
3616398
Compare
3616398
to
6fb8396
Compare
6fb8396
to
804175a
Compare
804175a
to
958ab56
Compare
958ab56
to
2071531
Compare
228d2ec
to
172b574
Compare
1. Reverted operation metadata to hashmap<string, string> 2. Updated relevant tests for the same
- Updated assertions for test_room_message_is_updated test - Added assertions to check if operation field is populated properly with clientId, description and metadata
1. Implemented integration test for message create, update and delete serially. 2. Implemented integration test to check for allowed ops on deleted message.
bedec54
to
4610d4d
Compare
There was a problem hiding this 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 (7)
lib/src/test/java/io/ably/lib/chat/ChatRoom.java (1)
3-5
: ReuseGson
instance to improve performanceCurrently, a new
Gson
instance is created in each method. Consider defining a singleGson
instance as a class-level field to reuse across methods, which can improve performance by reducing object creation overhead.Apply this diff to refactor the
Gson
instance:+import static io.ably.lib.util.Serialisation.gson; ... -public JsonElement sendMessage(SendMessageParams params) throws AblyException { +public JsonElement sendMessage(SendMessageParams params) throws AblyException { return makeAuthorizedRequest("/chat/v2/rooms/" + roomId + "/messages", "POST", gson.toJsonTree(params)) .orElseThrow(() -> new AblyException("Failed to send message", 500, 50000)); } -public JsonElement updateMessage(String serial, UpdateMessageParams params) throws AblyException { +public JsonElement updateMessage(String serial, UpdateMessageParams params) throws AblyException { return makeAuthorizedRequest("/chat/v2/rooms/" + roomId + "/messages/" + serial, "PUT", gson.toJsonTree(params)) .orElseThrow(() -> new AblyException("Failed to update message", 500, 50000)); } -public JsonElement deleteMessage(String serial, DeleteMessageParams params) throws AblyException { +public JsonElement deleteMessage(String serial, DeleteMessageParams params) throws AblyException { return makeAuthorizedRequest("/chat/v2/rooms/" + roomId + "/messages/" + serial + "/delete", "POST", gson.toJsonTree(params)) .orElseThrow(() -> new AblyException("Failed to delete message", 500, 50000)); }lib/src/test/java/io/ably/lib/types/MessageTest.java (1)
Line range hint
99-232
: Add test cases with null fields to ensure robustnessIn the tests
serialize_message_with_operation
,deserialize_message_with_operation
, andserialize_and_deserialize_with_msgpack
, all fields of theOperation
object are populated. To ensure that serialization and deserialization handle null values correctly, consider adding test cases where optional fields (clientId
,description
,metadata
) are set tonull
. This will help validate that your implementation gracefully handles missing data.Example of modifying the test:
@Test public void serialize_and_deserialize_with_msgpack() throws Exception { // Given Message message = new Message("test-name", "test-data"); message.clientId = "test-client-id"; message.connectionKey = "test-key"; message.refSerial = "test-ref-serial"; message.refType = "test-ref-type"; message.action = MessageAction.MESSAGE_CREATE; message.serial = "01826232498871-001@abcdefghij:001"; Message.Operation operation = new Message.Operation(); operation.clientId = null; // Set to null operation.description = "operation-description"; operation.metadata = null; // Set to null message.operation = operation; // When Encode to MessagePack ... // Then assertEquals(null, unpacked.operation.clientId); assertEquals("operation-description", unpacked.operation.description); assertNull(unpacked.operation.metadata); }lib/src/test/java/io/ably/lib/chat/ChatMessagesTest.java (5)
65-65
: Consider extracting the magic number timeout value.The timeout value of 10,000ms should be extracted as a constant to improve maintainability.
+ private static final int MESSAGE_WAIT_TIMEOUT = 10_000; - Exception err = new Helpers.ConditionalWaiter().wait(() -> !receivedMsg.isEmpty(), 10_000); + Exception err = new Helpers.ConditionalWaiter().wait(() -> !receivedMsg.isEmpty(), MESSAGE_WAIT_TIMEOUT);
107-109
: Enhance resource cleanup in finally block.The
ably.close()
call should be wrapped in a try-catch block to ensure any cleanup exceptions are logged but don't mask the original test exception.finally { - if(ably != null) - ably.close(); + if(ably != null) { + try { + ably.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } }
323-438
: Consider splitting this test into smaller, focused tests.This test method is quite long and tests multiple aspects of message lifecycle. Consider splitting it into smaller tests using
@TestFactory
or parameterized tests to improve maintainability and readability.Example approach:
@TestFactory Stream<DynamicTest> messageLifecycleTests() { return Stream.of( DynamicTest.dynamicTest("Message creation", () -> { // Test message creation }), DynamicTest.dynamicTest("Message update after creation", () -> { // Test message update }), DynamicTest.dynamicTest("Message deletion after update", () -> { // Test message deletion }) ); }
511-513
: Enhance assertions for message state verification.The current assertion only verifies the serial number. Consider adding more specific assertions to verify the state and content of messages at each stage.
for (Message msg : receivedMsg) { Assert.assertEquals("Serial should match original serial", originalSerial, msg.serial); + switch(msg.action) { + case MESSAGE_CREATE: + Assert.assertEquals("hello there", ((JsonObject)msg.data).get("text").getAsString()); + break; + case MESSAGE_UPDATE: + Assert.assertEquals("updated text", ((JsonObject)msg.data).get("text").getAsString()); + break; + case MESSAGE_DELETE: + Assert.assertNotNull("Delete operation should be present", msg.operation); + Assert.assertEquals("message deleted by clientId1", msg.operation.description); + break; + } }
1-523
: Consider implementing a custom test framework for chat operations.Given the repetitive nature of these tests and common patterns, consider creating a custom test framework or JUnit extensions that would:
- Handle common setup/teardown operations
- Provide fluent assertions for chat messages
- Manage connection lifecycle
- Handle async operations with proper timeouts
This would significantly reduce code duplication and make tests more maintainable.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
lib/src/main/java/io/ably/lib/types/Message.java
(9 hunks)lib/src/test/java/io/ably/lib/chat/ChatMessagesTest.java
(1 hunks)lib/src/test/java/io/ably/lib/chat/ChatRoom.java
(1 hunks)lib/src/test/java/io/ably/lib/types/MessageTest.java
(4 hunks)
🔇 Additional comments (1)
lib/src/test/java/io/ably/lib/chat/ChatMessagesTest.java (1)
1-20
: LGTM! Class structure and imports are well organized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
lib/src/main/java/io/ably/lib/types/Message.java (1)
96-98
: Consider using a more flexible metadata type.The current
Map<String, String>
type for metadata might be limiting. Consider usingMap<String, Object>
orJsonObject
to support various data types in metadata, improving flexibility for future use cases.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
lib/src/main/java/io/ably/lib/types/Message.java
(9 hunks)lib/src/test/java/io/ably/lib/chat/ChatRoom.java
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/src/test/java/io/ably/lib/chat/ChatRoom.java
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: check-rest-okhttp
- GitHub Check: check (29)
- GitHub Check: check (24)
- GitHub Check: check-rest
- GitHub Check: check-realtime-okhttp
- GitHub Check: check (21)
- GitHub Check: build
- GitHub Check: check (19)
- GitHub Check: check-realtime
- GitHub Check: check
🔇 Additional comments (5)
lib/src/main/java/io/ably/lib/types/Message.java (5)
80-94
: LGTM! Well-documented field declarations.The new fields are properly documented with spec references and maintain consistency with the existing codebase.
95-172
: Well-implemented Operation class with forward compatibility.The Operation class implementation is robust with:
- Efficient serialization of non-null fields
- Proper handling of null values
- Forward compatibility through default cases in deserialization
Line range hint
263-313
: LGTM! Consistent serialization implementation.The MessagePack serialization changes maintain consistency with the existing pattern and include proper null checks.
Also applies to: 343-349
516-522
: LGTM! Robust JSON handling implementation.The JSON serialization/deserialization changes include:
- Proper type checking
- Clear error messages
- Consistent handling with existing fields
Also applies to: 550-558
95-172
: Verify unit test coverage for Operation class.Please ensure there are comprehensive unit tests for the Operation class, covering:
- Serialization/deserialization of all fields
- Handling of null values
- Edge cases with empty/null metadata
✅ Verification successful
Operation class has sufficient test coverage
The Operation class is well-tested through:
- Comprehensive serialization tests (JSON and MessagePack)
- Full coverage of all fields (clientId, description, metadata)
- Integration tests in chat functionality
- Edge cases via Message class tests
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for Operation class tests rg -l "class.*Test.*Operation" "lib/src/test"Length of output: 45
Script:
#!/bin/bash # Search for Message.Operation usage in test files echo "=== Searching for Message.Operation usage in tests ===" rg "Message\.Operation" "lib/src/test" -B 1 -A 1 echo -e "\n=== Searching for test methods related to Operation ===" rg "void.*test.*[Oo]peration.*\(" "lib/src/test" -B 1 -A 1 echo -e "\n=== Searching for Message test files ===" rg -l "class.*MessageTest" "lib/src/test"Length of output: 2426
Script:
#!/bin/bash # Search for relevant test methods in MessageTest.java echo "=== Searching MessageTest.java for serialization tests ===" rg "test.*serializ|test.*json|test.*msgpack" "lib/src/test/java/io/ably/lib/types/MessageTest.java" -B 1 -A 10 echo -e "\n=== Showing context around Operation usage in MessageTest.java ===" rg -A 20 -B 2 "Operation operation = new Message\.Operation\(\)" "lib/src/test/java/io/ably/lib/types/MessageTest.java"Length of output: 6116
…ated ChatRoom public methods
6f7a983
to
c3264ea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
lib/src/main/java/io/ably/lib/types/Message.java (2)
98-98
: Consider making the metadata map immutable.The
metadata
map could be modified after creation, which might lead to unexpected behavior. Consider making it immutable to prevent modifications after creation.- public Map<String, String> metadata; + public final Map<String, String> metadata;Also, consider returning an unmodifiable view in the read methods:
- operation.metadata = new HashMap<>(mapSize); + Map<String, String> modifiableMap = new HashMap<>(mapSize); // ... populate the map ... + operation.metadata = Collections.unmodifiableMap(modifiableMap);
343-349
: Consider using a switch statement for field deserialization.The current if-else chain could be refactored to use a switch statement for better maintainability and consistency with the Operation class.
- } else if (fieldName.equals(REF_SERIAL)) { - refSerial = unpacker.unpackString(); - } else if (fieldName.equals(REF_TYPE)) { - refType = unpacker.unpackString(); - } else if (fieldName.equals(OPERATION)) { - operation = Operation.read(unpacker); + } else { + switch (fieldName) { + case REF_SERIAL: + refSerial = unpacker.unpackString(); + break; + case REF_TYPE: + refType = unpacker.unpackString(); + break; + case OPERATION: + operation = Operation.read(unpacker); + break; + default: + Log.v(TAG, "Unexpected field: " + fieldName); + unpacker.skipValue(); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
lib/src/main/java/io/ably/lib/types/Message.java
(9 hunks)lib/src/test/java/io/ably/lib/chat/ChatRoom.java
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/src/test/java/io/ably/lib/chat/ChatRoom.java
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: check-rest-okhttp
- GitHub Check: check (29)
- GitHub Check: check (24)
- GitHub Check: check-rest
- GitHub Check: check (21)
- GitHub Check: check-realtime-okhttp
- GitHub Check: build
- GitHub Check: check (19)
- GitHub Check: check-realtime
- GitHub Check: check
🔇 Additional comments (7)
lib/src/main/java/io/ably/lib/types/Message.java (7)
80-94
: LGTM! Well-documented fields with clear spec references.The new fields
refSerial
,refType
, andoperation
are properly documented with their respective spec references (TM2l, TM2m, TM2n).
95-172
: LGTM! Well-structured Operation class with robust serialization.The Operation class implementation is solid with proper null checks, efficient map initialization, and graceful handling of unknown fields.
181-183
: LGTM! Constants follow existing naming pattern.The new constants
REF_SERIAL
,REF_TYPE
, andOPERATION
are consistent with the existing naming convention.
268-271
: LGTM! Proper MessagePack serialization for new fields.The serialization logic correctly handles null checks and follows the existing pattern for writing fields.
Also applies to: 302-313
513-522
: LGTM! Robust JSON deserialization with proper type checking.The JSON deserialization properly validates the operation field type and handles errors appropriately.
550-558
: LGTM! Proper JSON serialization for new fields.The serialization logic correctly handles null checks and follows the existing pattern for writing fields.
Line range hint
1-583
: Verify test coverage for new message operations.Please ensure comprehensive test coverage for the new message operations functionality, including:
- Serialization/deserialization of messages with operations
- Edge cases with null/empty operation fields
- Invalid operation JSON/MessagePack formats
✅ Verification successful
Test coverage verified for Message Operation functionality
The codebase has comprehensive test coverage for the new Message Operation functionality:
- Core Operation class functionality in MessageTest.java
- Integration testing in ChatMessagesTest.java
- Both JSON and MessagePack serialization formats
- All Operation fields (clientId, description, metadata)
- Edge cases and error handling
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check test coverage for new message operations # Look for test files echo "Searching for relevant test files..." fd -e java -e kt test.*Message # Search for operation-related tests echo -e "\nSearching for operation-related tests..." rg -l "operation.*test" -t java -t kotlin # Look for specific test cases echo -e "\nSearching for specific test cases..." rg "test.*operation" -A 10 -t java -t kotlinLength of output: 1518
Script:
#!/bin/bash # Broader search for Message-related tests echo "Searching for Message class usage in tests..." rg "class.*Message.*Test|extends.*Message" -t java echo -e "\nSearching for Message serialization/deserialization tests..." rg "fromEncoded|writeMsgpack|readMsgpack.*Message" -B 2 -A 5 -t java echo -e "\nSearching for Operation-related code in tests..." rg "Operation.*\{|new Operation\(|operation\." -B 2 -A 5 -t java echo -e "\nLooking for test files that might contain Message tests..." fd -e java testLength of output: 67090
TODO
clientId
,description
andmetadata
.Summary by CodeRabbit
New Features
refSerial
,refType
, andoperation
.Tests