Merge pull request #272 from CanonicalLtd/mwhudson/testing-blue-sky

add some simple view unit tests and travis integration
This commit is contained in:
Michael Hudson-Doyle 2017-12-01 09:45:26 +13:00 committed by GitHub
commit ecdc01d0b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 190 additions and 5 deletions

21
.travis.yml Normal file
View File

@ -0,0 +1,21 @@
sudo: required
services:
- docker
language: bash
# Travis still doesn't support anything newer than trusty so we pull
# docker tricks to run things on Xenial. Maybe we should run things on
# bionic or whatever as well but this is a start...
before_install:
- docker pull ubuntu:xenial
- cid=`docker run --tty --detach --workdir /subiquity -v $(pwd):/subiquity ubuntu:xenial`
- docker exec $cid apt-get update
- docker exec $cid apt-get -y dist-upgrade
- docker exec $cid apt-get install -y --no-install-recommends libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libsystemd-dev python3-distutils-extra pkg-config python3.5 python3-pip git lsb-release python3-setuptools gcc python3-dev python3-wheel
- docker exec $cid pip3 install -r requirements.txt
- docker exec $cid python3 setup.py build
script:
- docker exec $cid python3 -m unittest discover

View File

@ -2,9 +2,11 @@ urwid==1.2.1
nose-cov
nose
flake8
python3-parted
yaml
PyYAML
testtools
mock
attr
attrs
systemd
jsonschema
pyudev
-e git+https://github.com/CanonicalLtd/probert#egg=probert

View File

@ -13,7 +13,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.controller import BaseController

View File

@ -1,3 +1,4 @@
"""
import argparse
import logging
import random
@ -459,3 +460,4 @@ class TestBlockdev(testtools.TestCase):
empty = self.bd.available_partitions
print(empty)
self.assertEqual(len(empty), 1)
"""

View File

@ -0,0 +1 @@
#

View File

@ -0,0 +1,49 @@
import re
import urwid
def find_with_pred(w, pred):
def _walk(w):
if pred(w):
return w
if hasattr(w, '_wrapped_widget'):
return _walk(w._wrapped_widget)
if hasattr(w, 'original_widget'):
return _walk(w.original_widget)
if isinstance(w, urwid.ListBox):
for w in w.body:
r = _walk(w)
if r:
return r
elif hasattr(w, 'contents'):
contents = w.contents
for w, _ in contents:
r = _walk(w)
if r:
return r
return _walk(w)
def find_button_matching(w, pat):
def pred(w):
return isinstance(w, urwid.Button) and re.match(pat, w.label)
return find_with_pred(w, pred)
def click(but):
but._emit('click')
def keypress(w, key, size=(30, 1)):
w.keypress(size, key)
def get_focus_path(w):
path = []
while True:
path.append(w)
if w.focus is not None:
w = w.focus
elif hasattr(w, '_wrapped_widget'):
w = w._wrapped_widget
elif hasattr(w, 'original_widget'):
w = w.original_widget
else:
break
return path

View File

@ -0,0 +1,32 @@
import unittest
from unittest import mock
from subiquitycore.models.identity import IdentityModel
from subiquitycore.signals import Signal
from subiquity.controllers.identity import IdentityController
from subiquity.ui.views.identity import IdentityView
from subiquity.ui.views.tests import helpers
class IdentityViewTests(unittest.TestCase):
def make_view(self):
model = mock.create_autospec(spec=IdentityModel)
controller = mock.create_autospec(spec=IdentityController)
controller.signal = mock.create_autospec(spec=Signal)
return IdentityView(model, controller, {})
def test_done_initially_disabled(self):
view = self.make_view()
self.assertFalse(view.form.done_btn.enabled)
def test_initial_focus(self):
view = self.make_view()
focus_path = helpers.get_focus_path(view)
for w in reversed(focus_path):
if w is view.form.realname.widget:
return
else:
self.fail("Realname widget not focus")

View File

@ -0,0 +1,33 @@
import unittest
from unittest import mock
from subiquity.controllers.installprogress import InstallProgressController
from subiquity.ui.views.installprogress import ProgressView
from subiquity.ui.views.tests import helpers
class IdentityViewTests(unittest.TestCase):
def make_view(self):
controller = mock.create_autospec(spec=InstallProgressController)
return ProgressView(controller)
def test_initial_focus(self):
view = self.make_view()
for w in reversed(helpers.get_focus_path(view)):
if w is view.listbox:
return
else:
self.fail("listbox widget not focus")
def test_show_complete(self):
view = self.make_view()
btn = helpers.find_button_matching(view, "^Reboot Now$")
self.assertIs(btn, None)
view.show_complete()
btn = helpers.find_button_matching(view, "^Reboot Now$")
self.assertIsNot(btn, None)
helpers.click(btn)
view.controller.reboot.assert_called_once_with()

View File

@ -0,0 +1,42 @@
import unittest
from unittest import mock
import urwid
from subiquity.controllers.welcome import WelcomeController
from subiquity.models.locale import LocaleModel
from subiquity.ui.views.welcome import WelcomeView
from subiquity.ui.views.tests import helpers
class WelcomeViewTests(unittest.TestCase):
def make_view_with_languages(self, languages):
controller = mock.create_autospec(spec=WelcomeController)
model = mock.create_autospec(spec=LocaleModel)
model.get_languages.return_value = languages
return WelcomeView(model, controller)
def test_basic(self):
# Clicking the button for a language calls "switch_language"
# on the model and "done" on the controller.
view = self.make_view_with_languages([('code', 'lang', 'native')])
but = helpers.find_button_matching(view, "^native$")
helpers.click(but)
view.model.switch_language.assert_called_once_with("code")
view.controller.done.assert_called_once_with()
def test_initial_focus(self):
# The initial focus for the view is the button for the first
# language.
view = self.make_view_with_languages([
('code1', 'lang1', 'native1'),
('code2', 'lang2', 'native2'),
])
for w in reversed(helpers.get_focus_path(view)):
if isinstance(w, urwid.Button):
self.assertEqual(w.label, "native1")
break
else:
self.fail("No button found in focus path")

View File

@ -104,6 +104,7 @@ class BoundFormField(object):
self.form = form
self.in_error = False
self._help = None
self.help_text = Text("", align="center")
self._caption = None
self.pile = None
self._enabled = True
@ -223,7 +224,7 @@ class BoundFormField(object):
raise RuntimeError("do not call as_row more than once!")
self.parent_view = view
self._longest_caption = longest_caption
self.help_text = Text(self.help, align="center")
self.help_text.set_text(self.help)
cols = [
(self._longest_caption, Text("")),
self.help_text,
@ -286,6 +287,9 @@ class Form(object, metaclass=MetaForm):
self._fields.append(bf)
if field.name in initial:
bf.value = initial[field.name]
for bf in self._fields:
bf.validate()
self.validated()
def _click_done(self, sender):
emit_signal(self, 'submit', self)