emmental/tests/db/test_idle.py

216 lines
9.0 KiB
Python

# Copyright 2022 (c) Anna Schumaker
"""Tests our idle queues."""
import unittest
import unittest.mock
import emmental.db.idle
from gi.repository import GObject
from gi.repository import GLib
@unittest.mock.patch("gi.repository.GLib.source_remove")
@unittest.mock.patch("gi.repository.GLib.idle_add", return_value=42)
class TestIdleQueue(unittest.TestCase):
"""Test the base Idle Queue."""
def setUp(self):
"""Set up common variables."""
self.queue = emmental.db.idle.Queue()
def test_init(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test that the Idle Queue is initialized properly."""
self.assertIsInstance(self.queue, GObject.GObject)
self.assertEqual(self.queue.total, 0)
self.assertEqual(self.queue.progress, 0.0)
self.assertFalse(self.queue.running)
self.assertTrue(self.queue.enabled)
self.assertListEqual(self.queue._tasks, [])
self.assertIsNone(self.queue._idle_id)
def test_getitem(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test the __getitem__() function."""
self.queue._tasks = [1, 2, 3]
self.assertEqual(self.queue[0], 1)
self.assertEqual(self.queue[1], 2)
self.assertEqual(self.queue[2], 3)
self.assertIsNone(self.queue[3])
def test_cancel(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test canceling queued tasks."""
self.queue.push(1)
self.queue.progress = 0.42
self.queue.cancel()
mock_source_removed.assert_called_with(42)
self.assertListEqual(self.queue._tasks, [])
self.assertIsNone(self.queue._idle_id)
self.assertEqual(self.queue.total, 0)
self.assertEqual(self.queue.progress, 0.0)
def test_cancel_task(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test canceling a specific task."""
self.queue.push(1)
self.queue.push(2)
self.queue.push(1)
self.queue.cancel_task(1)
self.assertListEqual(self.queue._tasks, [(2,)])
self.assertEqual(self.queue.total, 3)
self.assertAlmostEqual(self.queue.progress, 2 / 3)
mock_source_removed.assert_not_called()
self.queue.cancel_task(2)
self.assertListEqual(self.queue._tasks, [])
self.assertIsNone(self.queue._idle_id)
self.assertEqual(self.queue.total, 0)
self.assertEqual(self.queue.progress, 0.0)
mock_source_removed.assert_called_with(42)
def test_complete(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test completing queued tasks."""
func = unittest.mock.Mock(return_value=True)
self.queue.push(func, 1)
self.queue.push(func, 2)
self.queue.complete()
func.assert_has_calls([unittest.mock.call(1),
unittest.mock.call(2)])
self.assertFalse(self.queue.running)
self.assertListEqual(self.queue._tasks, [])
mock_source_removed.assert_called_with(42)
func.reset_mock()
self.queue.complete()
func.assert_not_called()
def test_push_enabled(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test adding an idle task to an enabled idle queue."""
func = unittest.mock.Mock(return_value=True)
self.assertIsNone(self.queue.push(func, 1))
mock_idle_add.assert_called_with(self.queue.run_task)
func.assert_not_called()
self.assertListEqual(self.queue._tasks, [(func, 1)])
self.assertEqual(self.queue.total, 1)
self.assertEqual(self.queue._idle_id, 42)
self.assertTrue(self.queue.running)
mock_idle_add.reset_mock()
self.assertIsNone(self.queue.push(func, 2))
self.assertListEqual(self.queue._tasks, [(func, 1), (func, 2)])
self.assertEqual(self.queue.total, 2)
mock_idle_add.assert_not_called()
def test_push_disabled(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test adding an idle task to a disabled idle queue."""
self.queue.enabled = False
func = unittest.mock.Mock(return_value=True)
self.assertTrue(self.queue.push(func, 1))
self.assertListEqual(self.queue._tasks, [])
self.assertEqual(self.queue.total, 0)
self.assertFalse(self.queue.running)
self.assertIsNone(self.queue._idle_id)
mock_idle_add.assert_not_called()
func.assert_called_with(1)
func = unittest.mock.Mock(return_value=False)
self.assertFalse(self.queue.push(func, 2))
mock_idle_add.assert_not_called()
func.assert_called_with(2)
def test_push_now(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test pushing an idle task with now=True."""
func = unittest.mock.Mock(return_value=True)
self.assertTrue(self.queue.push(func, 1, now=True))
self.assertListEqual(self.queue._tasks, [])
self.assertEqual(self.queue.total, 0)
self.assertFalse(self.queue.running)
self.assertIsNone(self.queue._idle_id)
mock_idle_add.assert_not_called()
func.assert_called_with(1)
def test_push_first(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test pushing an idle task with first=True."""
self.queue.push(1)
self.queue.push(0, first=True)
self.assertListEqual(self.queue._tasks, [(0,), (1,)])
self.queue.push(2, first=False)
self.assertListEqual(self.queue._tasks, [(0,), (1,), (2,)])
self.queue.push(3)
self.assertListEqual(self.queue._tasks, [(0,), (1,), (2,), (3,)])
def test_push_many_enabled(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test adding several calls to one function at one time."""
func = unittest.mock.Mock(return_value=True)
self.queue.push_many(func, [(1,), (2,), (3,)])
self.assertListEqual(self.queue._tasks, [(func, 1),
(func, 2),
(func, 3)])
self.assertEqual(self.queue.total, 3)
self.assertEqual(self.queue._idle_id, 42)
self.assertTrue(self.queue.running)
mock_idle_add.assert_called_with(self.queue.run_task)
func.assert_not_called()
def test_push_many_disabled(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test push_many() with the idle queue disabled."""
self.queue.enabled = False
func = unittest.mock.Mock(return_value=True)
self.queue.push_many(func, [(1,), (2,), (3,)])
func.assert_has_calls([unittest.mock.call(1),
unittest.mock.call(2),
unittest.mock.call(3)])
mock_idle_add.assert_not_called()
def test_push_many_now(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test push_many() with now=True."""
func = unittest.mock.Mock(return_value=True)
self.queue.push_many(func, [(1,), (2,), (3,)], now=True)
func.assert_has_calls([unittest.mock.call(1),
unittest.mock.call(2),
unittest.mock.call(3)])
mock_idle_add.assert_not_called()
def test_run_task(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test manually running idle tasks."""
func = unittest.mock.Mock(return_value=True)
self.queue.push_many(func, [(i,) for i in range(5)])
self.assertEqual(self.queue.total, 5)
for i in range(5):
expected = GLib.SOURCE_REMOVE if i == 4 else GLib.SOURCE_CONTINUE
with self.subTest(i=i, expected=expected):
self.assertEqual(self.queue.run_task(), expected)
func.assert_called_with(i)
self.assertAlmostEqual(self.queue.progress,
0 if i == 4 else (i + 1) / 5)
self.assertEqual(self.queue.running, i != 4)
self.assertIsNone(self.queue._idle_id)
self.queue.run_task()
def test_rerun_task(self, mock_idle_add: unittest.mock.Mock,
mock_source_removed: unittest.mock.Mock):
"""Test rerunning a task."""
func = unittest.mock.Mock(return_value=False)
self.queue.push(func, 1)
self.queue.push(func, 2)
self.queue.run_task()
self.assertListEqual(self.queue._tasks, [(func, 1), (func, 2)])