diff --git a/tests/store/test_cursor.py b/tests/store/test_cursor.py index 8fa4dd3314..ef28f9bb88 100644 --- a/tests/store/test_cursor.py +++ b/tests/store/test_cursor.py @@ -195,3 +195,57 @@ class TestCursor(StepsStore): # Validate that paginationCursor is **not** present when we reach the boundary (end of pagination) assert store_response.pagination_cursor is None, "paginationCursor should be absent when at the boundary" + + # This test publishes 5 messages and retrieves them using the store API with a page size of 3. + # It attempts to use an invalid 'paginationCursor' query parameter instead of the correct 'cursor'. + # The test then validates that the incorrect parameter doesn't affect pagination and that the correct + # 'cursor' parameter successfully retrieves the remaining messages. + def test_invalid_pagination_cursor_param(self): + # Store the timestamps used when creating messages + timestamps = [] + + # Publish 5 messages + for i in range(5): + message = self.create_message(payload=to_base64(f"Message_{i}")) + timestamps.append(message["timestamp"]) # Save the timestamp + self.publish_message(message=message) + + for node in self.store_nodes: + # Step 1: Request first page with pageSize = 3 + store_response = self.get_messages_from_store(node, page_size=3) + assert len(store_response.messages) == 3, "Message count mismatch on first page" + pagination_cursor = store_response.pagination_cursor + + # Step 2: Attempt to use invalid paginationCursor param (expect 200 but no page change) + invalid_cursor = pagination_cursor + store_response_invalid = self.get_messages_from_store(node, page_size=3, paginationCursor=invalid_cursor) + assert store_response_invalid.status_code == 200, "Expected 200 response with invalid paginationCursor param" + assert len(store_response_invalid.messages) == 3, "Expected the same page content since paginationCursor is ignored" + assert store_response_invalid.messages == store_response.messages, "Messages should be the same as the first page" + + # Step 3: Use correct cursor to get the remaining messages + store_response_valid = self.get_messages_from_store(node, page_size=3, cursor=pagination_cursor) + assert len(store_response_valid.messages) == 2, "Message count mismatch on second page" + assert store_response_valid.pagination_cursor is None, "There should be no pagination cursor for the last page" + + # Validate the message content using the correct timestamp + expected_message_hashes = [ + self.compute_message_hash( + self.test_pubsub_topic, + { + "payload": to_base64(f"Message_3"), + "contentTopic": "/myapp/1/latest/proto", + "timestamp": timestamps[3], # Use the stored timestamp for Message_3 + }, + ), + self.compute_message_hash( + self.test_pubsub_topic, + { + "payload": to_base64(f"Message_4"), + "contentTopic": "/myapp/1/latest/proto", + "timestamp": timestamps[4], # Use the stored timestamp for Message_4 + }, + ), + ] + for i, message in enumerate(store_response_valid.messages): + assert message["messageHash"] == expected_message_hashes[i], f"Message hash mismatch for message {i}" diff --git a/tests/store/test_hashes.py b/tests/store/test_hashes.py index 51528b4b80..f296bcb3e0 100644 --- a/tests/store/test_hashes.py +++ b/tests/store/test_hashes.py @@ -64,3 +64,109 @@ class TestHashes(StepsStore): assert not store_response.messages except Exception as ex: assert "waku message hash parsing error: invalid hash length" in str(ex) + + # Addon on Test + + # Test when the hashes parameter is an empty string. + def test_store_with_empty_hashes(self): + for i in range(4): + self.publish_message(message=self.create_message(payload=to_base64(f"Message_{i}"))) + + # Test with an empty string for the hashes parameter + for node in self.store_nodes: + store_response = self.get_messages_from_store(node, hashes="", page_size=50) + assert len(store_response.messages) == 4, "Messages found" + + # Test when the hash is longer than the valid length (e.g., 45 characters or more). + def test_store_with_excessive_length_hash(self): + excessive_length_hash = "A" * 50 # Exceeds valid length of 44 characters for a Base64-encoded hash + for i in range(4): + self.publish_message(message=self.create_message(payload=to_base64(f"Message_{i}"))) + + for node in self.store_nodes: + store_response = self.get_store_messages_with_errors(node, hashes=excessive_length_hash, page_size=50) + + # Check if the response has a "messages" key and if it's empty + assert "messages" not in store_response, "Messages found for an excessive length hash" + + # Test the behavior when you supply an empty hash alongside valid hashes. + def test_store_with_empty_and_valid_hash(self): + message_hash_list = [] + for i in range(4): + message = self.create_message(payload=to_base64(f"Message_{i}")) + self.publish_message(message=message) + message_hash_list.append(self.compute_message_hash(self.test_pubsub_topic, message)) + + empty_hash = "" + for node in self.store_nodes: + try: + # Combining valid hash with an empty hash + store_response = self.get_messages_from_store(node, hashes=f"{message_hash_list[0]},{empty_hash}", page_size=50) + assert len(store_response.messages) == 1, "Message count mismatch with empty and valid hashes" + except Exception as ex: + assert "waku message hash parsing error" in str(ex), "Unexpected error for combined empty and valid hash" + + # Test for hashes that include non-Base64 characters. + def test_store_with_non_base64_characters_in_hash(self): + non_base64_hash = "###INVALID###" # Invalid hash with non-Base64 characters + for i in range(4): + self.publish_message(message=self.create_message(payload=to_base64(f"Message_{i}"))) + + for node in self.store_nodes: + store_response = self.get_store_messages_with_errors(node, hashes=non_base64_hash, page_size=50) + + assert ( + "waku message hash parsing error: Incorrect base64 string" in store_response["error_message"] + ), f"Expected 'Incorrect base64 string' error, got {store_response['error_message']}" + + # Test when duplicate valid hashes are provided. + def test_store_with_duplicate_hashes(self): + message_hash_list = [] + for i in range(4): + message = self.create_message(payload=to_base64(f"Message_{i}")) + self.publish_message(message=message) + message_hash_list.append(self.compute_message_hash(self.test_pubsub_topic, message)) + + # Use the same hash twice + duplicate_hash = f"{message_hash_list[0]},{message_hash_list[0]}" + for node in self.store_nodes: + store_response = self.get_messages_from_store(node, hashes=duplicate_hash, page_size=50) + assert len(store_response.messages) == 1, "Expected only one message for duplicate hashes" + assert store_response.message_hash(0) == message_hash_list[0], "Incorrect message returned for duplicate hashes" + + # Invalid Query Parameter (hash) for Hashes + def test_invalid_hash_param(self): + # Publish 4 messages + published_messages = [] + for i in range(4): + message = self.create_message(payload=to_base64(f"Message_{i}")) + self.publish_message(message=message) + published_messages.append(message) + + for node in self.store_nodes: + # Step 1: Request messages with the correct 'hashes' parameter + correct_hash = self.compute_message_hash(self.test_pubsub_topic, published_messages[2]) + store_response_valid = self.get_messages_from_store(node, hashes=correct_hash) + + assert store_response_valid.status_code == 200, "Expected 200 response with correct 'hashes' parameter" + assert len(store_response_valid.messages) == 1, "Expected exactly one message in the response" + assert store_response_valid is not None and store_response_valid.messages, "Store response is None or has no messages" + assert store_response_valid.messages[0]["messageHash"] == correct_hash, "Returned message hash does not match the expected hash" + + # Step 2: Attempt to use the invalid 'hash' parameter (expect all messages to be returned) + store_response_invalid = self.get_messages_from_store(node, hash=correct_hash) + + assert store_response_invalid.status_code == 200, "Expected 200 response with invalid 'hash' parameter" + assert len(store_response_invalid.messages) == 4, "Expected all messages to be returned since 'hash' filter is ignored" + + # Collect the hashes of all published messages + if store_response_invalid is not None and store_response_invalid.messages: + expected_hashes = [msg["messageHash"] for msg in store_response_invalid.messages] + returned_hashes = [msg["messageHash"] for msg in store_response_invalid.messages] + else: + expected_hashes = [] + returned_hashes = [] + + print("expected_hashes: ", expected_hashes) + print("returned_hashes: ", returned_hashes) + assert set(returned_hashes) == set(expected_hashes), "Returned message hashes do not match the expected hashes"