Fix RPC failure testing #9707

pull jnewbery wants to merge 1 commits into bitcoin:master from jnewbery:rpctestassert changing 2 files +21 −4
  1. jnewbery commented at 3:22 pm on February 7, 2017: member

    RPC interface testing should include failure test cases (ie where we call an RPC with parameters that we expect to fail). The failure test cases should follow this pattern:

    0try:
    1    nodes.rpcfunction(paramters,...) 
    2except JSONRPCException as exp: #(1) must only catch JSONRPCExceptions
    3    assert_equal(exp.error["code"], EXPECTED_ERROR_CODE)  #(2) must verify error code
    4    assert_equal(exp.error["message"], "Expected error message")  #(3) must verify error message
    5else:
    6    assert(False) #(4) must fail the test if no JSONRPCException raised
    

    Unfortunately, many of the test cases in qa/rpc-tests get this pattern wrong and don’t actually test what they’re supposed to.

    Exhibit A:

    0        try:
    1            self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
    2        except JSONRPCException as e:
    3            assert("Invalid address" not in e.error['message'])
    4            assert("ProcessNewBlock, block not accepted" not in e.error['message'])
    5            assert("Couldn't create new block" not in e.error['message'])
    

    The call to generatetoaddress() actually succeeds here, but there isn’t an else: clause so the test continues (and none of the code in the except: branch is executing)

    Exhibit B:

    0        try:
    1            tmpl = self.nodes[0].getblocktemplate({})
    2            assert(len(tmpl['transactions']) == 1)  # Doesn't include witness tx
    3            assert(tmpl['sigoplimit'] == 20000)
    4            assert(tmpl['transactions'][0]['hash'] == txid)
    5            assert(tmpl['transactions'][0]['sigops'] == 2)
    6            assert(('!segwit' in tmpl['rules']) or ('segwit' not in tmpl['rules']))
    7        except JSONRPCException:
    8            # This is an acceptable outcome
    9            pass
    

    The call to getblocktemplate() is raising an exception. Apparently This is an acceptable outcome, but there’s no explanation why. None of the asserts in the try: branch are being executed. There’s also no checking of the error code/message of the JSONRPCException.

    Exhibit C:

    0assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3])
    1#there must be a expection because the unconfirmed wallettx0 must be gone by now
    

    This is using the helper function assert_raises() and the comment explains that the call should fail because the unconfirmed transaction is gone. There’s no testing of the error message or code. In fact, gettransaction() is failing because it’s being called with an array [txid3] instead of a string txid3.

    This PR improves the assert_raises_jsonrpc() to verify error cause and error message and improves the commenting of that function. Future PRs will go over all the qa tests, remove the various broken implementations of this pattern and replace them with calls to assert_raises_jsonrpc().

    This should also prevent the same bugs from being introduced in future because it should now be easier to get this right (by calling assert_raises_jsonrpc()) than get it wrong (by trying to reimplement the pattern and failing)

  2. fanquake added the label Tests on Feb 7, 2017
  3. in qa/rpc-tests/test_framework/util.py: in cd1fb3691a outdated
    564+            in src/rpc/protocol.h). Set to None if checking the error code is not required.
    565+        message (string), optional: [a substring of] the error string returned by the
    566+            RPC call. Set to None if checking the error string is not required
    567+        fun (function): the function to call. This should be the name of an RPC.
    568+        args*: positional argumemts for the function.
    569+        kwargs**: named arguments for the function.
    


    paveljanik commented at 5:11 pm on February 7, 2017:
    kwds
  4. in qa/rpc-tests/test_framework/util.py: in cd1fb3691a outdated
    549@@ -550,13 +550,30 @@ def assert_raises_message(exc, message, fun, *args, **kwds):
    550     else:
    551         raise AssertionError("No exception raised")
    552 
    553-def assert_raises_jsonrpc(code, fun, *args, **kwds):
    554-    '''Check for specific JSONRPC exception code'''
    555+def assert_raises_jsonrpc(code, message, fun, *args, **kwds):
    556+    """Run an RPC and verify that a specific JSONRPC exception code and message is raised.
    557+
    558+    Calls function `fun` with arguments `args` and `kwargs`. Catches a JSONRPCException
    


    paveljanik commented at 5:12 pm on February 7, 2017:
    kwds?
  5. in qa/rpc-tests/test_framework/util.py: in cd1fb3691a outdated
    563+        code (int), optional: the error code returned by the RPC call (defined
    564+            in src/rpc/protocol.h). Set to None if checking the error code is not required.
    565+        message (string), optional: [a substring of] the error string returned by the
    566+            RPC call. Set to None if checking the error string is not required
    567+        fun (function): the function to call. This should be the name of an RPC.
    568+        args*: positional argumemts for the function.
    


    paveljanik commented at 5:13 pm on February 7, 2017:
    arguments
  6. paveljanik commented at 5:15 pm on February 7, 2017: contributor
    Concept ACK
  7. MarcoFalke commented at 5:23 pm on February 7, 2017: member

    Future PRs will go over all the qa tests, remove the various broken implementations of this pattern and replace them with calls to assert_raises_jsonrpc().

    Concept ACK

    This should also prevent the same bugs from being introduced in future because it should now be easier to get this right (by calling assert_raises_jsonrpc()) than get it wrong (by trying to reimplement the pattern and failing)

    Hmm, it would be still easy to get it wrong by ignoring (or not knowing) that assert_raises* exists. You can always type in a useless try stuff() except: pass.

    On Tue, Feb 7, 2017 at 4:22 PM, John Newbery notifications@github.com wrote:

    RPC interface testing should include failure test cases (ie where we call an RPC with parameters that we expect to fail). The failure test cases should follow this pattern:

    try: nodes.rpcfunction(paramters,…) except JSONRPCException as exp: #(1) must only catch JSONRPCExceptions assert_equal(exp.error[“code”], EXPECTED_ERROR_CODE) #(2) must verify error code assert_equal(exp.error[“message”], “Expected error message”) #(3) must verify error message else: assert(False) #(4) must fail the test if no JSONRPCException raised

    Unfortunately, many of the test cases in qa/rpc-tests get this pattern wrong and don’t actually test what they’re supposed to.

    Exhibit A:

        try:
            self.nodes[0].generatetoaddress(1,
    

    ‘mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ’) except JSONRPCException as e: assert(“Invalid address” not in e.error[‘message’]) assert(“ProcessNewBlock, block not accepted” not in e.error[‘message’]) assert(“Couldn’t create new block” not in e.error[‘message’])

    The call to generatetoaddress() actually succeeds here, but there isn’t an else: clause so the test continues (and none of the code in the except: branch is executing)

    Exhibit B:

        try:
            tmpl = self.nodes[0].getblocktemplate({})
            assert(len(tmpl['transactions']) == 1)  # Doesn't include
    

    witness tx assert(tmpl[‘sigoplimit’] == 20000) assert(tmpl[’transactions’][0][‘hash’] == txid) assert(tmpl[’transactions’][0][‘sigops’] == 2) assert((’!segwit’ in tmpl[‘rules’]) or (‘segwit’ not in tmpl[‘rules’])) except JSONRPCException: # This is an acceptable outcome pass

    The call to getblocktemplate() is raising an exception. Apparently This is an acceptable outcome, but there’s no explanation why. None of the asserts in the try: branch are being executed. There’s also no checking of the error code/message of the JSONRPCException.

    Exhibit C:

    assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3]) #there must be a expection because the unconfirmed wallettx0 must be gone by now

    This is using the helper function assert_raises() and the comment explains that the call should fail because the unconfirmed transaction is gone. There’s no testing of the error message or code. In fact, gettransaction() is failing because it’s being called with an array [txid3] instead of a string txid3.

    This PR improves the assert_raises_jsonrpc() to verify error cause and error message and improves the commenting of that function. Future PRs will go over all the qa tests, remove the various broken implementations of this pattern and replace them with calls to assert_raises_jsonrpc().

    This should also prevent the same bugs from being introduced in future because it should now be easier to get this right (by calling assert_raises_jsonrpc()) than get it wrong (by trying to reimplement the pattern and failing)


    You can view, comment on, or merge this pull request online at:

    #9707

    Commit Summary

    Fix RPC failure testing

    File Changes

    M qa/rpc-tests/rpcnamedargs.py (2) M qa/rpc-tests/test_framework/util.py (23)

    Patch Links:

    #9707.patch #9707.diff

    — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

  8. jnewbery commented at 5:34 pm on February 7, 2017: member

    it would be still easy to get it wrong by ignoring (or not knowing) that assert_raises* exists

    Indeed. There’s no way to stop people from doing this again in future. I think the best we can hope for is to remove all existing cases where try/except has been used explicitly in individual testcases for JSON RPC error testing. When people come to write new testcases and copy the existing ones, they see the assert_raises* functions being used.

  9. jnewbery force-pushed on Feb 7, 2017
  10. jnewbery commented at 5:44 pm on February 7, 2017: member
    Thanks @paveljanik - all typos fixed
  11. MarcoFalke commented at 5:52 pm on February 7, 2017: member

    ACK, but could you replace it with if code is not None, so that 0, False, etc does not equal a wild card for code or message.

    On Tue, Feb 7, 2017 at 6:44 PM, John Newbery notifications@github.com wrote:

    Thanks @paveljanik https://github.com/paveljanik - all typos fixed

    — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bitcoin/bitcoin/pull/9707#issuecomment-278079944, or mute the thread https://github.com/notifications/unsubscribe-auth/AGGmv-JGLqS-4fvVmfE4CJE7nti8UutGks5raK17gaJpZM4L5oD0 .

  12. jnewbery force-pushed on Feb 7, 2017
  13. jnewbery commented at 6:03 pm on February 7, 2017: member
    @MarcoFalke done. It now explicitly tests code and message for not being None.
  14. Fix RPC failure testing
    Make sure that RPC tests are actually checking failures correctly by:
    
    - Catching JSON RPC exceptions and verifying the error codes and messages.
    - Failing the test case if the JSON RPC exception isn't raised.
    9db8eecac1
  15. jnewbery force-pushed on Feb 8, 2017
  16. jnewbery commented at 3:25 pm on February 8, 2017: member
    On @TheBlueMatt’s suggestion in #9713, I’ve added a new commit that removes the assert_raises() and assert_raises_message() functions.
  17. jnewbery force-pushed on Feb 8, 2017
  18. jnewbery commented at 6:18 pm on February 8, 2017: member
    Actually, on second thoughts I’ll save removing assert_raises() and assert_raises_message() for a future PR.
  19. TheBlueMatt commented at 4:49 pm on February 10, 2017: member
    OK, sounds good. utACK 9db8eecac1c713c760c0217b6acb7455c657fa8b
  20. jnewbery commented at 4:53 pm on February 10, 2017: member
    Thanks @TheBlueMatt. @MarcoFalke any chance of merging this small PR? I have a lot of fixes that build off this so it’d be good to have this merged into master.
  21. MarcoFalke added the label Refactoring on Feb 10, 2017
  22. MarcoFalke commented at 5:00 pm on February 10, 2017: member
    utACK 9db8eecac1c713c760c0217b6acb7455c657fa8b. This is refactoring, so can go into 0.14.
  23. MarcoFalke merged this on Feb 10, 2017
  24. MarcoFalke closed this on Feb 10, 2017

  25. MarcoFalke referenced this in commit b860915f8b on Feb 10, 2017
  26. jnewbery commented at 5:42 pm on February 10, 2017: member
    awsome. Thanks @MarcoFalke
  27. jnewbery deleted the branch on Feb 10, 2017
  28. jtimon commented at 5:54 pm on March 7, 2017: contributor
    late utACK 9db8eec
  29. MarcoFalke referenced this in commit 598ef9c44b on Mar 16, 2017
  30. MarcoFalke referenced this in commit c63364610f on Oct 9, 2017
  31. codablock referenced this in commit 0757ee03dd on Jan 19, 2018
  32. codablock referenced this in commit 8043468b3f on Jan 23, 2018
  33. PastaPastaPasta referenced this in commit 8baa01557f on Jan 2, 2019
  34. PastaPastaPasta referenced this in commit f755b61918 on Jan 2, 2019
  35. PastaPastaPasta referenced this in commit 3d50098051 on Jan 2, 2019
  36. PastaPastaPasta referenced this in commit 6bd7fb56b2 on Jan 3, 2019
  37. andvgal referenced this in commit b9282d87d4 on Jan 6, 2019
  38. PastaPastaPasta referenced this in commit 4655f69938 on Jan 21, 2019
  39. PastaPastaPasta referenced this in commit c4736b6f57 on Jan 29, 2019
  40. CryptoCentric referenced this in commit 36e8042fe6 on Feb 27, 2019
  41. PastaPastaPasta referenced this in commit a8aaa0ba89 on Mar 10, 2019
  42. PastaPastaPasta referenced this in commit fc1878bca3 on Mar 10, 2019
  43. PastaPastaPasta referenced this in commit 97bcbff227 on Mar 11, 2019
  44. PastaPastaPasta referenced this in commit 3c5707fb00 on Mar 11, 2019
  45. PastaPastaPasta referenced this in commit 7b0da09fc4 on Mar 12, 2019
  46. PastaPastaPasta referenced this in commit 9c5233dd39 on Mar 13, 2019
  47. UdjinM6 referenced this in commit a16144ee23 on Mar 13, 2019
  48. PastaPastaPasta referenced this in commit effc8bffd7 on Mar 13, 2019
  49. PastaPastaPasta referenced this in commit ef74ded65d on Mar 14, 2019
  50. PastaPastaPasta referenced this in commit 0b8012bd55 on Mar 14, 2019
  51. PastaPastaPasta referenced this in commit 8af32ca017 on Mar 15, 2019
  52. PastaPastaPasta referenced this in commit 0005b68c69 on Mar 16, 2019
  53. PastaPastaPasta referenced this in commit 39560b42d0 on Apr 3, 2019
  54. PastaPastaPasta referenced this in commit 319f4a63b9 on Apr 3, 2019
  55. PastaPastaPasta referenced this in commit c825949e0c on Apr 5, 2019
  56. PastaPastaPasta referenced this in commit 5ae202da96 on May 6, 2019
  57. barrystyle referenced this in commit 2688d58dff on Jan 22, 2020
  58. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-19 03:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me