Skip to content

Commit b6f05c9

Browse files
committed
test: add freeze transaction unit tests
Signed-off-by: dosi <[email protected]>
1 parent 6a01152 commit b6f05c9

File tree

1 file changed

+290
-0
lines changed

1 file changed

+290
-0
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
"""
2+
Test cases for the FreezeTransaction class.
3+
"""
4+
5+
from unittest.mock import MagicMock
6+
7+
import pytest
8+
9+
from hiero_sdk_python.file.file_id import FileId
10+
from hiero_sdk_python.hapi.services.freeze_type_pb2 import (
11+
FreezeType as proto_FreezeType,
12+
)
13+
from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import (
14+
SchedulableTransactionBody,
15+
)
16+
from hiero_sdk_python.system.freeze_transaction import FreezeTransaction
17+
from hiero_sdk_python.system.freeze_type import FreezeType
18+
from hiero_sdk_python.timestamp import Timestamp
19+
20+
pytestmark = pytest.mark.unit
21+
22+
23+
@pytest.fixture
24+
def freeze_params():
25+
"""Fixture for freeze transaction parameters."""
26+
return {
27+
"start_time": Timestamp(1640995200, 0),
28+
"file_id": FileId(0, 0, 123),
29+
"file_hash": b"test-file-hash",
30+
"freeze_type": FreezeType.FREEZE_ONLY,
31+
}
32+
33+
34+
def test_constructor_with_parameters(freeze_params):
35+
"""Test creating a freeze transaction with constructor parameters."""
36+
freeze_tx = FreezeTransaction(
37+
start_time=freeze_params["start_time"],
38+
file_id=freeze_params["file_id"],
39+
file_hash=freeze_params["file_hash"],
40+
freeze_type=freeze_params["freeze_type"],
41+
)
42+
43+
assert freeze_tx.start_time == freeze_params["start_time"]
44+
assert freeze_tx.file_id == freeze_params["file_id"]
45+
assert freeze_tx.file_hash == freeze_params["file_hash"]
46+
assert freeze_tx.freeze_type == freeze_params["freeze_type"]
47+
48+
49+
def test_constructor_default_values():
50+
"""Test that constructor sets default values correctly."""
51+
freeze_tx = FreezeTransaction()
52+
53+
assert freeze_tx.start_time is None
54+
assert freeze_tx.file_id is None
55+
assert freeze_tx.file_hash is None
56+
assert freeze_tx.freeze_type is None
57+
58+
59+
def test_build_transaction_body_with_valid_parameters(mock_account_ids, freeze_params):
60+
"""Test building a freeze transaction body with valid parameters."""
61+
operator_id, _, node_account_id, _, _ = mock_account_ids
62+
63+
freeze_tx = FreezeTransaction(
64+
start_time=freeze_params["start_time"],
65+
file_id=freeze_params["file_id"],
66+
file_hash=freeze_params["file_hash"],
67+
freeze_type=freeze_params["freeze_type"],
68+
)
69+
70+
# Set operator and node account IDs needed for building transaction body
71+
freeze_tx.operator_account_id = operator_id
72+
freeze_tx.node_account_id = node_account_id
73+
74+
transaction_body = freeze_tx.build_transaction_body()
75+
76+
# Verify the transaction body contains freeze field
77+
assert transaction_body.HasField("freeze")
78+
79+
# Verify all fields are correctly set
80+
freeze_body = transaction_body.freeze
81+
assert freeze_body.start_time == freeze_params["start_time"]._to_protobuf()
82+
assert freeze_body.update_file == freeze_params["file_id"]._to_proto()
83+
assert freeze_body.file_hash == freeze_params["file_hash"]
84+
assert freeze_body.freeze_type == freeze_params["freeze_type"]._to_proto()
85+
86+
87+
def test_build_transaction_body_with_none_values(mock_account_ids):
88+
"""Test building a freeze transaction body with None values."""
89+
operator_id, _, node_account_id, _, _ = mock_account_ids
90+
91+
freeze_tx = FreezeTransaction()
92+
93+
# Set operator and node account IDs needed for building transaction body
94+
freeze_tx.operator_account_id = operator_id
95+
freeze_tx.node_account_id = node_account_id
96+
97+
transaction_body = freeze_tx.build_transaction_body()
98+
99+
# Verify the transaction body contains freeze field
100+
assert transaction_body.HasField("freeze")
101+
102+
# Verify all fields are None or default values
103+
freeze_body = transaction_body.freeze
104+
assert not freeze_body.HasField("start_time") # Empty protobuf object when None
105+
assert not freeze_body.HasField("update_file") # Empty protobuf object when None
106+
assert freeze_body.file_hash == b"" # Empty bytes when None
107+
assert freeze_body.freeze_type == proto_FreezeType.UNKNOWN_FREEZE_TYPE
108+
109+
110+
def test_build_scheduled_body(freeze_params):
111+
"""Test building a schedulable freeze transaction body."""
112+
freeze_tx = FreezeTransaction(
113+
start_time=freeze_params["start_time"],
114+
file_id=freeze_params["file_id"],
115+
file_hash=freeze_params["file_hash"],
116+
freeze_type=freeze_params["freeze_type"],
117+
)
118+
119+
schedulable_body = freeze_tx.build_scheduled_body()
120+
121+
# Verify the correct type is returned
122+
assert isinstance(schedulable_body, SchedulableTransactionBody)
123+
124+
# Verify the transaction was built with freeze type
125+
assert schedulable_body.HasField("freeze")
126+
127+
# Verify fields in the schedulable body
128+
freeze_body = schedulable_body.freeze
129+
assert freeze_body.start_time == freeze_params["start_time"]._to_protobuf()
130+
assert freeze_body.update_file == freeze_params["file_id"]._to_proto()
131+
assert freeze_body.file_hash == freeze_params["file_hash"]
132+
assert freeze_body.freeze_type == freeze_params["freeze_type"]._to_proto()
133+
134+
135+
def test_set_start_time(freeze_params):
136+
"""Test setting start_time using the setter method."""
137+
freeze_tx = FreezeTransaction()
138+
139+
result = freeze_tx.set_start_time(freeze_params["start_time"])
140+
141+
assert freeze_tx.start_time == freeze_params["start_time"]
142+
assert result is freeze_tx # Should return self for method chaining
143+
144+
145+
def test_set_file_id(freeze_params):
146+
"""Test setting file_id using the setter method."""
147+
freeze_tx = FreezeTransaction()
148+
149+
result = freeze_tx.set_file_id(freeze_params["file_id"])
150+
151+
assert freeze_tx.file_id == freeze_params["file_id"]
152+
assert result is freeze_tx # Should return self for method chaining
153+
154+
155+
def test_set_file_hash(freeze_params):
156+
"""Test setting file_hash using the setter method."""
157+
freeze_tx = FreezeTransaction()
158+
159+
result = freeze_tx.set_file_hash(freeze_params["file_hash"])
160+
161+
assert freeze_tx.file_hash == freeze_params["file_hash"]
162+
assert result is freeze_tx # Should return self for method chaining
163+
164+
165+
def test_set_freeze_type(freeze_params):
166+
"""Test setting freeze_type using the setter method."""
167+
freeze_tx = FreezeTransaction()
168+
169+
result = freeze_tx.set_freeze_type(freeze_params["freeze_type"])
170+
171+
assert freeze_tx.freeze_type == freeze_params["freeze_type"]
172+
assert result is freeze_tx # Should return self for method chaining
173+
174+
175+
def test_method_chaining_with_all_setters(freeze_params):
176+
"""Test that all setter methods support method chaining."""
177+
freeze_tx = FreezeTransaction()
178+
179+
result = (
180+
freeze_tx.set_start_time(freeze_params["start_time"])
181+
.set_file_id(freeze_params["file_id"])
182+
.set_file_hash(freeze_params["file_hash"])
183+
.set_freeze_type(freeze_params["freeze_type"])
184+
)
185+
186+
assert result is freeze_tx
187+
assert freeze_tx.start_time == freeze_params["start_time"]
188+
assert freeze_tx.file_id == freeze_params["file_id"]
189+
assert freeze_tx.file_hash == freeze_params["file_hash"]
190+
assert freeze_tx.freeze_type == freeze_params["freeze_type"]
191+
192+
193+
def test_set_methods_require_not_frozen(mock_client, freeze_params):
194+
"""Test that setter methods raise exception when transaction is frozen."""
195+
freeze_tx = FreezeTransaction()
196+
freeze_tx.freeze_with(mock_client)
197+
198+
test_cases = [
199+
("set_start_time", freeze_params["start_time"]),
200+
("set_file_id", freeze_params["file_id"]),
201+
("set_file_hash", freeze_params["file_hash"]),
202+
("set_freeze_type", freeze_params["freeze_type"]),
203+
]
204+
205+
for method_name, value in test_cases:
206+
with pytest.raises(
207+
Exception, match="Transaction is immutable; it has been frozen"
208+
):
209+
getattr(freeze_tx, method_name)(value)
210+
211+
212+
def test_get_method():
213+
"""Test retrieving the gRPC method for the transaction."""
214+
freeze_tx = FreezeTransaction()
215+
216+
mock_channel = MagicMock()
217+
mock_freeze_stub = MagicMock()
218+
mock_channel.freeze = mock_freeze_stub
219+
220+
method = freeze_tx._get_method(mock_channel)
221+
222+
assert method.query is None
223+
assert method.transaction == mock_freeze_stub.freeze
224+
225+
226+
def test_sign_transaction(mock_client):
227+
"""Test signing the freeze transaction with a private key."""
228+
freeze_tx = FreezeTransaction()
229+
freeze_tx.set_freeze_type(FreezeType.FREEZE_ONLY)
230+
231+
private_key = MagicMock()
232+
private_key.sign.return_value = b"signature"
233+
private_key.public_key().to_bytes_raw.return_value = b"public_key"
234+
235+
freeze_tx.freeze_with(mock_client)
236+
freeze_tx.sign(private_key)
237+
238+
node_id = mock_client.network.current_node._account_id
239+
body_bytes = freeze_tx._transaction_body_bytes[node_id]
240+
241+
assert len(freeze_tx._signature_map[body_bytes].sigPair) == 1
242+
sig_pair = freeze_tx._signature_map[body_bytes].sigPair[0]
243+
assert sig_pair.pubKeyPrefix == b"public_key"
244+
assert sig_pair.ed25519 == b"signature"
245+
246+
247+
def test_to_proto(mock_client):
248+
"""Test converting the freeze transaction to protobuf format after signing."""
249+
freeze_tx = FreezeTransaction()
250+
freeze_tx.set_freeze_type(FreezeType.FREEZE_ONLY)
251+
252+
private_key = MagicMock()
253+
private_key.sign.return_value = b"signature"
254+
private_key.public_key().to_bytes_raw.return_value = b"public_key"
255+
256+
freeze_tx.freeze_with(mock_client)
257+
freeze_tx.sign(private_key)
258+
proto = freeze_tx._to_proto()
259+
260+
assert proto.signedTransactionBytes
261+
assert len(proto.signedTransactionBytes) > 0
262+
263+
264+
def test_build_proto_body_with_all_fields(freeze_params):
265+
"""Test building protobuf body with all fields set."""
266+
freeze_tx = FreezeTransaction(
267+
start_time=freeze_params["start_time"],
268+
file_id=freeze_params["file_id"],
269+
file_hash=freeze_params["file_hash"],
270+
freeze_type=freeze_params["freeze_type"],
271+
)
272+
273+
proto_body = freeze_tx._build_proto_body()
274+
275+
assert proto_body.start_time == freeze_params["start_time"]._to_protobuf()
276+
assert proto_body.update_file == freeze_params["file_id"]._to_proto()
277+
assert proto_body.file_hash == freeze_params["file_hash"]
278+
assert proto_body.freeze_type == freeze_params["freeze_type"]._to_proto()
279+
280+
281+
def test_build_proto_body_with_none_fields():
282+
"""Test building protobuf body with None fields."""
283+
freeze_tx = FreezeTransaction()
284+
285+
proto_body = freeze_tx._build_proto_body()
286+
287+
assert not proto_body.HasField("start_time")
288+
assert not proto_body.HasField("update_file")
289+
assert proto_body.file_hash == b""
290+
assert proto_body.freeze_type == proto_FreezeType.UNKNOWN_FREEZE_TYPE

0 commit comments

Comments
 (0)