Пример #1
0
  def testCallsFunctionEveryTimeWhenMinTimeBetweenCallsZero(self):
    decorated = cache.WithLimitedCallFrequency(rdfvalue.Duration(0))(
        self.mock_fn)
    for _ in range(10):
      decorated()

    self.assertEqual(self.mock_fn.call_count, 10)
Пример #2
0
  def testDecoratedFunctionsAreWaitedForPerArguments(self):
    event = threading.Event()

    def Fn(x):
      if x != 42:
        event.wait()
      return x

    mock_fn = mock.Mock(wraps=Fn)
    compatibility.SetName(mock_fn, "foo")  # Expected by functools.wraps.

    decorated = cache.WithLimitedCallFrequency(
        rdfvalue.Duration.From(30, rdfvalue.SECONDS))(
            mock_fn)

    def T():
      decorated(1)

    t = threading.Thread(target=T)
    t.start()
    try:

      # This should return immediately. There's another function call
      # in progress, but with different arguments, so no locking should occur.
      # I.e. decorated(1) and decorated(42) shouldn't influence each other.
      decorated(42)

    finally:
      event.set()
      t.join()

    self.assertEqual(mock_fn.call_count, 2)
Пример #3
0
    def testPropagatesExceptions(self):
        mock_fn = mock.Mock(side_effect=ValueError())
        compatibility.SetName(mock_fn, "foo")  # Expected by functools.wraps.

        decorated = cache.WithLimitedCallFrequency(
            rdfvalue.Duration.From(30, rdfvalue.SECONDS))(mock_fn)

        with self.assertRaises(ValueError):
            decorated()
Пример #4
0
    def testExceptionIsNotCached(self):
        mock_fn = mock.Mock(side_effect=ValueError())
        compatibility.SetName(mock_fn, "foo")  # Expected by functools.wraps.

        decorated = cache.WithLimitedCallFrequency(
            rdfvalue.Duration.From(30, rdfvalue.SECONDS))(mock_fn)

        for _ in range(10):
            with self.assertRaises(ValueError):
                decorated()

        self.assertEqual(mock_fn.call_count, 10)
Пример #5
0
    def testCallsFunctionOnceInGivenTimeRangeWhenMinTimeBetweenCallsNonZero(
            self):
        decorated = cache.WithLimitedCallFrequency(
            rdfvalue.DurationSeconds("30s"))(self.mock_fn)

        now = rdfvalue.RDFDatetime.Now()
        with test_lib.FakeTime(now):
            r1 = decorated()

        with test_lib.FakeTime(now + rdfvalue.DurationSeconds("15s")):
            r2 = decorated()

        self.assertEqual(r1, r2)
        self.assertEqual(self.mock_fn.call_count, 1)

        with test_lib.FakeTime(now + rdfvalue.DurationSeconds("30s")):
            r3 = decorated()

        self.assertNotEqual(r1, r3)
        self.assertEqual(self.mock_fn.call_count, 2)
Пример #6
0
    def testDecoratedFunctionIsNotExecutedConcurrently(self):
        event = threading.Event()

        # Can't rely on mock's call_count as it's not thread safe.
        fn_calls = []

        def Fn():
            fn_calls.append(True)
            event.wait()
            return self.mock_fn()

        decorated = cache.WithLimitedCallFrequency(
            rdfvalue.Duration.From(30, rdfvalue.SECONDS))(Fn)

        results = []

        def T():
            results.append(decorated())

        threads = []
        for _ in range(10):
            t = threading.Thread(target=T)
            t.start()
            threads.append(t)

        # At this point all threads should be waiting on the function to complete,
        # with only 1 threads actually executing the function. Trigger the event
        # to force that one thread to complete.
        event.set()

        for t in threads:
            t.join()

        self.assertLen(results, len(threads))
        self.assertEqual(set(results), set([results[0]]))
        self.assertLen(fn_calls, 1)