Repository: bitcoin/bitcoin
File: test/functional/interface_rest.py (Python)

Code before:
                                              req_type=req_type, ret_type=RetType.BYTES, **kwargs)
                assert isinstance(resp, bytes)
                if req_type is ReqType.HEX and status == 200:
                    resp = bytes.fromhex(resp.decode().strip())
                return resp

            assert_equal(block_bin, get_block_part(query_params={"offset": 0, "size": len(block_bin)}))

            assert len(block_bin) >= 500
            assert_equal(block_bin[20:320], get_block_part(query_params={"offset": 20, "size": 300}))
            assert_equal(block_bin[-5:], get_block_part(query_params={"offset": len(block_bin) - 5, "size": 5}))

            get_block_part(status=400, query_params={"offset": 10})
            get_block_part(status=400, query_params={"size": 100})
            get_block_part(status=400, query_params={"offset": "x"})
            get_block_part(status=400, query_params={"size": "y"})
            get_block_part(status=400, query_params={"offset": "x", "size": "y"})
            assert get_block_part(status=400, query_params="%XY").decode("utf-8").startswith("URI parsing failed")

            get_block_part(status=400, query_params={"offset": 0, "size": 0})
            get_block_part(status=400, query_params={"offset": len(block_bin), "size": 0})
            get_block_part(status=400, query_params={"offset": len(block_bin) + 1, "size": 1})
            get_block_part(status=400, query_params={"offset": len(block_bin), "size": 1})
            get_block_part(status=400, query_params={"offset": len(block_bin) + 1, "size": 1})
            get_block_part(status=400, query_params={"offset": 0, "size": len(block_bin) + 1})

        self.test_rest_request(f"/blockpart/{blockhash}", status=400, req_type=ReqType.JSON, ret_type=RetType.OBJ)

        self.log.info("Missing block data should cause REST API to fail")

        self.test_rest_request(f"/block/{blockhash}", status=200, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset": 0, "size": 1}, status=200, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        blk_files = list(self.nodes[0].blocks_path.glob("blk*.dat"))
        for blk_file in blk_files:
            blk_file.rename(blk_file.with_suffix('.bkp'))
        self.test_rest_request(f"/block/{blockhash}", status=500, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset": 0, "size": 1}, status=500, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        for blk_file in blk_files:
            blk_file.with_suffix('.bkp').rename(blk_file)

        self.log.info("Test the /deploymentinfo URI")

        deployment_info = self.nodes[0].getdeploymentinfo()
        assert_equal(deployment_info, self.test_rest_request('/deploymentinfo'))

        previous_bb_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount() - 1)
        deployment_info = self.nodes[0].getdeploymentinfo(previous_bb_hash)
        assert_equal(deployment_info, self.test_rest_request(f"/deploymentinfo/{previous_bb_hash}"))

        non_existing_blockhash = '42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4'
        resp = self.test_rest_request(f'/deploymentinfo/{non_existing_blockhash}', ret_type=RetType.OBJ, status=400)

Review comment (bug):
nit: This one could also do with more precision, to disambiguate whether it's testing for failure because of req_type=JSON or because of omitting offset/size:

```suggestion
        res = self.test_rest_request(f"/blockpart/{blockhash}", status=400, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        assert res.read().decode().startswith("Block part offset missing or invalid")
```

(Edit: removed `, f"Got: {resp}"` residue).

Code after:
                                              req_type=req_type, ret_type=RetType.BYTES, **kwargs)
                assert isinstance(resp, bytes)
                if req_type is ReqType.HEX and status == 200:
                    resp = bytes.fromhex(resp.decode().strip())
                return resp

            assert_equal(block_bin, get_block_part(query_params={"offset": 0, "size": len(block_bin)}))

            assert len(block_bin) >= 500
            assert_equal(block_bin[20:320], get_block_part(query_params={"offset": 20, "size": 300}))
            assert_equal(block_bin[-5:], get_block_part(query_params={"offset": len(block_bin) - 5, "size": 5}))

            get_block_part(status=400, query_params={"offset": 10})
            get_block_part(status=400, query_params={"size": 100})
            get_block_part(status=400, query_params={"offset": "x"})
            get_block_part(status=400, query_params={"size": "y"})
            get_block_part(status=400, query_params={"offset": "x", "size": "y"})
            assert get_block_part(status=400, query_params="%XY").decode("utf-8").startswith("URI parsing failed")

            get_block_part(status=400, query_params={"offset": 0, "size": 0})
            get_block_part(status=400, query_params={"offset": len(block_bin), "size": 0})
            get_block_part(status=400, query_params={"offset": len(block_bin), "size": 1})
            get_block_part(status=400, query_params={"offset": len(block_bin) + 1, "size": 1})
            get_block_part(status=400, query_params={"offset": 0, "size": len(block_bin) + 1})

        res = self.test_rest_request(f"/blockpart/{blockhash}", status=400, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        assert res.read().decode().startswith("Block part offset missing or invalid")

        res = self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset":0, "size":1}, status=400, req_type=ReqType.JSON, ret_type=RetType.OBJ)
        assert res.read().decode().startswith("JSON output is not supported for this request type")

        self.log.info("Missing block data should cause REST API to fail")

        self.test_rest_request(f"/block/{blockhash}", status=200, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset": 0, "size": 1}, status=200, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        blk_files = list(self.nodes[0].blocks_path.glob("blk*.dat"))
        for blk_file in blk_files:
            blk_file.rename(blk_file.with_suffix('.bkp'))
        self.test_rest_request(f"/block/{blockhash}", status=500, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset": 0, "size": 1}, status=500, req_type=ReqType.BIN, ret_type=RetType.OBJ)
        for blk_file in blk_files:
            blk_file.with_suffix('.bkp').rename(blk_file)

        self.log.info("Test the /deploymentinfo URI")

        deployment_info = self.nodes[0].getdeploymentinfo()
        assert_equal(deployment_info, self.test_rest_request('/deploymentinfo'))

        previous_bb_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount() - 1)
        deployment_info = self.nodes[0].getdeploymentinfo(previous_bb_hash)
        assert_equal(deployment_info, self.test_rest_request(f"/deploymentinfo/{previous_bb_hash}"))