99from io import BytesIO
1010import http .client
1111import json
12+ import platform
1213import typing
1314import urllib .parse
1415
2829 MiniWallet ,
2930 getnewdestination ,
3031)
31- from typing import Optional
3232
3333
3434INVALID_PARAM = "abc"
@@ -66,13 +66,16 @@ def test_rest_request(
6666 body : str = '' ,
6767 status : int = 200 ,
6868 ret_type : RetType = RetType .JSON ,
69- query_params : Optional [dict [str , typing .Any ]] = None ,
69+ query_params : typing . Union [dict [str , typing .Any ], str , None ] = None ,
7070 ) -> typing .Union [http .client .HTTPResponse , bytes , str , None ]:
7171 rest_uri = '/rest' + uri
7272 if req_type in ReqType :
7373 rest_uri += f'.{ req_type .name .lower ()} '
7474 if query_params :
75- rest_uri += f'?{ urllib .parse .urlencode (query_params )} '
75+ if isinstance (query_params , str ):
76+ rest_uri += f'?{ query_params } '
77+ else :
78+ rest_uri += f'?{ urllib .parse .urlencode (query_params )} '
7679
7780 conn = http .client .HTTPConnection (self .url .hostname , self .url .port )
7881 self .log .debug (f'{ http_method } { rest_uri } { body } ' )
@@ -82,7 +85,7 @@ def test_rest_request(
8285 conn .request ('POST' , rest_uri , body )
8386 resp = conn .getresponse ()
8487
85- assert_equal ( resp .status , status )
88+ assert resp .status == status , f"Expected: { status } , Got: { resp . status } - Response: { str ( resp . read ()) } "
8689
8790 if ret_type == RetType .OBJ :
8891 return resp
@@ -455,6 +458,53 @@ def run_test(self):
455458 expected = [(p ["scriptPubKey" ], p ["value" ]) for p in prevouts ]
456459 assert_equal (expected , actual )
457460
461+ self .log .info ("Test the /blockpart URI" )
462+
463+ blockhash = self .nodes [0 ].getbestblockhash ()
464+ block_bin = self .test_rest_request (f"/block/{ blockhash } " , req_type = ReqType .BIN , ret_type = RetType .BYTES )
465+ for req_type in (ReqType .BIN , ReqType .HEX ):
466+ def _get_block_part (status : int = 200 , ** kwargs ):
467+ resp = self .test_rest_request (f"/blockpart/{ blockhash } " , status = status ,
468+ req_type = req_type , ret_type = RetType .BYTES , ** kwargs )
469+ assert isinstance (resp , bytes )
470+ if req_type is ReqType .HEX and status == 200 :
471+ resp = bytes .fromhex (resp .decode ().strip ())
472+ return resp
473+
474+ assert_equal (block_bin , _get_block_part (query_params = {"offset" : 0 , "size" : len (block_bin )}))
475+
476+ assert len (block_bin ) >= 500
477+ assert_equal (block_bin [20 :320 ], _get_block_part (query_params = {"offset" : 20 , "size" : 300 }))
478+ assert_equal (block_bin [- 5 :], _get_block_part (query_params = {"offset" : len (block_bin ) - 5 , "size" : 5 }))
479+
480+ _get_block_part (status = 400 , query_params = {"offset" : 10 })
481+ _get_block_part (status = 400 , query_params = {"size" : 100 })
482+ _get_block_part (status = 400 , query_params = {"offset" : "x" })
483+ _get_block_part (status = 400 , query_params = {"size" : "y" })
484+ _get_block_part (status = 400 , query_params = {"offset" : "x" , "size" : "y" })
485+ assert _get_block_part (status = 400 , query_params = "%XY" ).decode ("utf-8" ).startswith ("URI parsing failed" )
486+
487+ _get_block_part (status = 400 , query_params = {"offset" : 0 , "size" : 0 })
488+ _get_block_part (status = 400 , query_params = {"offset" : len (block_bin ), "size" : 0 })
489+ _get_block_part (status = 400 , query_params = {"offset" : len (block_bin ) + 1 , "size" : 1 })
490+ _get_block_part (status = 400 , query_params = {"offset" : len (block_bin ), "size" : 1 })
491+ _get_block_part (status = 400 , query_params = {"offset" : len (block_bin ) + 1 , "size" : 1 })
492+ _get_block_part (status = 400 , query_params = {"offset" : 0 , "size" : len (block_bin ) + 1 })
493+
494+ self .test_rest_request (f"/blockpart/{ blockhash } " , status = 400 , req_type = ReqType .JSON , ret_type = RetType .OBJ )
495+
496+ self .test_rest_request (f"/block/{ blockhash } " , status = 200 , req_type = ReqType .BIN , ret_type = RetType .OBJ )
497+ self .test_rest_request (f"/blockpart/{ blockhash } " , query_params = {"offset" : 0 , "size" : 1 }, status = 200 , req_type = ReqType .BIN , ret_type = RetType .OBJ )
498+ # Missing block data should cause REST API to fail
499+ if platform .system () != "Windows" :
500+ blocks_path = self .nodes [0 ].blocks_path
501+ backup_path = blocks_path .with_suffix (".bkp" )
502+ blocks_path .rename (backup_path )
503+ try :
504+ self .test_rest_request (f"/block/{ blockhash } " , status = 500 , req_type = ReqType .BIN , ret_type = RetType .OBJ )
505+ self .test_rest_request (f"/blockpart/{ blockhash } " , query_params = {"offset" : 0 , "size" : 1 }, status = 500 , req_type = ReqType .BIN , ret_type = RetType .OBJ )
506+ finally :
507+ backup_path .rename (blocks_path )
458508
459509 self .log .info ("Test the /deploymentinfo URI" )
460510
0 commit comments