[tests] Purge tests and start with a clean implementation of subprocess

Seems like subprocess and friends (Popen, communicate) are not so easy
to mock cleanly. Therefore, start from scratch and carefully write test
by test, until (at least) the old test coverage has been restored.
This commit is contained in:
Tobi-wan Kenobi 2017-03-04 11:25:52 +01:00
parent 1c6122fc3f
commit 6dbe440cb5
23 changed files with 61 additions and 1240 deletions

View file

@ -1,68 +0,0 @@
# pylint: disable=C0103,C0111
import sys
import json
import unittest
import mock
from contextlib import contextmanager
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.battery import Module
from tests.util import MockEngine, MockConfig, assertPopen
class MockOpen(object):
def __init__(self):
self._value = ""
def returns(self, value):
self._value = value
def __enter__(self):
return self
def __exit__(self, a, b, c):
pass
def read(self):
return self._value
class TestBatteryModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
for widget in self.module.widgets():
widget.link_module(self.module)
@mock.patch("sys.stdout")
def test_format(self, mock_output):
for widget in self.module.widgets():
self.assertEquals(len(widget.full_text()), len("100%"))
@mock.patch("os.path.exists")
@mock.patch("{}.open".format("__builtin__" if sys.version_info[0] < 3 else "builtins"))
@mock.patch("subprocess.Popen")
def test_critical(self, mock_output, mock_open, mock_exists):
mock_open.return_value = MockOpen()
mock_open.return_value.returns("19")
mock_exists.return_value = True
self.config.set("battery.critical", "20")
self.config.set("battery.warning", "25")
self.module.update(self.module.widgets())
self.assertTrue("critical" in self.module.widgets()[0].state())
@mock.patch("os.path.exists")
@mock.patch("{}.open".format("__builtin__" if sys.version_info[0] < 3 else "builtins"))
@mock.patch("subprocess.Popen")
def test_warning(self, mock_output, mock_open, mock_exists):
mock_open.return_value = MockOpen()
mock_exists.return_value = True
mock_open.return_value.returns("22")
self.config.set("battery.critical", "20")
self.config.set("battery.warning", "25")
self.module.update(self.module.widgets())
self.assertTrue("warning" in self.module.widgets()[0].state())
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,56 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.brightness import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent
class TestBrightnessModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
for widget in self.module.widgets():
widget.link_module(self.module)
@mock.patch("sys.stdout")
def test_format(self, mock_output):
for widget in self.module.widgets():
self.assertEquals(len(widget.full_text()), len("100%"))
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_wheel_up(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.WHEEL_UP,
"xbacklight +2%"
)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_wheel_down(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.WHEEL_DOWN,
"xbacklight -2%"
)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_custom_step(self, mock_input, mock_output, mock_select):
self.config.set("brightness.step", "10")
module = Module(engine=self.engine, config={ "config": self.config })
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
module, bumblebee.input.WHEEL_DOWN,
"xbacklight -10%"
)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,21 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.caffeine import Module
from tests.util import MockEngine, MockConfig, assertPopen
class TestCaffeineModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.engine.input.need_valid_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
for widget in self.module.widgets():
widget.link_module(self.module)

View file

@ -1,58 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.cmus import Module
from tests.util import MockEngine, MockConfig, assertPopen, MockEpoll
class TestCmusModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.module = Module(engine=self.engine, config={"config": MockConfig()})
@mock.patch("subprocess.Popen")
def test_read_song(self, mock_output):
rv = mock.Mock()
rv.configure_mock(**{
"communicate.return_value": ("out", None)
})
mock_output.return_value = rv
self.module.update(self.module.widgets())
assertPopen(mock_output, "cmus-remote -Q")
def test_widgets(self):
self.assertTrue(len(self.module.widgets()), 5)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_interaction(self, mock_input, mock_output, mock_select):
events = [
{"widget": "cmus.shuffle", "action": "cmus-remote -S"},
{"widget": "cmus.repeat", "action": "cmus-remote -R"},
{"widget": "cmus.next", "action": "cmus-remote -n"},
{"widget": "cmus.prev", "action": "cmus-remote -r"},
{"widget": "cmus.main", "action": "cmus-remote -u"},
]
mock_input.fileno.return_value = 1
mock_select.return_value = MockEpoll()
for event in events:
mock_input.readline.return_value = json.dumps({
"name": self.module.id,
"button": bumblebee.input.LEFT_MOUSE,
"instance": self.module.widget(event["widget"]).id
})
self.engine.input.start()
self.engine.input.stop()
mock_input.readline.assert_any_call()
assertPopen(mock_output, event["action"])
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,48 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.cpu import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains
class TestCPUModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
@mock.patch("sys.stdout")
def test_format(self, mock_output):
for widget in self.module.widgets():
self.assertEquals(len(widget.full_text()), len("100.00%"))
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_leftclick(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.LEFT_MOUSE,
"gnome-system-monitor"
)
@mock.patch("psutil.cpu_percent")
def test_warning(self, mock_psutil):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "18")
mock_psutil.return_value = 19.0
assertStateContains(self, self.module, "warning")
@mock.patch("psutil.cpu_percent")
def test_critical(self, mock_psutil):
self.config.set("cpu.critical", "20")
self.config.set("cpu.warning", "19")
mock_psutil.return_value = 21.0
assertStateContains(self, self.module, "critical")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,56 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.disk import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertStateContains, MockEpoll
class MockVFS(object):
def __init__(self, perc):
self.f_blocks = 1024*1024
self.f_frsize = 1
self.f_bavail = self.f_blocks - self.f_blocks*(perc/100.0)
class TestDiskModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.config.set("disk.path", "somepath")
self.module = Module(engine=self.engine, config={"config": self.config})
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_leftclick(self, mock_input, mock_output, mock_select):
mock_input.readline.return_value = json.dumps({
"name": self.module.id,
"button": bumblebee.input.LEFT_MOUSE,
"instance": None
})
mock_select.return_value = MockEpoll()
self.engine.input.start()
self.engine.input.stop()
mock_input.readline.assert_any_call()
assertPopen(mock_output, "nautilus {}".format(self.module.parameter("path")))
@mock.patch("os.statvfs")
def test_warning(self, mock_stat):
self.config.set("disk.critical", "80")
self.config.set("disk.warning", "70")
mock_stat.return_value = MockVFS(75.0)
assertStateContains(self, self.module, "warning")
@mock.patch("os.statvfs")
def test_critical(self, mock_stat):
self.config.set("disk.critical", "80")
self.config.set("disk.warning", "70")
mock_stat.return_value = MockVFS(85.0)
assertStateContains(self, self.module, "critical")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,47 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.load import Module
from tests.util import MockEngine, MockConfig, assertStateContains, assertMouseEvent
class TestLoadModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_leftclick(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.LEFT_MOUSE,
"gnome-system-monitor"
)
@mock.patch("multiprocessing.cpu_count")
@mock.patch("os.getloadavg")
def test_warning(self, mock_loadavg, mock_cpucount):
self.config.set("load.critical", "1")
self.config.set("load.warning", "0.8")
mock_cpucount.return_value = 1
mock_loadavg.return_value = [ 0.9, 0, 0 ]
assertStateContains(self, self.module, "warning")
@mock.patch("multiprocessing.cpu_count")
@mock.patch("os.getloadavg")
def test_critical(self, mock_loadavg, mock_cpucount):
self.config.set("load.critical", "1")
self.config.set("load.warning", "0.8")
mock_cpucount.return_value = 1
mock_loadavg.return_value = [ 1.1, 0, 0 ]
assertStateContains(self, self.module, "critical")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,47 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.memory import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains
class VirtualMemory(object):
def __init__(self, percent):
self.percent = percent
class TestMemoryModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_leftclick(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.LEFT_MOUSE,
"gnome-system-monitor"
)
@mock.patch("psutil.virtual_memory")
def test_warning(self, mock_vmem):
self.config.set("memory.critical", "80")
self.config.set("memory.warning", "70")
mock_vmem.return_value = VirtualMemory(75)
assertStateContains(self, self.module, "warning")
@mock.patch("psutil.virtual_memory")
def test_critical(self, mock_vmem):
self.config.set("memory.critical", "80")
self.config.set("memory.warning", "70")
mock_vmem.return_value = VirtualMemory(85)
assertStateContains(self, self.module, "critical")
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,57 +0,0 @@
# pylint: disable=C0103,C0111
import unittest
import importlib
import mock
from bumblebee.engine import all_modules
from bumblebee.config import Config
from tests.util import assertWidgetAttributes, MockEngine
class MockCommunicate(object):
def __init__(self):
self.returncode = 0
def communicate(self):
return (str.encode("1"), "error")
class TestGenericModules(unittest.TestCase):
@mock.patch("subprocess.Popen")
def setUp(self, mock_output):
mock_output.return_value = MockCommunicate()
engine = MockEngine()
config = Config()
self.objects = {}
for mod in all_modules():
cls = importlib.import_module("bumblebee.modules.{}".format(mod["name"]))
self.objects[mod["name"]] = getattr(cls, "Module")(engine, {"config": config})
for widget in self.objects[mod["name"]].widgets():
self.assertEquals(widget.get("variable", None), None)
@mock.patch("subprocess.Popen")
def test_widgets(self, mock_output):
mock_output.return_value = MockCommunicate()
for mod in self.objects:
widgets = self.objects[mod].widgets()
for widget in widgets:
widget.link_module(self.objects[mod])
self.assertEquals(widget.module, mod)
assertWidgetAttributes(self, widget)
widget.set("variable", "value")
self.assertEquals(widget.get("variable", None), "value")
self.assertTrue(isinstance(widget.full_text(), str) or isinstance(widget.full_text(), unicode))
@mock.patch("subprocess.Popen")
def test_update(self, mock_output):
mock_output.return_value = MockCommunicate()
rv = mock.Mock()
rv.configure_mock(**{
"communicate.return_value": ("out", None)
})
for mod in self.objects:
widgets = self.objects[mod].widgets()
self.objects[mod].update(widgets)
self.test_widgets()
self.assertEquals(widgets, self.objects[mod].widgets())
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,56 +0,0 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
import bumblebee.input
from bumblebee.input import I3BarInput
from bumblebee.modules.pulseaudio import Module
from tests.util import MockEngine, MockConfig, assertPopen, assertMouseEvent, assertStateContains
class TestPulseAudioModule(unittest.TestCase):
def setUp(self):
self.engine = MockEngine()
self.engine.input = I3BarInput()
self.engine.input.need_event = True
self.config = MockConfig()
self.module = Module(engine=self.engine, config={ "config": self.config })
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_leftclick(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.LEFT_MOUSE,
"pactl set-source-mute @DEFAULT_SOURCE@ toggle"
)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_rightclick(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.RIGHT_MOUSE,
"pavucontrol"
)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_wheelup(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.WHEEL_UP,
"pactl set-source-volume @DEFAULT_SOURCE@ +2%"
)
@mock.patch("select.epoll")
@mock.patch("subprocess.Popen")
@mock.patch("sys.stdin")
def test_wheeldown(self, mock_input, mock_output, mock_select):
assertMouseEvent(mock_input, mock_output, mock_select, self.engine,
self.module, bumblebee.input.WHEEL_DOWN,
"pactl set-source-volume @DEFAULT_SOURCE@ -2%"
)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4