Make tests work reliably on the Pi

While the tests work well on a PC or Travis, the Pi (where I ought to be
running them!) has some issues with the timing tests. Need to relax the
tolerance of the "assert_states_and_times" method to 0.05 seconds
otherwise it periodically fails even on something reasonably quick like
a Pi 2 (less failures on a Pi 3 but still occasionally).

Also reduced default fps to 25; if the default timing occasionally fails
on a Pi 2 it's evidently too fast for a Pi 1 and shouldn't be the
default; 25 also doesn't look any different to me on a pulsing LED.

There's also a bunch of miscellaneous fixes in here; last minute typos
and chart re-gens for the 1.2 release.
This commit is contained in:
Dave Jones
2016-04-08 11:10:59 +01:00
parent 44422bd6c9
commit c2a9392ea5
28 changed files with 846 additions and 842 deletions

View File

@@ -25,114 +25,112 @@ def teardown_function(function):
def test_output_initial_values():
pin = MockPin(2)
device = OutputDevice(pin, initial_value=False)
assert pin.function == 'output'
assert not pin.state
device.close()
device = OutputDevice(pin, initial_value=True)
assert pin.state
device.close()
state = pin.state
device = OutputDevice(pin, initial_value=None)
assert state == pin.state
with OutputDevice(pin, initial_value=False) as device:
assert pin.function == 'output'
assert not pin.state
with OutputDevice(pin, initial_value=True) as device:
assert pin.state
state = pin.state
with OutputDevice(pin, initial_value=None) as device:
assert state == pin.state
def test_output_write_active_high():
pin = MockPin(2)
device = OutputDevice(pin)
device.on()
assert pin.state
device.off()
assert not pin.state
with OutputDevice(pin) as device:
device.on()
assert pin.state
device.off()
assert not pin.state
def test_output_write_active_low():
pin = MockPin(2)
device = OutputDevice(pin, active_high=False)
device.on()
assert not pin.state
device.off()
assert pin.state
with OutputDevice(pin, active_high=False) as device:
device.on()
assert not pin.state
device.off()
assert pin.state
def test_output_write_closed():
device = OutputDevice(MockPin(2))
device.close()
with pytest.raises(GPIODeviceClosed):
device.on()
with OutputDevice(MockPin(2)) as device:
device.close()
with pytest.raises(GPIODeviceClosed):
device.on()
def test_output_write_silly():
pin = MockPin(2)
device = OutputDevice(pin)
pin.function = 'input'
with pytest.raises(AttributeError):
device.on()
with OutputDevice(pin) as device:
pin.function = 'input'
with pytest.raises(AttributeError):
device.on()
def test_output_value():
pin = MockPin(2)
device = OutputDevice(pin)
assert not device.value
assert not pin.state
device.on()
assert device.value
assert pin.state
device.value = False
assert not device.value
assert not pin.state
with OutputDevice(pin) as device:
assert not device.value
assert not pin.state
device.on()
assert device.value
assert pin.state
device.value = False
assert not device.value
assert not pin.state
def test_output_digital_toggle():
pin = MockPin(2)
device = DigitalOutputDevice(pin)
assert not device.value
assert not pin.state
device.toggle()
assert device.value
assert pin.state
device.toggle()
assert not device.value
assert not pin.state
with DigitalOutputDevice(pin) as device:
assert not device.value
assert not pin.state
device.toggle()
assert device.value
assert pin.state
device.toggle()
assert not device.value
assert not pin.state
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_blink_background():
pin = MockPin(2)
device = DigitalOutputDevice(pin)
device.blink(0.1, 0.1, n=2)
device._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
pin.assert_states_and_times([
(0.0, False),
(0.0, True),
(0.1, False),
(0.1, True),
(0.1, False)
])
with DigitalOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2)
device._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
pin.assert_states_and_times([
(0.0, False),
(0.0, True),
(0.1, False),
(0.1, True),
(0.1, False)
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_blink_foreground():
pin = MockPin(2)
device = DigitalOutputDevice(pin)
device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([
(0.0, False),
(0.0, True),
(0.1, False),
(0.1, True),
(0.1, False)
])
with DigitalOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([
(0.0, False),
(0.0, True),
(0.1, False),
(0.1, True),
(0.1, False)
])
def test_output_blink_interrupt_on():
pin = MockPin(2)
device = DigitalOutputDevice(pin)
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
pin.assert_states([False, True, False])
with DigitalOutputDevice(pin) as device:
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
pin.assert_states([False, True, False])
def test_output_blink_interrupt_off():
pin = MockPin(2)
device = DigitalOutputDevice(pin)
device.blink(0.1, 1)
sleep(0.2)
device.off() # should interrupt while off
pin.assert_states([False, True, False])
with DigitalOutputDevice(pin) as device:
device.blink(0.1, 1)
sleep(0.2)
device.off() # should interrupt while off
pin.assert_states([False, True, False])
def test_output_pwm_bad_initial_value():
with pytest.raises(ValueError):
@@ -144,50 +142,50 @@ def test_output_pwm_not_supported():
def test_output_pwm_states():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.value = 0.1
device.value = 0.2
device.value = 0.0
pin.assert_states([0.0, 0.1, 0.2, 0.0])
with PWMOutputDevice(pin) as device:
device.value = 0.1
device.value = 0.2
device.value = 0.0
pin.assert_states([0.0, 0.1, 0.2, 0.0])
def test_output_pwm_read():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin, frequency=100)
assert device.frequency == 100
device.value = 0.1
assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.1)
assert device.is_active
device.frequency = None
assert not device.value
assert not device.is_active
assert device.frequency is None
with PWMOutputDevice(pin, frequency=100) as device:
assert device.frequency == 100
device.value = 0.1
assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.1)
assert device.is_active
device.frequency = None
assert not device.value
assert not device.is_active
assert device.frequency is None
def test_output_pwm_write():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.on()
device.off()
pin.assert_states([False, True, False])
with PWMOutputDevice(pin) as device:
device.on()
device.off()
pin.assert_states([False, True, False])
def test_output_pwm_toggle():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.toggle()
device.value = 0.5
device.value = 0.1
device.toggle()
device.off()
pin.assert_states([False, True, 0.5, 0.1, 0.9, False])
with PWMOutputDevice(pin) as device:
device.toggle()
device.value = 0.5
device.value = 0.1
device.toggle()
device.off()
pin.assert_states([False, True, 0.5, 0.1, 0.9, False])
def test_output_pwm_active_high_read():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin, active_high=False)
device.value = 0.1
assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.9)
device.frequency = None
assert device.value
with PWMOutputDevice(pin, active_high=False) as device:
device.value = 0.1
assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.9)
device.frequency = None
assert device.value
def test_output_pwm_bad_value():
with pytest.raises(ValueError):
@@ -201,108 +199,108 @@ def test_output_pwm_write_closed():
def test_output_pwm_write_silly():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
pin.function = 'input'
with pytest.raises(AttributeError):
device.off()
with PWMOutputDevice(pin) as device:
pin.function = 'input'
with pytest.raises(AttributeError):
device.off()
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_blink_background():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.blink(0.1, 0.1, n=2)
device._blink_thread.join()
pin.assert_states_and_times([
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
])
with PWMOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2)
device._blink_thread.join()
pin.assert_states_and_times([
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_blink_foreground():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
])
with PWMOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_fade_background():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.blink(0, 0, 0.1, 0.1, n=2)
device._blink_thread.join()
pin.assert_states_and_times([
(0.0, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
])
with PWMOutputDevice(pin) as device:
device.blink(0, 0, 0.2, 0.2, n=2)
device._blink_thread.join()
pin.assert_states_and_times([
(0.0, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_fade_foreground():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.blink(0, 0, 0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([
(0.0, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
])
with PWMOutputDevice(pin) as device:
device.blink(0, 0, 0.2, 0.2, n=2, background=False)
pin.assert_states_and_times([
(0.0, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
])
def test_output_pwm_blink_interrupt():
pin = MockPWMPin(2)
device = PWMOutputDevice(pin)
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
pin.assert_states([0, 1, 0])
with PWMOutputDevice(pin) as device:
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
pin.assert_states([0, 1, 0])
def test_rgbled_missing_pins():
with pytest.raises(ValueError):
@@ -310,116 +308,116 @@ def test_rgbled_missing_pins():
def test_rgbled_initial_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b, initial_value=(0.1, 0.2, 0))
assert r.frequency
assert g.frequency
assert b.frequency
assert isclose(r.state, 0.1)
assert isclose(g.state, 0.2)
assert isclose(b.state, 0.0)
with RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) as device:
assert r.frequency
assert g.frequency
assert b.frequency
assert isclose(r.state, 0.1)
assert isclose(g.state, 0.2)
assert isclose(b.state, 0.0)
def test_rgbled_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
assert not device.is_active
assert device.value == (0, 0, 0)
device.on()
assert device.is_active
assert device.value == (1, 1, 1)
device.off()
assert not device.is_active
assert device.value == (0, 0, 0)
with RGBLED(r, g, b) as device:
assert not device.is_active
assert device.value == (0, 0, 0)
device.on()
assert device.is_active
assert device.value == (1, 1, 1)
device.off()
assert not device.is_active
assert device.value == (0, 0, 0)
def test_rgbled_toggle():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
assert not device.is_active
assert device.value == (0, 0, 0)
device.toggle()
assert device.is_active
assert device.value == (1, 1, 1)
device.toggle()
assert not device.is_active
assert device.value == (0, 0, 0)
with RGBLED(r, g, b) as device:
assert not device.is_active
assert device.value == (0, 0, 0)
device.toggle()
assert device.is_active
assert device.value == (1, 1, 1)
device.toggle()
assert not device.is_active
assert device.value == (0, 0, 0)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_background():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
device.blink(0.1, 0.1, n=2)
device._blink_thread.join()
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
with RGBLED(r, g, b) as device:
device.blink(0.1, 0.1, n=2)
device._blink_thread.join()
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_foreground():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
device.blink(0.1, 0.1, n=2, background=False)
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
with RGBLED(r, g, b) as device:
device.blink(0.1, 0.1, n=2, background=False)
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_fade_background():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
device.blink(0, 0, 0.1, 0.1, n=2)
device._blink_thread.join()
expected = [
(0.0, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
(0.02, 0.2),
(0.02, 0.4),
(0.02, 0.6),
(0.02, 0.8),
(0.02, 1),
(0.02, 0.8),
(0.02, 0.6),
(0.02, 0.4),
(0.02, 0.2),
(0.02, 0),
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
with RGBLED(r, g, b) as device:
device.blink(0, 0, 0.2, 0.2, n=2)
device._blink_thread.join()
expected = [
(0.0, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
def test_output_rgbled_blink_interrupt():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b)
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
r.assert_states([0, 1, 0])
g.assert_states([0, 1, 0])
b.assert_states([0, 1, 0])
with RGBLED(r, g, b) as device:
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
r.assert_states([0, 1, 0])
g.assert_states([0, 1, 0])
b.assert_states([0, 1, 0])
def test_motor_missing_pins():
with pytest.raises(ValueError):
@@ -428,55 +426,55 @@ def test_motor_missing_pins():
def test_motor_pins():
f = MockPWMPin(1)
b = MockPWMPin(2)
device = Motor(f, b)
assert device.forward_device.pin is f
assert device.backward_device.pin is b
with Motor(f, b) as device:
assert device.forward_device.pin is f
assert device.backward_device.pin is b
def test_motor_close():
f = MockPWMPin(1)
b = MockPWMPin(2)
device = Motor(f, b)
device.close()
assert device.closed
assert device.forward_device.pin is None
assert device.backward_device.pin is None
with Motor(f, b) as device:
device.close()
assert device.closed
assert device.forward_device.pin is None
assert device.backward_device.pin is None
def test_motor_value():
f = MockPWMPin(1)
b = MockPWMPin(2)
device = Motor(f, b)
device.value = -1
assert device.is_active
assert device.value == -1
assert b.state == 1 and f.state == 0
device.value = 1
assert device.is_active
assert device.value == 1
assert b.state == 0 and f.state == 1
device.value = 0.5
assert device.is_active
assert device.value == 0.5
assert b.state == 0 and f.state == 0.5
device.value = 0
assert not device.is_active
assert not device.value
assert b.state == 0 and f.state == 0
with Motor(f, b) as device:
device.value = -1
assert device.is_active
assert device.value == -1
assert b.state == 1 and f.state == 0
device.value = 1
assert device.is_active
assert device.value == 1
assert b.state == 0 and f.state == 1
device.value = 0.5
assert device.is_active
assert device.value == 0.5
assert b.state == 0 and f.state == 0.5
device.value = 0
assert not device.is_active
assert not device.value
assert b.state == 0 and f.state == 0
def test_motor_bad_value():
f = MockPWMPin(1)
b = MockPWMPin(2)
device = Motor(f, b)
with pytest.raises(ValueError):
device.value = 2
with Motor(f, b) as device:
with pytest.raises(ValueError):
device.value = 2
def test_motor_reverse():
f = MockPWMPin(1)
b = MockPWMPin(2)
device = Motor(f, b)
device.forward()
assert device.value == 1
assert b.state == 0 and f.state == 1
device.reverse()
assert device.value == -1
assert b.state == 1 and f.state == 0
with Motor(f, b) as device:
device.forward()
assert device.value == 1
assert b.state == 0 and f.state == 1
device.reverse()
assert device.value == -1
assert b.state == 1 and f.state == 0