Merge pull request #272 from CanonicalLtd/mwhudson/testing-blue-sky
add some simple view unit tests and travis integration
This commit is contained in:
commit
ecdc01d0b2
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
"""
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#
|
|
@ -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
|
|
@ -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")
|
|
@ -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()
|
|
@ -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")
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue