|
3 | 3 | import pytest |
4 | 4 |
|
5 | 5 | from hiero_sdk_python.consensus.topic_info import TopicInfo |
| 6 | +from hiero_sdk_python.executable import _ExecutionState |
6 | 7 | from hiero_sdk_python.hapi.services import ( |
7 | 8 | basic_types_pb2, |
8 | 9 | consensus_get_topic_info_pb2, |
9 | 10 | consensus_topic_info_pb2, |
10 | 11 | response_header_pb2, |
11 | | - response_pb2 |
| 12 | + response_pb2, |
| 13 | + query_pb2, |
12 | 14 | ) |
13 | 15 | from hiero_sdk_python.hapi.services.query_header_pb2 import ResponseType |
14 | 16 | from hiero_sdk_python.query.topic_info_query import TopicInfoQuery |
@@ -59,6 +61,15 @@ def create_topic_info_response(status_code=ResponseCode.OK, with_info=True): |
59 | 61 | return responses |
60 | 62 |
|
61 | 63 |
|
| 64 | +def _response_with_status(status: ResponseCode) -> response_pb2.Response: |
| 65 | + """Create a Response with only the consensusGetTopicInfo header status set.""" |
| 66 | + return response_pb2.Response( |
| 67 | + consensusGetTopicInfo=consensus_get_topic_info_pb2.ConsensusGetTopicInfoResponse( |
| 68 | + header=response_header_pb2.ResponseHeader(nodeTransactionPrecheckCode=status) |
| 69 | + ) |
| 70 | + ) |
| 71 | + |
| 72 | + |
62 | 73 | def test_topic_info_query(topic_id): |
63 | 74 | """Test basic functionality of TopicInfoQuery with mock server.""" |
64 | 75 | responses = create_topic_info_response() |
@@ -96,3 +107,61 @@ def test_topic_info_query_with_empty_topic_id(): |
96 | 107 | query.execute(client) |
97 | 108 |
|
98 | 109 | assert "Topic ID must be set" in str(exc_info.value) |
| 110 | + |
| 111 | + |
| 112 | +def test_make_request_builds_expected_protobuf(topic_id): |
| 113 | + """ |
| 114 | + Covers TopicInfoQuery._make_request() using REAL protobuf classes. |
| 115 | + This is fast and deterministic (no network). |
| 116 | + """ |
| 117 | + query = TopicInfoQuery().set_topic_id(topic_id) |
| 118 | + |
| 119 | + req = query._make_request() |
| 120 | + assert isinstance(req, query_pb2.Query) |
| 121 | + |
| 122 | + # Ensure the correct oneof field is populated |
| 123 | + assert req.HasField("consensusGetTopicInfo") |
| 124 | + assert req.consensusGetTopicInfo.HasField("topicID") |
| 125 | + |
| 126 | + # Compare serialized protobuf to avoid equality quirks |
| 127 | + expected_topic_id_proto = topic_id._to_proto() |
| 128 | + assert ( |
| 129 | + req.consensusGetTopicInfo.topicID.SerializeToString() |
| 130 | + == expected_topic_id_proto.SerializeToString() |
| 131 | + ) |
| 132 | + |
| 133 | + |
| 134 | +@pytest.mark.parametrize( |
| 135 | + "status,expected_state", |
| 136 | + [ |
| 137 | + (ResponseCode.OK, _ExecutionState.FINISHED), |
| 138 | + (ResponseCode.UNKNOWN, _ExecutionState.RETRY), |
| 139 | + (ResponseCode.BUSY, _ExecutionState.RETRY), |
| 140 | + (ResponseCode.PLATFORM_NOT_ACTIVE, _ExecutionState.RETRY), |
| 141 | + (ResponseCode.INVALID_TOPIC_ID, _ExecutionState.ERROR), |
| 142 | + ], |
| 143 | +) |
| 144 | +def test_should_retry_branches(status, expected_state): |
| 145 | + """Covers OK / RETRY / ERROR branches of TopicInfoQuery._should_retry().""" |
| 146 | + query = TopicInfoQuery() |
| 147 | + response = _response_with_status(status) |
| 148 | + |
| 149 | + assert query._should_retry(response) == expected_state |
| 150 | + |
| 151 | + |
| 152 | +def test_freeze_prevents_set_topic_id_if_available(topic_id): |
| 153 | + """ |
| 154 | + If TopicInfoQuery implements freeze semantics, ensure it prevents mutation. |
| 155 | + This is written to not break the suite if freeze() doesn't exist in your version. |
| 156 | + """ |
| 157 | + query = TopicInfoQuery() |
| 158 | + |
| 159 | + if not hasattr(query, "freeze"): |
| 160 | + pytest.skip("TopicInfoQuery.freeze() not available in this SDK version") |
| 161 | + |
| 162 | + query.freeze() |
| 163 | + |
| 164 | + with pytest.raises(ValueError) as exc_info: |
| 165 | + query.set_topic_id(topic_id) |
| 166 | + |
| 167 | + assert "frozen" in str(exc_info.value).lower() |
0 commit comments