Пример #1
0
    def test_failed_request2(self):
        """
        A request is "failed" if it throws an exception while executing.
        The exception should be forwarded to ALL waiting requests, which should re-raise it.
        """

        class CustomRuntimeError(RuntimeError):
            pass
        
        def impossible_workload():
            time.sleep(0.2)
            raise CustomRuntimeError("Can't service your request")
        
        impossible_req = Request(impossible_workload)

        def wait_for_impossible():
            # This request will fail...
            impossible_req.wait()

            # Since there are some exception guards in the code we're testing, 
            #  spit something out to stderr just to be sure this error 
            #  isn't getting swallowed accidentally.
            sys.stderr.write("ERROR: Shouldn't get here.")
            assert False, "Shouldn't get here."

        req1 = Request(wait_for_impossible)
        req2 = Request(wait_for_impossible)
        
        failed_ids = []
        lock = threading.Lock()
        def handle_failed_req(req_id, failure_exc):
            assert isinstance(failure_exc, CustomRuntimeError)
            with lock:
                failed_ids.append(req_id)
        
        req1.notify_failed( partial(handle_failed_req, 1) )
        req2.notify_failed( partial(handle_failed_req, 2) )
        
        req1.submit()
        req2.submit()

        try:
            req1.wait()
        except RuntimeError:
            pass
        else:
            assert False, "Expected an exception from that request, but didn't get it."

        try:
            req2.wait()
        except RuntimeError:
            pass
        else:
            assert False, "Expected an exception from that request, but didn't get it."

        assert 1 in failed_ids
        assert 2 in failed_ids
Пример #2
0
    def testExceptionPropagation(self):
        """
        When an exception is generated in a request, the exception should be propagated to all waiting threads.
        Also, the failure signal should fire.
        """
        class SpecialException(Exception):
            pass
        
        def always_fails():
            time.sleep(0.2)
            raise SpecialException()
        
        req1 = Request(always_fails)


        def wait_for_req1():
            req1.wait()
        
        req2 = Request(wait_for_req1)
        req3 = Request(wait_for_req1)

        signaled_exceptions = []
        def failure_handler(ex):
            signaled_exceptions.append(ex)
            
        req2.notify_failed( failure_handler )
        req3.notify_failed( failure_handler )

        caught_exceptions = []        
        def wait_for_request(req):        
            try:
                req.wait()
            except SpecialException as ex:
                caught_exceptions.append(ex)
            except:
                raise # Got some other exception than the one we expected
            else:
                assert "Expected to get an exception.  Didn't get one."

        th2 = threading.Thread( target=partial( wait_for_request, req2 ) )
        th3 = threading.Thread( target=partial( wait_for_request, req3 ) )
        
        th2.start()
        th3.start()
        
        th2.join()
        th3.join()
        
        assert len(caught_exceptions) == 2, "Expected both requests to catch exceptions."
        assert len(signaled_exceptions) == 2, "Expected both requests to signal failure."

        assert isinstance( caught_exceptions[0], SpecialException ), "Caught exception was of the wrong type."
        assert caught_exceptions[0] == caught_exceptions[1] == signaled_exceptions[0] == signaled_exceptions[1]
        
        # Attempting to wait for a request that has already failed will raise the exception that causes the failure
        wait_for_request(req2)
        
        # Subscribing to notify_failed on a request that's already failed should call the failure handler immediately.
        req2.notify_failed( failure_handler )
        assert len(signaled_exceptions) == 3