Exemple #1
0
    def test_get_process_auth_db_exceptions(self):
        """Ensure get_process_auth_db() handles DB exceptions well."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make process cache expire.
        self.set_time(api.get_process_cache_expiration_sec() + 1)

        # Emulate an exception in fetch_auth_db.
        def mock_fetch_auth_db(*_kwargs):
            raise Exception("Boom!")

        self.mock(api, "fetch_auth_db", mock_fetch_auth_db)

        # Capture calls to logging.exception.
        logger_calls = []
        self.mock(api.logging, "exception", lambda *_args: logger_calls.append(1))

        # Should return older copy of auth_db_v0 and log the exception.
        self.assertEqual(auth_db_v0, api.get_process_auth_db())
        self.assertEqual(1, len(logger_calls))

        # Make fetch_auth_db to work again. Verify get_process_auth_db() works too.
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #2
0
    def test_get_process_auth_db_exceptions(self):
        """Ensure get_process_auth_db() handles DB exceptions well."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make process cache expire.
        self.set_time(api.get_process_cache_expiration_sec() + 1)

        # Emulate an exception in fetch_auth_db.
        def mock_fetch_auth_db(*_kwargs):
            raise Exception('Boom!')

        self.mock(api, 'fetch_auth_db', mock_fetch_auth_db)

        # Capture calls to logging.exception.
        logger_calls = []
        self.mock(api.logging, 'exception',
                  lambda *_args: logger_calls.append(1))

        # Should return older copy of auth_db_v0 and log the exception.
        self.assertEqual(auth_db_v0, api.get_process_auth_db())
        self.assertEqual(1, len(logger_calls))

        # Make fetch_auth_db to work again. Verify get_process_auth_db() works too.
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #3
0
    def test_get_process_auth_db_multithreading(self):
        """Ensure get_process_auth_db() plays nice with multiple threads."""

        def run_in_thread(func):
            """Runs |func| in a parallel thread, returns future (as Queue)."""
            result = Queue.Queue()
            thread = threading.Thread(target=lambda: result.put(func()))
            thread.start()
            return result

        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Run initial fetch, should cache |auth_db_v0| in process cache.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make process cache expire.
        self.set_time(api.get_process_cache_expiration_sec() + 1)

        # Start fetching AuthDB from another thread, at some point it will call
        # 'fetch_auth_db', and we pause the thread then and resume main thread.
        fetching_now = threading.Event()
        auth_db_queue = Queue.Queue()

        def mock_fetch_auth_db(**_kwargs):
            fetching_now.set()
            return auth_db_queue.get()

        self.mock(api, "fetch_auth_db", mock_fetch_auth_db)
        future = run_in_thread(api.get_process_auth_db)

        # Wait for internal thread to call |fetch_auth_db|.
        fetching_now.wait()

        # Ok, now main thread is unblocked, while internal thread is blocking on a
        # artificially slow 'fetch_auth_db' call. Main thread can now try to get
        # AuthDB via get_process_auth_db(). It should get older stale copy right
        # away.
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Finish background 'fetch_auth_db' call by returning 'auth_db_v1'.
        # That's what internal thread should get as result of 'get_process_auth_db'.
        auth_db_queue.put(auth_db_v1)
        self.assertEqual(auth_db_v1, future.get())

        # Now main thread should get it as well.
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #4
0
    def test_get_process_auth_db_multithreading(self):
        """Ensure get_process_auth_db() plays nice with multiple threads."""
        def run_in_thread(func):
            """Runs |func| in a parallel thread, returns future (as Queue)."""
            result = Queue.Queue()
            thread = threading.Thread(target=lambda: result.put(func()))
            thread.start()
            return result

        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Run initial fetch, should cache |auth_db_v0| in process cache.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make process cache expire.
        self.set_time(api.get_process_cache_expiration_sec() + 1)

        # Start fetching AuthDB from another thread, at some point it will call
        # 'fetch_auth_db', and we pause the thread then and resume main thread.
        fetching_now = threading.Event()
        auth_db_queue = Queue.Queue()

        def mock_fetch_auth_db(**_kwargs):
            fetching_now.set()
            return auth_db_queue.get()

        self.mock(api, 'fetch_auth_db', mock_fetch_auth_db)
        future = run_in_thread(api.get_process_auth_db)

        # Wait for internal thread to call |fetch_auth_db|.
        fetching_now.wait()

        # Ok, now main thread is unblocked, while internal thread is blocking on a
        # artificially slow 'fetch_auth_db' call. Main thread can now try to get
        # AuthDB via get_process_auth_db(). It should get older stale copy right
        # away.
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Finish background 'fetch_auth_db' call by returning 'auth_db_v1'.
        # That's what internal thread should get as result of 'get_process_auth_db'.
        auth_db_queue.put(auth_db_v1)
        self.assertEqual(auth_db_v1, future.get())

        # Now main thread should get it as well.
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #5
0
    def test_get_process_auth_db_known_version(self):
        """Ensure get_process_auth_db() respects entity group version."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v0_again = api.AuthDB(entity_group_version=0)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make cache expire, but setup fetch_auth_db to return a new instance of
        # AuthDB, but with same entity group version. Old known instance of AuthDB
        # should be reused.
        self.set_time(api.get_process_cache_expiration_sec() + 1)
        self.set_fetched_auth_db(auth_db_v0_again)
        self.assertTrue(api.get_process_auth_db() is auth_db_v0)
Exemple #6
0
    def test_get_process_auth_db_known_version(self):
        """Ensure get_process_auth_db() respects entity group version."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v0_again = api.AuthDB(entity_group_version=0)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Make cache expire, but setup fetch_auth_db to return a new instance of
        # AuthDB, but with same entity group version. Old known instance of AuthDB
        # should be reused.
        self.set_time(api.get_process_cache_expiration_sec() + 1)
        self.set_fetched_auth_db(auth_db_v0_again)
        self.assertTrue(api.get_process_auth_db() is auth_db_v0)
Exemple #7
0
    def test_get_latest_auth_db(self):
        """Ensure get_latest_auth_db "rushes" cached AuthDB update."""
        auth_db_v0 = api.AuthDB(replication_state=mock_replication_state(0))
        auth_db_v1 = api.AuthDB(replication_state=mock_replication_state(1))

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # Rig up fetch_auth_db to return a newer version.
        self.set_fetched_auth_db(auth_db_v1)

        # 'get_process_auth_db' still returns the cached one.
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # But 'get_latest_auth_db' returns a new one and updates the cached copy.
        self.assertEqual(auth_db_v1, api.get_latest_auth_db())
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #8
0
    def test_get_process_auth_db_expiration(self):
        """Ensure get_process_auth_db() respects expiration."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # It doesn't expire for some time.
        self.set_time(api.get_process_cache_expiration_sec() - 1)
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # But eventually it does.
        self.set_time(api.get_process_cache_expiration_sec() + 1)
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v1, api.get_process_auth_db())
Exemple #9
0
    def test_get_process_auth_db_expiration(self):
        """Ensure get_process_auth_db() respects expiration."""
        # Prepare several instances of AuthDB to be used in mocks.
        auth_db_v0 = api.AuthDB(entity_group_version=0)
        auth_db_v1 = api.AuthDB(entity_group_version=1)

        # Fetch initial copy of AuthDB.
        self.set_time(0)
        self.set_fetched_auth_db(auth_db_v0)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # It doesn't expire for some time.
        self.set_time(api.get_process_cache_expiration_sec() - 1)
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v0, api.get_process_auth_db())

        # But eventually it does.
        self.set_time(api.get_process_cache_expiration_sec() + 1)
        self.set_fetched_auth_db(auth_db_v1)
        self.assertEqual(auth_db_v1, api.get_process_auth_db())