Пример #1
0
  def test_transitive_params(self):
    # Test that C can be provided and implicitly converted into a B with transitive_b_c() to satisfy
    # the selectors of consumes_a_and_b().
    a, c = A(), C()
    result_str, = self.scheduler.product_request(str, [Params(a, c)])
    self.assertEquals(remove_locations_from_traceback(result_str),
                      remove_locations_from_traceback(consumes_a_and_b(a, transitive_b_c(c))))

    # Test that an inner Get in transitive_coroutine_rule() is able to resolve B from C due to the
    # existence of transitive_b_c().
    result_d, = self.scheduler.product_request(D, [Params(c)])
    # We don't need the inner B objects to be the same, and we know the arguments are type-checked,
    # we're just testing transitively resolving products in this file.
    self.assertTrue(isinstance(result_d, D))
Пример #2
0
  def test_transitive_params(self):
    # Test that C can be provided and implicitly converted into a B with transitive_b_c() to satisfy
    # the selectors of consumes_a_and_b().
    a, c = A(), C()
    result_str, = self.scheduler.product_request(str, [Params(a, c)])
    self.assertEquals(remove_locations_from_traceback(result_str),
                      remove_locations_from_traceback(consumes_a_and_b(a, transitive_b_c(c))))

    # Test that an inner Get in transitive_coroutine_rule() is able to resolve B from C due to the
    # existence of transitive_b_c().
    result_d, = self.scheduler.product_request(D, [Params(c)])
    # We don't need the inner B objects to be the same, and we know the arguments are type-checked,
    # we're just testing transitively resolving products in this file.
    self.assertTrue(isinstance(result_d, D))
Пример #3
0
    def test_trace_includes_rule_exception_traceback(self):
        rules = [
            RootRule(B),
            nested_raise,
        ]

        scheduler = create_scheduler(rules)
        request = scheduler._native.new_execution_request()
        subject = B()
        scheduler.add_root_selection(request, subject, A)
        session = scheduler.new_session()
        scheduler._run_and_return_roots(session._session, request)

        trace = '\n'.join(scheduler.graph_trace(request))
        # NB removing location info to make trace repeatable
        trace = remove_locations_from_traceback(trace)

        assert_equal_with_printing(
            self,
            dedent('''
                     Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A)
                       Computing Task(nested_raise(), <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A, true)
                         Throw(An exception for B)
                           Traceback (most recent call last):
                             File LOCATION-INFO, in call
                               val = func(*args)
                             File LOCATION-INFO, in nested_raise
                               fn_raises(x)
                             File LOCATION-INFO, in fn_raises
                               raise Exception('An exception for {}'.format(type(x).__name__))
                           Exception: An exception for B''').lstrip() +
            '\n\n',  # Traces include two empty lines after.
            trace)
Пример #4
0
  def test_include_trace_error_raises_error_with_trace(self):
    rules = [
      RootRule(B),
      TaskRule(A, [Select(B)], nested_raise)
    ]

    scheduler = self.scheduler(rules, include_trace_on_error=True)
    with self.assertRaises(Exception) as cm:
      list(scheduler.product_request(A, subjects=[(B())]))

    self.assert_equal_with_printing(dedent('''
      Received unexpected Throw state(s):
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
        Computing Task(<function nested_raise at 0xEEEEEEEEE>, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
          Throw(An exception for B)
            Traceback (most recent call last):
              File LOCATION-INFO, in extern_invoke_runnable
                val = runnable(*args)
              File LOCATION-INFO, in nested_raise
                fn_raises(x)
              File LOCATION-INFO, in fn_raises
                raise Exception('An exception for {}'.format(type(x).__name__))
            Exception: An exception for B
      ''').lstrip()+'\n',
      remove_locations_from_traceback(str(cm.exception)))
Пример #5
0
  def test_trace_does_not_include_cancellations(self):
    # Tests that when the computation of `Select(C)` fails, the cancellation of `Select(D)`
    # is not rendered as a failure.
    rules = [
      RootRule(B),
      TaskRule(D, [Select(B)], D),
      TaskRule(C, [Select(B)], nested_raise),
      TaskRule(A, [Select(C), Select(D)], A),
    ]

    scheduler = self.scheduler(rules, include_trace_on_error=True)
    with self.assertRaises(Exception) as cm:
      list(scheduler.product_request(A, subjects=[(B())]))

    self.assert_equal_with_printing(dedent('''
      Received unexpected Throw state(s):
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
        Computing Task(<class 'pants_test.engine.test_engine.A'>, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
          Computing Task(<function nested_raise at 0xEEEEEEEEE>, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =C)
            Throw(An exception for B)
              Traceback (most recent call last):
                File LOCATION-INFO, in call
                  val = func(*args)
                File LOCATION-INFO, in nested_raise
                  fn_raises(x)
                File LOCATION-INFO, in fn_raises
                  raise Exception('An exception for {}'.format(type(x).__name__))
              Exception: An exception for B
      ''').lstrip()+'\n',
      remove_locations_from_traceback(str(cm.exception)))
Пример #6
0
  def test_include_trace_error_raises_error_with_trace(self):
    rules = [
      RootRule(B),
      nested_raise,
    ]

    scheduler = self.scheduler(rules, include_trace_on_error=True)
    with self.assertRaises(ExecutionError) as cm:
      list(scheduler.product_request(A, subjects=[(B())]))

    self.assert_equal_with_printing(dedent('''
      1 Exception encountered:
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A)
        Computing Task(nested_raise(), <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A, true)
          Throw(An exception for B)
            Traceback (most recent call last):
              File LOCATION-INFO, in call
                val = func(*args)
              File LOCATION-INFO, in nested_raise
                fn_raises(x)
              File LOCATION-INFO, in fn_raises
                raise Exception('An exception for {}'.format(type(x).__name__))
            Exception: An exception for B
      ''').lstrip()+'\n',
      remove_locations_from_traceback(str(cm.exception)))
Пример #7
0
  def test_trace_includes_rule_exception_traceback(self):
    rules = [
      RootRule(B),
      TaskRule(A, [Select(B)], nested_raise)
    ]

    scheduler = create_scheduler(rules)
    request = scheduler._native.new_execution_request()
    subject = B()
    scheduler.add_root_selection(request, subject, A)
    session = scheduler.new_session()
    scheduler._run_and_return_roots(session._session, request)

    trace = '\n'.join(scheduler.graph_trace(request))
    # NB removing location info to make trace repeatable
    trace = remove_locations_from_traceback(trace)

    assert_equal_with_printing(self, dedent('''
                     Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                       Computing Task(nested_raise, <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                         Throw(An exception for B)
                           Traceback (most recent call last):
                             File LOCATION-INFO, in call
                               val = func(*args)
                             File LOCATION-INFO, in nested_raise
                               fn_raises(x)
                             File LOCATION-INFO, in fn_raises
                               raise Exception('An exception for {}'.format(type(x).__name__))
                           Exception: An exception for B''').lstrip() + '\n\n', # Traces include two empty lines after.
                               trace)
Пример #8
0
    def test_trace_includes_rule_exception_traceback(self):
        rules = [TaskRule(A, [Select(B)], nested_raise)]

        scheduler = create_native_scheduler({B}, rules)
        subject = B()
        scheduler.add_root_selection(subject, Select(A))
        scheduler.run_and_return_stat()

        trace = '\n'.join(scheduler.graph_trace())
        # NB removing location info to make trace repeatable
        trace = remove_locations_from_traceback(trace)

        assert_equal_with_printing(
            self,
            dedent('''
                     Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                       Computing Task(<function nested_raise at 0xEEEEEEEEE>, <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                         Throw(An exception for B)
                           Traceback (most recent call last):
                             File LOCATION-INFO, in extern_invoke_runnable
                               val = runnable(*args)
                             File LOCATION-INFO, in nested_raise
                               fn_raises(x)
                             File LOCATION-INFO, in fn_raises
                               raise Exception('An exception for {}'.format(type(x).__name__))
                           Exception: An exception for B''').lstrip() +
            '\n\n',  # Traces include two empty lines after.
            trace)
Пример #9
0
  def test_trace_includes_rule_exception_traceback(self):
    rules = [
      TaskRule(A, [Select(B)], nested_raise)
    ]

    scheduler = create_native_scheduler({B}, rules)
    subject = B()
    scheduler.add_root_selection(subject, Select(A))
    scheduler.run_and_return_stat()

    trace = '\n'.join(scheduler.graph_trace())
    # NB removing location info to make trace repeatable
    trace = remove_locations_from_traceback(trace)

    assert_equal_with_printing(self, dedent('''
                     Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                       Computing Task(<function nested_raise at 0xEEEEEEEEE>, <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, =A)
                         Throw(An exception for B)
                           Traceback (most recent call last):
                             File LOCATION-INFO, in extern_invoke_runnable
                               val = runnable(*args)
                             File LOCATION-INFO, in nested_raise
                               fn_raises(x)
                             File LOCATION-INFO, in fn_raises
                               raise Exception('An exception for {}'.format(type(x).__name__))
                           Exception: An exception for B''').lstrip() + '\n\n', # Traces include two empty lines after.
                               trace)
Пример #10
0
  def test_trace_multi(self):
    # Tests that when multiple distinct failures occur, they are each rendered.

    @rule(D, [B])
    def d_from_b_nested_raise(b):
      fn_raises(b)

    @rule(C, [B])
    def c_from_b_nested_raise(b):
      fn_raises(b)

    @rule(A, [C, D])
    def a_from_c_and_d(c, d):
      return A()

    rules = [
      RootRule(B),
      d_from_b_nested_raise,
      c_from_b_nested_raise,
      a_from_c_and_d,
    ]

    scheduler = self.scheduler(rules, include_trace_on_error=True)
    with self.assertRaises(ExecutionError) as cm:
      list(scheduler.product_request(A, subjects=[(B())]))

    self.assert_equal_with_printing(dedent('''
      1 Exception encountered:
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A)
        Computing Task(a_from_c_and_d(), <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A, true)
          Computing Task(d_from_b_nested_raise(), <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =D, true)
            Throw(An exception for B)
              Traceback (most recent call last):
                File LOCATION-INFO, in call
                  val = func(*args)
                File LOCATION-INFO, in d_from_b_nested_raise
                  fn_raises(b)
                File LOCATION-INFO, in fn_raises
                  raise Exception('An exception for {}'.format(type(x).__name__))
              Exception: An exception for B


      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A)
        Computing Task(a_from_c_and_d(), <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, A, true)
          Computing Task(c_from_b_nested_raise(), <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =C, true)
            Throw(An exception for B)
              Traceback (most recent call last):
                File LOCATION-INFO, in call
                  val = func(*args)
                File LOCATION-INFO, in c_from_b_nested_raise
                  fn_raises(b)
                File LOCATION-INFO, in fn_raises
                  raise Exception('An exception for {}'.format(type(x).__name__))
              Exception: An exception for B
      ''').lstrip()+'\n',
      remove_locations_from_traceback(str(cm.exception)))
Пример #11
0
  def test_trace_multi(self):
    # Tests that when multiple distinct failures occur, they are each rendered.
    rules = [
      RootRule(B),
      TaskRule(D, [Select(B)], nested_raise),
      TaskRule(C, [Select(B)], nested_raise),
      TaskRule(A, [Select(C), Select(D)], A),
    ]

    scheduler = self.scheduler(rules, include_trace_on_error=True)
    with self.assertRaises(ExecutionError) as cm:
      list(scheduler.product_request(A, subjects=[(B())]))

    self.assert_equal_with_printing(dedent('''
      1 Exception encountered:
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
        Computing Task(A, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
          Computing Task(nested_raise, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =D)
            Throw(An exception for B)
              Traceback (most recent call last):
                File LOCATION-INFO, in call
                  val = func(*args)
                File LOCATION-INFO, in nested_raise
                  fn_raises(x)
                File LOCATION-INFO, in fn_raises
                  raise Exception('An exception for {}'.format(type(x).__name__))
              Exception: An exception for B


      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
        Computing Task(A, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
          Computing Task(nested_raise, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =C)
            Throw(An exception for B)
              Traceback (most recent call last):
                File LOCATION-INFO, in call
                  val = func(*args)
                File LOCATION-INFO, in nested_raise
                  fn_raises(x)
                File LOCATION-INFO, in fn_raises
                  raise Exception('An exception for {}'.format(type(x).__name__))
              Exception: An exception for B
      ''').lstrip()+'\n',
      remove_locations_from_traceback(str(cm.exception)))
Пример #12
0
  def test_trace_includes_rule_exception_traceback(self):
    # Execute a request that will trigger the nested raise, and then directly inspect its trace.
    request = self.scheduler.execution_request([A], [B()])
    self.scheduler.execute(request)

    trace = remove_locations_from_traceback('\n'.join(self.scheduler.trace(request)))
    assert_equal_with_printing(self, dedent('''
                     Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A)
                       Computing Task(nested_raise(), <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A, true)
                         Throw(An exception for B)
                           Traceback (most recent call last):
                             File LOCATION-INFO, in call
                               val = func(*args)
                             File LOCATION-INFO, in nested_raise
                               fn_raises(x)
                             File LOCATION-INFO, in fn_raises
                               raise Exception('An exception for {}'.format(type(x).__name__))
                           Exception: An exception for B''').lstrip() + '\n\n', # Traces include two empty lines after.
                               trace)
Пример #13
0
 def test_trace_includes_rule_exception_traceback(self):
   # Execute a request that will trigger the nested raise, and then directly inspect its trace.
   request = self.scheduler.execution_request([A], [B()])
   self.scheduler.execute(request)
   
   trace = remove_locations_from_traceback('\n'.join(self.scheduler.trace(request)))
   assert_equal_with_printing(self, dedent('''
                    Computing Select(<pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A)
                      Computing Task(nested_raise(), <pants_test.engine.test_scheduler.B object at 0xEEEEEEEEE>, A, true)
                        Throw(An exception for B)
                          Traceback (most recent call last):
                            File LOCATION-INFO, in call
                              val = func(*args)
                            File LOCATION-INFO, in nested_raise
                              fn_raises(x)
                            File LOCATION-INFO, in fn_raises
                              raise Exception('An exception for {}'.format(type(x).__name__))
                          Exception: An exception for B''').lstrip() + '\n\n', # Traces include two empty lines after.
                              trace)
Пример #14
0
    def test_include_trace_error_raises_error_with_trace(self):
        rules = [RootRule(B), TaskRule(A, [Select(B)], nested_raise)]

        scheduler = self.scheduler(rules, include_trace_on_error=True)
        with self.assertRaises(Exception) as cm:
            list(scheduler.product_request(A, subjects=[(B())]))

        self.assert_equal_with_printing(
            dedent('''
      Received unexpected Throw state(s):
      Computing Select(<pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
        Computing Task(<function nested_raise at 0xEEEEEEEEE>, <pants_test.engine.test_engine.B object at 0xEEEEEEEEE>, =A)
          Throw(An exception for B)
            Traceback (most recent call last):
              File LOCATION-INFO, in extern_invoke_runnable
                val = runnable(*args)
              File LOCATION-INFO, in nested_raise
                fn_raises(x)
              File LOCATION-INFO, in fn_raises
                raise Exception('An exception for {}'.format(type(x).__name__))
            Exception: An exception for B
      ''').lstrip() + '\n', remove_locations_from_traceback(str(cm.exception)))
Пример #15
0
  def test_unhashable_failure(self):
    """Test that unhashable Get(...) params result in a structured error."""

    def assert_has_cffi_extern_traceback_header(exc_str):
      self.assertTrue(exc_str.startswith(dedent("""\
        1 Exception raised in CFFI extern methods:
        Traceback (most recent call last):
        """)), "exc_str was: {}".format(exc_str))

    def assert_has_end_of_cffi_extern_error_traceback(exc_str):
      self.assertIn(dedent("""\
        Traceback (most recent call last):
          File LOCATION-INFO, in extern_identify
            return c.identify(obj)
          File LOCATION-INFO, in identify
            hash_ = hash(obj)
          File LOCATION-INFO, in __hash__
            .format(self, type(self).__name__, field_name, e))
        TypeError: For datatype object CollectionType(items=[1, 2, 3]) (type 'CollectionType'): in field 'items': unhashable type: 'list'
        """), exc_str, "exc_str was: {}".format(exc_str))

    resulting_engine_error = "Exception: No installed @rules can satisfy Select(C) for input Params(Any).\n\n\n"

    # Test that the error contains the full traceback from within the CFFI context as well
    # (mentioning which specific extern method ended up raising the exception).
    with self.assertRaises(ExecutionError) as cm:
      self.scheduler.product_request(C, [Params(CollectionType([1, 2, 3]))])
    exc_str = remove_locations_from_traceback(str(cm.exception))
    # TODO: convert these manual self.assertTrue() conditionals to a self.assertStartsWith() method
    # in TestBase!
    assert_has_cffi_extern_traceback_header(exc_str)
    assert_has_end_of_cffi_extern_error_traceback(exc_str)
    self.assertIn(dedent("""\
      The engine execution request raised this error, which is probably due to the errors in the
      CFFI extern methods listed above, as CFFI externs return None upon error:
      """), exc_str)
    self.assertTrue(exc_str.endswith(resulting_engine_error), "exc_str was: {}".format(exc_str))

    PATCH_OPTS = dict(autospec=True, spec_set=True)
    def create_cffi_exception():
      try:
        raise Exception('test cffi exception')
      except:                   # noqa: T803
        return Native.CFFIExternMethodRuntimeErrorInfo(*sys.exc_info()[0:3])

    # Test that CFFI extern method errors result in an ExecutionError, even if .execution_request()
    # succeeds.
    with self.assertRaises(ExecutionError) as cm:
      with mock.patch.object(SchedulerSession, 'execution_request',
                             **PATCH_OPTS) as mock_exe_request:
        with mock.patch.object(Native, 'cffi_extern_method_runtime_exceptions',
                               **PATCH_OPTS) as mock_cffi_exceptions:
          mock_exe_request.return_value = None
          mock_cffi_exceptions.return_value = [create_cffi_exception()]
          self.scheduler.product_request(C, [Params(CollectionType([1, 2, 3]))])
    exc_str = remove_locations_from_traceback(str(cm.exception))
    assert_has_cffi_extern_traceback_header(exc_str)
    self.assertIn("Exception: test cffi exception", exc_str)
    self.assertNotIn(resulting_engine_error, exc_str)

    # Test that an error in the .execution_request() method is propagated directly, even if there
    # are no CFFI extern methods.
    class TestError(Exception): pass
    with self.assertRaisesWithMessage(TestError, 'non-CFFI error'):
      with mock.patch.object(SchedulerSession, 'execution_request',
                             **PATCH_OPTS) as mock_exe_request:
        mock_exe_request.side_effect = TestError('non-CFFI error')
        self.scheduler.product_request(C, [Params(CollectionType([1, 2, 3]))])
Пример #16
0
def assert_execution_error(test_case, expected_msg):
  with test_case.assertRaises(ExecutionError) as cm:
    yield
  test_case.assertIn(expected_msg, remove_locations_from_traceback(str(cm.exception)))
Пример #17
0
def assert_execution_error(test_case, expected_msg):
    with test_case.assertRaises(ExecutionError) as cm:
        yield
    test_case.assertIn(expected_msg,
                       remove_locations_from_traceback(str(cm.exception)))
Пример #18
0
 def _assert_execution_error(self, expected_msg):
     with self.assertRaises(ExecutionError) as cm:
         yield
     self.assertIn(expected_msg,
                   remove_locations_from_traceback(str(cm.exception)))
Пример #19
0
    def test_unhashable_failure(self):
        """Test that unhashable Get(...) params result in a structured error."""
        def assert_has_cffi_extern_traceback_header(exc_str):
            self.assertTrue(
                exc_str.startswith(
                    dedent("""\
        1 Exception raised in CFFI extern methods:
        Traceback (most recent call last):
        """)), "exc_str was: {}".format(exc_str))

        def assert_has_end_of_cffi_extern_error_traceback(exc_str):
            self.assertIn(
                dedent("""\
        Traceback (most recent call last):
          File LOCATION-INFO, in extern_identify
            return c.identify(obj)
          File LOCATION-INFO, in identify
            hash_ = hash(obj)
          File LOCATION-INFO, in __hash__
            .format(self, type(self).__name__, field_name, e))
        TypeError: For datatype object CollectionType(items=[1, 2, 3]) (type 'CollectionType'): in field 'items': unhashable type: 'list'
        """), exc_str, "exc_str was: {}".format(exc_str))

        resulting_engine_error = "Exception: No installed @rules can compute C for input Params(Any).\n\n\n"

        # Test that the error contains the full traceback from within the CFFI context as well
        # (mentioning which specific extern method ended up raising the exception).
        with self.assertRaises(ExecutionError) as cm:
            self.scheduler.product_request(C,
                                           [Params(CollectionType([1, 2, 3]))])
        exc_str = remove_locations_from_traceback(str(cm.exception))
        # TODO: convert these manual self.assertTrue() conditionals to a self.assertStartsWith() method
        # in TestBase!
        assert_has_cffi_extern_traceback_header(exc_str)
        assert_has_end_of_cffi_extern_error_traceback(exc_str)
        self.assertIn(
            dedent("""\
      The engine execution request raised this error, which is probably due to the errors in the
      CFFI extern methods listed above, as CFFI externs return None upon error:
      """), exc_str)
        self.assertTrue(exc_str.endswith(resulting_engine_error),
                        "exc_str was: {}".format(exc_str))

        PATCH_OPTS = dict(autospec=True, spec_set=True)

        def create_cffi_exception():
            try:
                raise Exception('test cffi exception')
            except:  # noqa: T803
                return Native.CFFIExternMethodRuntimeErrorInfo(
                    *sys.exc_info()[0:3])

        # Test that CFFI extern method errors result in an ExecutionError, even if .execution_request()
        # succeeds.
        with self.assertRaises(ExecutionError) as cm:
            with unittest.mock.patch.object(SchedulerSession,
                                            'execution_request',
                                            **PATCH_OPTS) as mock_exe_request:
                with unittest.mock.patch.object(
                        Native, 'cffi_extern_method_runtime_exceptions',
                        **PATCH_OPTS) as mock_cffi_exceptions:
                    mock_exe_request.return_value = None
                    mock_cffi_exceptions.return_value = [
                        create_cffi_exception()
                    ]
                    self.scheduler.product_request(
                        C, [Params(CollectionType([1, 2, 3]))])
        exc_str = remove_locations_from_traceback(str(cm.exception))
        assert_has_cffi_extern_traceback_header(exc_str)
        self.assertIn("Exception: test cffi exception", exc_str)
        self.assertNotIn(resulting_engine_error, exc_str)

        # Test that an error in the .execution_request() method is propagated directly, even if there
        # are no CFFI extern methods.
        class TestError(Exception):
            pass

        with self.assertRaisesWithMessage(TestError, 'non-CFFI error'):
            with unittest.mock.patch.object(SchedulerSession,
                                            'execution_request',
                                            **PATCH_OPTS) as mock_exe_request:
                mock_exe_request.side_effect = TestError('non-CFFI error')
                self.scheduler.product_request(
                    C, [Params(CollectionType([1, 2, 3]))])