diff options
| -rw-r--r-- | src/leap/gui/firstrun/__init__.py | 2 | ||||
| -rw-r--r-- | src/leap/gui/firstrun/connect.py | 231 | ||||
| -rw-r--r-- | src/leap/gui/firstrun/providerselect.py | 22 | ||||
| -rw-r--r-- | src/leap/gui/firstrun/register.py | 82 | ||||
| -rwxr-xr-x | src/leap/gui/firstrun/wizard.py | 32 | ||||
| -rw-r--r-- | src/leap/gui/progress.py | 1 | ||||
| -rw-r--r-- | src/leap/gui/tests/test_firstrun_providerselect.py | 162 | ||||
| -rw-r--r-- | src/leap/gui/tests/test_firstrun_register.py | 224 | ||||
| -rw-r--r-- | src/leap/gui/tests/test_firstrun_wizard.py | 3 | 
9 files changed, 458 insertions, 301 deletions
| diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index a2ca704d..d380b75a 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -5,7 +5,6 @@ try:  except ValueError:      pass -import connect  import intro  import last  import login @@ -17,7 +16,6 @@ import register  import regvalidation  __all__ = [ -    'connect',      'intro',      'last',      'login', diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py deleted file mode 100644 index a0fe021c..00000000 --- a/src/leap/gui/firstrun/connect.py +++ /dev/null @@ -1,231 +0,0 @@ -""" -Connecting Page, used in First Run Wizard -""" -# XXX FIXME -# DEPRECATED. All functionality moved to regvalidation -# This file should be removed after checking that one is ok. -# XXX - -import logging - -from PyQt4 import QtGui - -logger = logging.getLogger(__name__) - -from leap.base import auth - -from leap.gui.constants import APP_LOGO -from leap.gui.styles import ErrorLabelStyleSheet - - -class ConnectingPage(QtGui.QWizardPage): - -    # XXX change to a ValidationPage - -    def __init__(self, parent=None): -        super(ConnectingPage, self).__init__(parent) - -        self.setTitle("Connecting") -        self.setSubTitle('Connecting to provider.') - -        self.setPixmap( -            QtGui.QWizard.LogoPixmap, -            QtGui.QPixmap(APP_LOGO)) - -        self.status = QtGui.QLabel("") -        self.status.setWordWrap(True) -        self.progress = QtGui.QProgressBar() -        self.progress.setMaximum(100) -        self.progress.hide() - -        # for pre-checks -        self.status_line_1 = QtGui.QLabel() -        self.status_line_2 = QtGui.QLabel() -        self.status_line_3 = QtGui.QLabel() -        self.status_line_4 = QtGui.QLabel() - -        # for connecting signals... -        self.status_line_5 = QtGui.QLabel() - -        layout = QtGui.QGridLayout() -        layout.addWidget(self.status, 0, 1) -        layout.addWidget(self.progress, 5, 1) -        layout.addWidget(self.status_line_1, 8, 1) -        layout.addWidget(self.status_line_2, 9, 1) -        layout.addWidget(self.status_line_3, 10, 1) -        layout.addWidget(self.status_line_4, 11, 1) - -        # XXX to be used? -        #self.validation_status = QtGui.QLabel("") -        #self.validation_status.setStyleSheet( -            #ErrorLabelStyleSheet) -        #self.validation_msg = QtGui.QLabel("") - -        self.setLayout(layout) - -        self.goto_login_again = False - -    def set_status(self, status): -        self.status.setText(status) -        self.status.setWordWrap(True) - -    def set_status_line(self, line, status): -        line = getattr(self, 'status_line_%s' % line) -        if line: -            line.setText(status) - -    def set_validation_status(self, status): -        # Do not remember if we're using -        # status lines > 3 now... -        # if we are, move below -        self.status_line_3.setStyleSheet( -            ErrorLabelStyleSheet) -        self.status_line_3.setText(status) - -    def set_validation_message(self, message): -        self.status_line_4.setText(message) -        self.status_line_4.setWordWrap(True) - -    def get_donemsg(self, msg): -        return "%s ... done" % msg - -    def run_eip_checks_for_provider_and_connect(self, domain): -        wizard = self.wizard() -        conductor = wizard.conductor -        start_eip_signal = getattr( -            wizard, -            'start_eipconnection_signal', None) - -        if conductor: -            conductor.set_provider_domain(domain) -            conductor.run_checks() -            self.conductor = conductor -            errors = self.eip_error_check() -            if not errors and start_eip_signal: -                start_eip_signal.emit() - -        else: -            logger.warning( -                "No conductor found. This means that " -                "probably the wizard has been launched " -                "in an stand-alone way") - -    def eip_error_check(self): -        """ -        a version of the main app error checker, -        but integrated within the connecting page of the wizard. -        consumes the conductor error queue. -        pops errors, and add those to the wizard page -        """ -        logger.debug('eip error check from connecting page') -        errq = self.conductor.error_queue -        # XXX missing! - -    def fetch_and_validate(self): -        # XXX MOVE TO validate function in register-validation -        import time -        domain = self.field('provider_domain') -        wizard = self.wizard() -        #pconfig = wizard.providerconfig -        eipconfigchecker = wizard.eipconfigchecker() -        pCertChecker = wizard.providercertchecker( -            domain=domain) - -        # username and password are in different fields -        # if they were stored in log_in or sign_up pages. -        from_login = self.wizard().from_login -        unamek_base = 'userName' -        passwk_base = 'userPassword' -        unamek = 'login_%s' % unamek_base if from_login else unamek_base -        passwk = 'login_%s' % passwk_base if from_login else passwk_base - -        username = self.field(unamek) -        password = self.field(passwk) -        credentials = username, password - -        self.progress.show() - -        fetching_eip_conf_msg = 'Fetching eip service configuration' -        self.set_status(fetching_eip_conf_msg) -        self.progress.setValue(30) - -        # Fetching eip service -        eipconfigchecker.fetch_eip_service_config( -            domain=domain) - -        self.status_line_1.setText( -            self.get_donemsg(fetching_eip_conf_msg)) - -        getting_client_cert_msg = 'Getting client certificate' -        self.set_status(getting_client_cert_msg) -        self.progress.setValue(66) - -        # Download cert -        try: -            pCertChecker.download_new_client_cert( -                credentials=credentials, -                # FIXME FIXME FIXME -                # XXX FIX THIS!!!!! -                # BUG #638. remove verify -                # FIXME FIXME FIXME -                verify=False) -        except auth.SRPAuthenticationError as exc: -            self.set_validation_status( -                "Authentication error: %s" % exc.message) -            return False - -        time.sleep(2) -        self.status_line_2.setText( -            self.get_donemsg(getting_client_cert_msg)) - -        validating_clientcert_msg = 'Validating client certificate' -        self.set_status(validating_clientcert_msg) -        self.progress.setValue(90) -        time.sleep(2) -        self.status_line_3.setText( -            self.get_donemsg(validating_clientcert_msg)) - -        self.progress.setValue(100) -        time.sleep(3) - -        # here we go! :) -        self.run_eip_checks_for_provider_and_connect(domain) - -        #self.validation_block = self.wait_for_validation_block() - -        # XXX signal timeout! -        return True - -    # -    # wizardpage methods -    # - -    def nextId(self): -        wizard = self.wizard() -        # XXX this does not work because -        # page login has already been met -        #if self.goto_login_again: -            #next_ = "login" -        #else: -            #next_ = "lastpage" -        next_ = "lastpage" -        return wizard.get_page_index(next_) - -    def initializePage(self): -        # XXX if we're coming from signup page -        # we could say something like -        # 'registration successful!' -        self.status.setText( -            "We have " -            "all we need to connect with the provider.<br><br> " -            "Click <i>next</i> to continue. ") -        self.progress.setValue(0) -        self.progress.hide() -        self.status_line_1.setText('') -        self.status_line_2.setText('') -        self.status_line_3.setText('') - -    def validatePage(self): -        # XXX remove -        validated = self.fetch_and_validate() -        return validated diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index a4be51a9..fd48f7f9 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -40,7 +40,7 @@ class SelectProviderPage(InlineValidationPage):          self.did_cert_check = False -        self.is_done = False +        self.done = False          self.setupSteps()          self.setupUI() @@ -131,7 +131,7 @@ class SelectProviderPage(InlineValidationPage):      # certinfo -    def setupCertInfoGroup(self): +    def setupCertInfoGroup(self):  # pragma: no cover          # XXX not used now.          certinfoGroup = QtGui.QGroupBox(              self.tr("Certificate validation")) @@ -188,7 +188,6 @@ class SelectProviderPage(InlineValidationPage):          _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain)          netchecker = wizard.netchecker() -          providercertchecker = wizard.providercertchecker()          eipconfigchecker = wizard.eipconfigchecker(domain=_domain) @@ -205,6 +204,7 @@ class SelectProviderPage(InlineValidationPage):              this domain              """              try: +                #import ipdb;ipdb.set_trace()                  netchecker.check_name_resolution(                      domain) @@ -306,7 +306,7 @@ class SelectProviderPage(InlineValidationPage):          # done! -        self.is_done = True +        self.done = True          yield(("end_sentinel", 100), lambda: None)      def on_checks_validation_ready(self): @@ -316,7 +316,7 @@ class SelectProviderPage(InlineValidationPage):          self.domain_checked = True          self.completeChanged.emit()          # let's set focus... -        if self.is_done: +        if self.is_done():              self.wizard().clean_validation_error(self.current_page)              nextbutton = self.wizard().button(QtGui.QWizard.NextButton)              nextbutton.setFocus() @@ -329,7 +329,7 @@ class SelectProviderPage(InlineValidationPage):      def is_insecure_cert_trusted(self):          return self.trustProviderCertCheckBox.isChecked() -    def onTrustCheckChanged(self, state): +    def onTrustCheckChanged(self, state):  # pragma: no cover XXX          checked = False          if state == 2:              checked = True @@ -342,7 +342,7 @@ class SelectProviderPage(InlineValidationPage):          # trigger signal to redraw next button          self.completeChanged.emit() -    def add_cert_info(self, certinfo): +    def add_cert_info(self, certinfo):  # pragma: no cover XXX          self.certWarning.setText(              "Do you want to <b>trust this provider certificate?</b>")          self.certInfo.setText( @@ -351,7 +351,7 @@ class SelectProviderPage(InlineValidationPage):          self.certinfoGroup.show()      def onProviderChanged(self, text): -        self.is_done = False +        self.done = False          provider = self.providerNameEdit.text()          if provider:              self.providerCheckButton.setDisabled(False) @@ -374,7 +374,7 @@ class SelectProviderPage(InlineValidationPage):      def isComplete(self):          provider = self.providerNameEdit.text() -        if not self.is_done: +        if not self.is_done():              return False          if not provider: @@ -383,7 +383,7 @@ class SelectProviderPage(InlineValidationPage):              if self.is_insecure_cert_trusted():                  return True              if not self.did_cert_check: -                if self.is_done: +                if self.is_done():                      # XXX sure?                      return True              return False @@ -452,7 +452,7 @@ class SelectProviderPage(InlineValidationPage):          if hasattr(self, 'certinfoGroup'):              # XXX remove ?              self.certinfoGroup.hide() -        self.is_done = False +        self.done = False          self.providerCheckButton.setDisabled(True)          self.valFrame.hide()          self.steps.removeAllSteps() diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index e85723cb..7fd5c574 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -131,6 +131,16 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):              field.setDisabled(True)      # error painting +    def paintEvent(self, event): +        """ +        we hook our populate errors +        on paintEvent because we need it to catch +        when user enters the page coming from next, +        and initializePage does not cover that case. +        Maybe there's a better event to hook upon. +        """ +        super(RegisterUserPage, self).paintEvent(event) +        self.populateErrors()      def markRedAndGetFocus(self, field):          field.setStyleSheet(styles.ErrorLineEdit) @@ -193,16 +203,21 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):          """          self.bad_string = None -    def paintEvent(self, event): +    def green_validation_status(self): +        val = self.validationMsg +        val.setText(self.tr('Registration succeeded!')) +        val.setStyleSheet(styles.GreenLineEdit) + +    def reset_validation_status(self):          """ -        we hook our populate errors -        on paintEvent because we need it to catch -        when user enters the page coming from next, -        and initializePage does not cover that case. -        Maybe there's a better event to hook upon. +        empty the validation msg +        and clean the inline validation widget.          """ -        super(RegisterUserPage, self).paintEvent(event) -        self.populateErrors() +        self.validationMsg.setText('') +        self.steps.removeAllSteps() +        self.clearTable() + +    # actual checks      def _do_checks(self):          """ @@ -255,6 +270,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):                  schema="https",                  provider=provider,                  verify=verify) +            #import ipdb;ipdb.set_trace()              try:                  ok, req = signup.register_user(                      username, password) @@ -277,9 +293,15 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):                      self.tr(                          "Error during registration (%s)") % req.status_code) -            validation_msgs = json.loads(req.content) -            errors = validation_msgs.get('errors', None) -            logger.debug('validation errors: %s' % validation_msgs) +            try: +                validation_msgs = json.loads(req.content) +                errors = validation_msgs.get('errors', None) +                logger.debug('validation errors: %s' % validation_msgs) +            except ValueError: +                # probably bad json returned +                return self.fail( +                    self.tr( +                        "Could not register (bad response)"))              if errors and errors.get('login', None):                  # XXX this sometimes catch the blank username @@ -287,11 +309,13 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):                  return self.fail(                      self.tr('Username not available.')) +            return True +          logger.debug('registering user')          yield(("registering with provider", 40), register)          self.set_done() -        yield(("end_sentinel", 0), lambda: None) +        yield(("end_sentinel", 100), lambda: None)      def on_checks_validation_ready(self):          """ @@ -308,20 +332,6 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):              self.green_validation_status()              self.do_confirm_next = True -    def green_validation_status(self): -        val = self.validationMsg -        val.setText(self.tr('Registration succeeded!')) -        val.setStyleSheet(styles.GreenLineEdit) - -    def reset_validation_status(self): -        """ -        empty the validation msg -        and clean the inline validation widget. -        """ -        self.validationMsg.setText('') -        self.steps.removeAllSteps() -        self.clearTable() -      # pagewizard methods      def validatePage(self): @@ -352,10 +362,22 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn):          """          inits wizard page          """ -        provider = self.field('provider_domain') -        self.setSubTitle( -            self.tr("Register a new user with provider %s.") % -            provider) +        provider = unicode(self.field('provider_domain')) +        # hack. don't get why I'm  getting a QVariant there, +        # making segfault in tests. +        provider = QtCore.QString(provider) +        if provider: +            # here we should have provider +            # but in tests we might not. + +            # XXX this error causes a segfault on free() +            # that we might want to get fixed ... +            #self.setSubTitle( +                #self.tr("Register a new user with provider %s.") % +                        #provider) +            self.setSubTitle( +                self.tr("Register a new user with provider %s." % +                        provider))          self.validationMsg.setText('')          self.userPassword2LineEdit.setText('')          self.valFrame.hide() diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index bd3fe903..89209401 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -49,12 +49,29 @@ TODO-ish:  """ +def get_pages_dict(): +    return OrderedDict(( +        ('intro', firstrun.intro.IntroPage), +        ('providerselection', +            firstrun.providerselect.SelectProviderPage), +        ('login', firstrun.login.LogInPage), +        ('providerinfo', firstrun.providerinfo.ProviderInfoPage), +        ('providersetupvalidation', +            firstrun.providersetup.ProviderSetupValidationPage), +        ('signup', firstrun.register.RegisterUserPage), +        ('signupvalidation', +            firstrun.regvalidation.RegisterUserValidationPage), +        ('lastpage', firstrun.last.LastPage) +    )) + +  class FirstRunWizard(QtGui.QWizard):      def __init__(              self,              conductor_instance,              parent=None, +            pages_dict=None,              eip_username=None,              providers=None,              success_cb=None, is_provider_setup=False, @@ -115,20 +132,7 @@ class FirstRunWizard(QtGui.QWizard):          self.is_previously_registered = bool(self.eip_username)          self.from_login = False -        pages_dict = OrderedDict(( -            ('intro', firstrun.intro.IntroPage), -            ('providerselection', -                firstrun.providerselect.SelectProviderPage), -            ('login', firstrun.login.LogInPage), -            ('providerinfo', firstrun.providerinfo.ProviderInfoPage), -            ('providersetupvalidation', -                firstrun.providersetup.ProviderSetupValidationPage), -            ('signup', firstrun.register.RegisterUserPage), -            ('signupvalidation', -                firstrun.regvalidation.RegisterUserValidationPage), -            ('connecting', firstrun.connect.ConnectingPage), -            ('lastpage', firstrun.last.LastPage) -        )) +        pages_dict = pages_dict or get_pages_dict()          self.add_pages_from_dict(pages_dict)          self.validation_errors = {} diff --git a/src/leap/gui/progress.py b/src/leap/gui/progress.py index f0bb4cfc..ffea80de 100644 --- a/src/leap/gui/progress.py +++ b/src/leap/gui/progress.py @@ -248,6 +248,7 @@ class WithStepsMixIn(object):      # slot      #@QtCore.pyqtSlot(str, int)      def onStepStatusChanged(self, status, progress=None): +        status = unicode(status)          if status not in ("head_sentinel", "end_sentinel"):              self.add_status_line(status)          if status in ("end_sentinel"): diff --git a/src/leap/gui/tests/test_firstrun_providerselect.py b/src/leap/gui/tests/test_firstrun_providerselect.py index be7cc9c1..976c68cd 100644 --- a/src/leap/gui/tests/test_firstrun_providerselect.py +++ b/src/leap/gui/tests/test_firstrun_providerselect.py @@ -4,23 +4,29 @@ import unittest  import mock  from leap.testing import qunittest -from leap.testing import pyqt +#from leap.testing import pyqt  from PyQt4 import QtGui  #from PyQt4 import QtCore -import PyQt4.QtCore  # some weirdness with mock module +#import PyQt4.QtCore  # some weirdness with mock module  from PyQt4.QtTest import QTest -#from PyQt4.QtCore import Qt +from PyQt4.QtCore import Qt  from leap.gui import firstrun +try: +    from collections import OrderedDict +except ImportError: +    # We must be in 2.6 +    from leap.util.dicts import OrderedDict +  class TestPage(firstrun.providerselect.SelectProviderPage):      pass -class SelectProviderPageTestCase(qunittest.TestCase): +class SelectProviderPageLogicTestCase(qunittest.TestCase):      # XXX can spy on signal connections @@ -29,7 +35,18 @@ class SelectProviderPageTestCase(qunittest.TestCase):          QtGui.qApp = self.app          self.page = TestPage(None)          self.page.wizard = mock.MagicMock() -        self.page.wizard().netchecker.return_value = True + +        mocknetchecker = mock.Mock() +        self.page.wizard().netchecker.return_value = mocknetchecker +        self.mocknetchecker = mocknetchecker + +        mockpcertchecker = mock.Mock() +        self.page.wizard().providercertchecker.return_value = mockpcertchecker +        self.mockpcertchecker = mockpcertchecker + +        mockeipconfchecker = mock.Mock() +        self.page.wizard().eipconfigchecker.return_value = mockeipconfchecker +        self.mockeipconfchecker = mockeipconfchecker      def tearDown(self):          QtGui.qApp = None @@ -38,6 +55,9 @@ class SelectProviderPageTestCase(qunittest.TestCase):      def test__do_checks(self):          eq = self.assertEqual + +        self.page.providerNameEdit.setText('test_provider1') +          checks = [x for x in self.page._do_checks()]          eq(len(checks), 5)          labels = [str(x) for (x, y), z in checks] @@ -47,15 +67,135 @@ class SelectProviderPageTestCase(qunittest.TestCase):          progress = [y for (x, y), z in checks]          eq(progress, [0, 20, 40, 80, 100]) -        # XXX now: execute the functions -        # with proper mocks (for checkers and so on) -        # and try to cover all the exceptions +        # normal run, ie, no exceptions +          checkfuns = [z for (x, y), z in checks] -        #import ipdb;ipdb.set_trace()  +        namecheck, httpscheck, fetchinfo = checkfuns[1:-1] + +        self.assertTrue(namecheck()) +        self.mocknetchecker.check_name_resolution.assert_called_with( +            'test_provider1') + +        self.assertTrue(httpscheck()) +        self.mockpcertchecker.is_https_working.assert_called_with( +            "https://test_provider1", verify=True) + +        self.assertTrue(fetchinfo()) +        self.mockeipconfchecker.fetch_definition.assert_called_with( +            domain="test_provider1") + +        # XXX missing: inject failing exceptions +        # XXX TODO make it break + -    def test_next_button_is_disabled(self): -        pass +class SelectProviderPageUITestCase(qunittest.TestCase): +    # XXX can spy on signal connections +    __name__ = "Select Provider Page UI tests" + +    def setUp(self): +        self.app = QtGui.QApplication(sys.argv) +        QtGui.qApp = self.app + +        self.pagename = "providerselection" +        pages = OrderedDict(( +            (self.pagename, TestPage), +            ('providerinfo', +             firstrun.providerinfo.ProviderInfoPage))) +        self.wizard = firstrun.wizard.FirstRunWizard(None, pages_dict=pages) +        self.page = self.wizard.page(self.wizard.get_page_index(self.pagename)) + +        self.page.do_checks = mock.Mock() + +        # wizard would do this for us +        self.page.initializePage() + +    def tearDown(self): +        QtGui.qApp = None +        self.app = None +        self.wizard = None + +    def fill_provider(self): +        """ +        fills provider line edit +        """ +        keyp = QTest.keyPress +        pedit = self.page.providerNameEdit +        pedit.setFocus(True) +        for c in "testprovider": +            keyp(pedit, c) +        self.assertEqual(pedit.text(), "testprovider") + +    def del_provider(self): +        """ +        deletes entried provider in +        line edit +        """ +        keyp = QTest.keyPress +        pedit = self.page.providerNameEdit +        for c in range(len("testprovider")): +            keyp(pedit, Qt.Key_Backspace) +        self.assertEqual(pedit.text(), "") + +    def test_buttons_disabled_until_textentry(self): +        nextbutton = self.wizard.button(QtGui.QWizard.NextButton) +        checkbutton = self.page.providerCheckButton + +        self.assertFalse(nextbutton.isEnabled()) +        self.assertFalse(checkbutton.isEnabled()) + +        self.fill_provider() +        # checkbutton should be enabled +        self.assertTrue(checkbutton.isEnabled()) +        self.assertFalse(nextbutton.isEnabled()) + +        self.del_provider() +        # after rm provider checkbutton disabled again +        self.assertFalse(checkbutton.isEnabled()) +        self.assertFalse(nextbutton.isEnabled()) + +    def test_check_button_triggers_tests(self): +        checkbutton = self.page.providerCheckButton +        self.assertFalse(checkbutton.isEnabled()) +        self.assertFalse(self.page.do_checks.called) + +        self.fill_provider() + +        self.assertTrue(checkbutton.isEnabled()) +        mclick = QTest.mouseClick +        # click! +        mclick(checkbutton, Qt.LeftButton) +        self.waitFor(seconds=0.1) +        self.assertTrue(self.page.do_checks.called) + +        # XXX +        # can play with different side_effects for do_checks mock... +        # so we can see what happens with errors and so on + +    def test_page_completed_after_checks(self): +        nextbutton = self.wizard.button(QtGui.QWizard.NextButton) +        self.assertFalse(nextbutton.isEnabled()) + +        self.assertFalse(self.page.isComplete()) +        self.fill_provider() +        # simulate checks done +        self.page.done = True +        self.page.on_checks_validation_ready() +        self.assertTrue(self.page.isComplete()) +        # cannot test for nexbutton enabled +        # cause it's the the wizard loop +        # that would do that I think + +    def test_validate_page(self): +        self.assertTrue(self.page.validatePage()) + +    def test_next_id(self): +        self.assertEqual(self.page.nextId(), 1) + +    def test_paint_event(self): +        self.page.populateErrors = mock.Mock() +        self.page.paintEvent(None) +        self.page.populateErrors.assert_called_with()  if __name__ == "__main__":      unittest.main() diff --git a/src/leap/gui/tests/test_firstrun_register.py b/src/leap/gui/tests/test_firstrun_register.py new file mode 100644 index 00000000..be38e87c --- /dev/null +++ b/src/leap/gui/tests/test_firstrun_register.py @@ -0,0 +1,224 @@ +import sys +import unittest + +import mock + +from leap.testing import qunittest +#from leap.testing import pyqt + +from PyQt4 import QtGui +#from PyQt4 import QtCore +#import PyQt4.QtCore  # some weirdness with mock module + +from PyQt4.QtTest import QTest +from PyQt4.QtCore import Qt + +from leap.gui import firstrun + +try: +    from collections import OrderedDict +except ImportError: +    # We must be in 2.6 +    from leap.util.dicts import OrderedDict + + +class TestPage(firstrun.register.RegisterUserPage): + +    def field(self, field): +        if field == "provider_domain": +            return "testprovider" + + +class RegisterUserPageLogicTestCase(qunittest.TestCase): + +    # XXX can spy on signal connections +    __name__ = "register user page logic tests" + +    def setUp(self): +        self.app = QtGui.QApplication(sys.argv) +        QtGui.qApp = self.app +        self.page = TestPage(None) +        self.page.wizard = mock.MagicMock() + +        #mocknetchecker = mock.Mock() +        #self.page.wizard().netchecker.return_value = mocknetchecker +        #self.mocknetchecker = mocknetchecker +# +        #mockpcertchecker = mock.Mock() +        #self.page.wizard().providercertchecker.return_value = mockpcertchecker +        #self.mockpcertchecker = mockpcertchecker +# +        #mockeipconfchecker = mock.Mock() +        #self.page.wizard().eipconfigchecker.return_value = mockeipconfchecker +        #self.mockeipconfchecker = mockeipconfchecker + +    def tearDown(self): +        QtGui.qApp = None +        self.app = None +        self.page = None + +    def test__do_checks(self): +        eq = self.assertEqual + +        self.page.userNameLineEdit.setText('testuser') +        self.page.userPasswordLineEdit.setText('testpassword') +        self.page.userPassword2LineEdit.setText('testpassword') + +        # fake register process +        with mock.patch('leap.base.auth.LeapSRPRegister') as mockAuth: +            mockSignup = mock.MagicMock() + +            reqMockup = mock.Mock() +            # XXX should inject bad json to get error +            reqMockup.content = '{"errors": null}' +            mockSignup.register_user.return_value = (True, reqMockup) +            mockAuth.return_value = mockSignup +            checks = [x for x in self.page._do_checks()] + +            eq(len(checks), 3) +            labels = [str(x) for (x, y), z in checks] +            eq(labels, ['head_sentinel', +                        'registering with provider', +                        'end_sentinel']) +            progress = [y for (x, y), z in checks] +            eq(progress, [0, 40, 100]) + +            # normal run, ie, no exceptions + +            checkfuns = [z for (x, y), z in checks] +            passcheck, register = checkfuns[:-1] + +            self.assertTrue(passcheck()) +            #self.mocknetchecker.check_name_resolution.assert_called_with( +                #'test_provider1') + +            self.assertTrue(register()) +            #self.mockpcertchecker.is_https_working.assert_called_with( +                #"https://test_provider1", verify=True) + +        # XXX missing: inject failing exceptions +        # XXX TODO make it break + + +class RegisterUserPageUITestCase(qunittest.TestCase): + +    # XXX can spy on signal connections +    __name__ = "Register User Page UI tests" + +    def setUp(self): +        self.app = QtGui.QApplication(sys.argv) +        QtGui.qApp = self.app + +        self.pagename = "signup" +        pages = OrderedDict(( +            (self.pagename, TestPage), +            ('signupvalidation', +             firstrun.regvalidation.RegisterUserValidationPage))) +        self.wizard = firstrun.wizard.FirstRunWizard(None, pages_dict=pages) +        self.page = self.wizard.page(self.wizard.get_page_index(self.pagename)) + +        self.page.do_checks = mock.Mock() + +        # wizard would do this for us +        self.page.initializePage() + +    def tearDown(self): +        QtGui.qApp = None +        self.app = None +        self.wizard = None + +    def fill_field(self, field, text): +        """ +        fills a field (line edit) that is passed along +        :param field: the qLineEdit +        :param text: the text to be filled +        :type field: QLineEdit widget +        :type text: str +        """ +        keyp = QTest.keyPress +        field.setFocus(True) +        for c in text: +            keyp(field, c) +        self.assertEqual(field.text(), text) + +    def del_field(self, field): +        """ +        deletes entried text in +        field line edit +        :param field: the QLineEdit +        :type field: QLineEdit widget +        """ +        keyp = QTest.keyPress +        for c in range(len(field.text())): +            keyp(field, Qt.Key_Backspace) +        self.assertEqual(field.text(), "") + +    def test_buttons_disabled_until_textentry(self): +        # it's a commit button this time +        nextbutton = self.wizard.button(QtGui.QWizard.CommitButton) + +        self.assertFalse(nextbutton.isEnabled()) + +        f_username = self.page.userNameLineEdit +        f_password = self.page.userPasswordLineEdit +        f_passwor2 = self.page.userPassword2LineEdit + +        self.fill_field(f_username, "testuser") +        self.fill_field(f_password, "testpassword") +        self.fill_field(f_passwor2, "testpassword") + +        # commit should be enabled +        # XXX Need a workaround here +        # because the isComplete is not being evaluated... +        # (no event loop running??) +        #import ipdb;ipdb.set_trace() +        #self.assertTrue(nextbutton.isEnabled()) +        self.assertTrue(self.page.isComplete()) + +        self.del_field(f_username) +        self.del_field(f_password) +        self.del_field(f_passwor2) + +        # after rm fields commit button +        # should be disabled again +        #self.assertFalse(nextbutton.isEnabled()) +        self.assertFalse(self.page.isComplete()) + +    @unittest.skip +    def test_check_button_triggers_tests(self): +        checkbutton = self.page.providerCheckButton +        self.assertFalse(checkbutton.isEnabled()) +        self.assertFalse(self.page.do_checks.called) + +        self.fill_provider() + +        self.assertTrue(checkbutton.isEnabled()) +        mclick = QTest.mouseClick +        # click! +        mclick(checkbutton, Qt.LeftButton) +        self.waitFor(seconds=0.1) +        self.assertTrue(self.page.do_checks.called) + +        # XXX +        # can play with different side_effects for do_checks mock... +        # so we can see what happens with errors and so on + +    def test_validate_page(self): +        self.assertFalse(self.page.validatePage()) +        # XXX TODO MOAR CASES... +        # add errors, False +        # change done, False +        # not done, do_checks called +        # click confirm, True +        # done and do_confirm, True + +    def test_next_id(self): +        self.assertEqual(self.page.nextId(), 1) + +    def test_paint_event(self): +        self.page.populateErrors = mock.Mock() +        self.page.paintEvent(None) +        self.page.populateErrors.assert_called_with() + +if __name__ == "__main__": +    unittest.main() diff --git a/src/leap/gui/tests/test_firstrun_wizard.py b/src/leap/gui/tests/test_firstrun_wizard.py index c63781fc..091cd932 100644 --- a/src/leap/gui/tests/test_firstrun_wizard.py +++ b/src/leap/gui/tests/test_firstrun_wizard.py @@ -31,7 +31,6 @@ PAGES_DICT = dict((      ('signup', firstrun.register.RegisterUserPage),      ('signupvalidation',          firstrun.regvalidation.RegisterUserValidationPage), -    ('connecting', firstrun.connect.ConnectingPage),      ('lastpage', firstrun.last.LastPage)  )) @@ -115,7 +114,7 @@ class FirstRunWizardTestCase(qunittest.TestCase):          pagenames = ('intro', 'providerselection', 'login', 'providerinfo',                       'providersetupvalidation', 'signup', 'signupvalidation', -                     'connecting', 'lastpage') +                     'lastpage')          eq = self.assertEqual          w = self.wizard          for index, name in enumerate(pagenames): | 
