Merge lp:~ralsina/ubuntuone-windows-installer/fix_800376 into lp:ubuntuone-windows-installer

Proposed by Roberto Alsina
Status: Merged
Approved by: Roberto Alsina
Approved revision: 11
Merged at revision: 10
Proposed branch: lp:~ralsina/ubuntuone-windows-installer/fix_800376
Merge into: lp:ubuntuone-windows-installer
Diff against target: 649 lines (+450/-22)
4 files modified
data/qt/local_folders.ui (+167/-0)
ubuntuone_installer/gui/qt/gui.py (+11/-16)
ubuntuone_installer/gui/qt/local_folders.py (+159/-0)
ubuntuone_installer/gui/qt/tests/test_gui.py (+113/-6)
To merge this branch: bzr merge lp:~ralsina/ubuntuone-windows-installer/fix_800376
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Natalia Bidart (community) Approve
Review via email: mp+66194@code.launchpad.net

Commit message

First branch of the implementation of "Syncing your computer to the cloud" pages.

Description of the change

Initial implementation of a page to select which local folders will be synced to Ubuntu One.

Currently it doesn't do UDF creation or validation, because that functionality should be imported from control panel.

To test IRL (windows only):

You need ubuntuone-client and ubuntu-one-control-panel in your PYTHONPATH, for example:

PYTHONPATH=.;..\ubuntuone-client;..\ubuntuone-control-panel

On another terminal, start the SSO windows client.

Then you can start the wizard:

python bin\ubuntuone-installer-qt

You should be able to click "Agree & Install", then login with a valid user/password, then click "Next" and see this page.

In the page, you should get your "My Documents" folder added by default, and after some seconds,
the space used should be visible on that item and in the header of the list.

I intentionally faked the quota to be very low. Because of that, you should see a widget asking you to buy more space.

If you click "remove" in that row, the item should disappear, and the space used adjust accordingly to 0.

This branch doesn't close the bug, it's just a step towards that.

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

A couple of needs fixing:

* always call super() instead of explicitly calling the parent class

* the diff seems to add several (at first) not needed blank lines, can you please remove those, if they are not needed? (we usually do not add empty lines after the docstrings)

* by convention, setUp and tearDown, if defined, should be the first 2 methods after the class declaration

* this docstring:

506 + """After removing all folders, offer_frame should be hidden.
507 +
508 + Push the user over quota, it should be visible"""

should be:

506 + """After removing all folders, offer_frame should be hidden.
507 +
508 + Push the user over quota, it should be visible.

          """

review: Needs Fixing
Revision history for this message
Roberto Alsina (ralsina) wrote :

> A couple of needs fixing:
>
> * always call super() instead of explicitly calling the parent class

Ok.

>
> * the diff seems to add several (at first) not needed blank lines, can you
> please remove those, if they are not needed? (we usually do not add empty
> lines after the docstrings)

Ok.

> * by convention, setUp and tearDown, if defined, should be the first 2 methods
> after the class declaration

Ok.

> * this docstring:
>
> 506 + """After removing all folders, offer_frame should be hidden.
> 507 +
> 508 + Push the user over quota, it should be visible"""
>
> should be:
>
> 506 + """After removing all folders, offer_frame should be hidden.
> 507 +
> 508 + Push the user over quota, it should be visible.
>
> """

Ok.

All of those hsould be fixed now.

9. By Roberto Alsina

Implement the page that lets the user choose between "sync now" / "sync later" / "sync selectively"

10. By Roberto Alsina

Resolve conflicts with trunk

Revision history for this message
Natalia Bidart (nataliabidart) :
review: Approve
11. By Roberto Alsina

PEP 252

Revision history for this message
Manuel de la Peña (mandel) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'data/qt/local_folders.ui'
--- data/qt/local_folders.ui 1970-01-01 00:00:00 +0000
+++ data/qt/local_folders.ui 2011-06-29 15:13:36 +0000
@@ -0,0 +1,167 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Form</class>
4 <widget class="QWidget" name="Form">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>460</width>
10 <height>536</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_2">
17 <item>
18 <widget class="QLabel" name="label">
19 <property name="text">
20 <string>Ok! Now it's time to choose wich folder sync to the cloud from this computer.
21We started by suggesting a few</string>
22 </property>
23 <property name="textFormat">
24 <enum>Qt::RichText</enum>
25 </property>
26 <property name="wordWrap">
27 <bool>true</bool>
28 </property>
29 </widget>
30 </item>
31 <item>
32 <layout class="QHBoxLayout" name="horizontalLayout_2">
33 <item>
34 <widget class="QLabel" name="label_2">
35 <property name="text">
36 <string>Folders on my computer</string>
37 </property>
38 </widget>
39 </item>
40 <item>
41 <spacer name="horizontalSpacer_3">
42 <property name="orientation">
43 <enum>Qt::Horizontal</enum>
44 </property>
45 <property name="sizeHint" stdset="0">
46 <size>
47 <width>40</width>
48 <height>20</height>
49 </size>
50 </property>
51 </spacer>
52 </item>
53 <item>
54 <widget class="QPushButton" name="pushButton_2">
55 <property name="text">
56 <string>Add a folder</string>
57 </property>
58 </widget>
59 </item>
60 </layout>
61 </item>
62 <item>
63 <widget class="QTreeWidget" name="folder_list">
64 <attribute name="headerStretchLastSection">
65 <bool>false</bool>
66 </attribute>
67 <column>
68 <property name="text">
69 <string>My Folders</string>
70 </property>
71 </column>
72 <column>
73 <property name="text">
74 <string>Space (Total)</string>
75 </property>
76 </column>
77 <column>
78 <property name="text">
79 <string>Remove</string>
80 </property>
81 </column>
82 </widget>
83 </item>
84 <item>
85 <widget class="QCheckBox" name="checkBox">
86 <property name="text">
87 <string>Connect automatically when computer starts</string>
88 </property>
89 </widget>
90 </item>
91 <item>
92 <widget class="QCheckBox" name="checkBox_2">
93 <property name="text">
94 <string>Automatically sync all selected folders from this computer to the cloud</string>
95 </property>
96 </widget>
97 </item>
98 <item>
99 <widget class="QFrame" name="offer_frame">
100 <property name="frameShape">
101 <enum>QFrame::StyledPanel</enum>
102 </property>
103 <property name="frameShadow">
104 <enum>QFrame::Raised</enum>
105 </property>
106 <layout class="QVBoxLayout" name="verticalLayout">
107 <property name="leftMargin">
108 <number>0</number>
109 </property>
110 <property name="rightMargin">
111 <number>0</number>
112 </property>
113 <item>
114 <widget class="QLabel" name="offer_label">
115 <property name="text">
116 <string>The folders you have selected to sync take over your 2GB space. You can remove some folders or add some extra space</string>
117 </property>
118 <property name="wordWrap">
119 <bool>true</bool>
120 </property>
121 </widget>
122 </item>
123 <item>
124 <layout class="QHBoxLayout" name="horizontalLayout">
125 <item>
126 <spacer name="horizontalSpacer">
127 <property name="orientation">
128 <enum>Qt::Horizontal</enum>
129 </property>
130 <property name="sizeHint" stdset="0">
131 <size>
132 <width>40</width>
133 <height>20</height>
134 </size>
135 </property>
136 </spacer>
137 </item>
138 <item>
139 <widget class="QPushButton" name="pushButton">
140 <property name="text">
141 <string>add more space</string>
142 </property>
143 </widget>
144 </item>
145 <item>
146 <spacer name="horizontalSpacer_2">
147 <property name="orientation">
148 <enum>Qt::Horizontal</enum>
149 </property>
150 <property name="sizeHint" stdset="0">
151 <size>
152 <width>40</width>
153 <height>20</height>
154 </size>
155 </property>
156 </spacer>
157 </item>
158 </layout>
159 </item>
160 </layout>
161 </widget>
162 </item>
163 </layout>
164 </widget>
165 <resources/>
166 <connections/>
167</ui>
0168
=== modified file 'ubuntuone_installer/gui/qt/gui.py'
--- ubuntuone_installer/gui/qt/gui.py 2011-06-28 19:45:45 +0000
+++ ubuntuone_installer/gui/qt/gui.py 2011-06-29 15:13:36 +0000
@@ -72,6 +72,7 @@
72 license_ui,72 license_ui,
73 congratulations_ui,73 congratulations_ui,
74)74)
75from ubuntuone_installer.gui.qt.local_folders import LocalFoldersPage
75from ubuntuone_installer.gui.qt.sync_now_or_later import SyncNowOrLaterPage76from ubuntuone_installer.gui.qt.sync_now_or_later import SyncNowOrLaterPage
7677
77_ = gettext.gettext78_ = gettext.gettext
@@ -87,7 +88,7 @@
87 """Wizard Page that displays the license info and links to the GPL."""88 """Wizard Page that displays the license info and links to the GPL."""
8889
89 def __init__(self, parent=None):90 def __init__(self, parent=None):
90 QtGui.QWizardPage.__init__(self, parent)91 super(LicensePage, self).__init__(parent)
91 self.ui = license_ui.Ui_Form()92 self.ui = license_ui.Ui_Form()
92 self.ui.setupUi(self)93 self.ui.setupUi(self)
93 self.setCommitPage(False)94 self.setCommitPage(False)
@@ -97,7 +98,6 @@
9798
98 def initializePage(self):99 def initializePage(self):
99 """Setup UI details."""100 """Setup UI details."""
100
101 # Set the right texts and connections for buttons101 # Set the right texts and connections for buttons
102 self.setButtonText(QtGui.QWizard.NextButton, _("Agree && Install"))102 self.setButtonText(QtGui.QWizard.NextButton, _("Agree && Install"))
103 self.setButtonText(QtGui.QWizard.CancelButton,103 self.setButtonText(QtGui.QWizard.CancelButton,
@@ -124,7 +124,6 @@
124124
125 def print_document(self, button_id):125 def print_document(self, button_id):
126 """Print the document displayed in textBrowser."""126 """Print the document displayed in textBrowser."""
127
128 if button_id == QtGui.QWizard.CustomButton1:127 if button_id == QtGui.QWizard.CustomButton1:
129 document = self.ui.textBrowser.document()128 document = self.ui.textBrowser.document()
130 printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)129 printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
@@ -143,7 +142,7 @@
143 """Wizard Page that lets the user Sign into Ubuntu One."""142 """Wizard Page that lets the user Sign into Ubuntu One."""
144143
145 def __init__(self, ui=None, controller=None, parent=None):144 def __init__(self, ui=None, controller=None, parent=None):
146 QtGui.QWizardPage.__init__(self, parent)145 super(SignInPage, self).__init__(parent)
147 self.ui = ui146 self.ui = ui
148 self.ui.setupUi(self)147 self.ui.setupUi(self)
149 self.controller = controller148 self.controller = controller
@@ -155,7 +154,6 @@
155154
156 def initializePage(self):155 def initializePage(self):
157 """Setup UI details."""156 """Setup UI details."""
158
159 self.setButtonText(QtGui.QWizard.CancelButton,157 self.setButtonText(QtGui.QWizard.CancelButton,
160 _("Close window and setup later"))158 _("Close window and setup later"))
161 # Layout without custom button 1,159 # Layout without custom button 1,
@@ -175,7 +173,7 @@
175 """Wizard Page that lets a current user Sign into Ubuntu One."""173 """Wizard Page that lets a current user Sign into Ubuntu One."""
176174
177 def __init__(self, ui=None, controller=None, parent=None):175 def __init__(self, ui=None, controller=None, parent=None):
178 QtGui.QWizardPage.__init__(self, parent)176 super(CurrentUserSignInPage, self).__init__(parent)
179 self.ui = ui177 self.ui = ui
180 self.ui.setupUi(self)178 self.ui.setupUi(self)
181 self.controller = controller179 self.controller = controller
@@ -185,9 +183,6 @@
185 # Invalid names of Qt-inherited methods183 # Invalid names of Qt-inherited methods
186 # pylint: disable=C0103184 # pylint: disable=C0103
187185
188 def initializePage(self):
189 """Setup UI details."""
190
191 def nextId(self):186 def nextId(self):
192 """Provide the next id."""187 """Provide the next id."""
193 return self.next188 return self.next
@@ -197,7 +192,7 @@
197 """Shown after SSO login, before setup."""192 """Shown after SSO login, before setup."""
198193
199 def __init__(self, ui=None, controller=None, parent=None):194 def __init__(self, ui=None, controller=None, parent=None):
200 QtGui.QWizardPage.__init__(self, parent)195 super(SuccessPage, self).__init__(parent)
201 self.ui = ui196 self.ui = ui
202 self.ui.setupUi(self)197 self.ui.setupUi(self)
203 self.controller = controller198 self.controller = controller
@@ -225,7 +220,7 @@
225 """Final page of the wizard."""220 """Final page of the wizard."""
226221
227 def __init__(self, parent=None):222 def __init__(self, parent=None):
228 QtGui.QWizardPage.__init__(self, parent)223 super(CongratulationsPage, self).__init__(parent)
229 self.ui = congratulations_ui.Ui_Form()224 self.ui = congratulations_ui.Ui_Form()
230 self.ui.setupUi(self)225 self.ui.setupUi(self)
231 self.setFinalPage(True)226 self.setFinalPage(True)
@@ -235,7 +230,6 @@
235230
236 def initializePage(self):231 def initializePage(self):
237 """Setup UI details."""232 """Setup UI details."""
238
239 # We need custom buttons233 # We need custom buttons
240 self.wizard().setButtonText(QtGui.QWizard.FinishButton,234 self.wizard().setButtonText(QtGui.QWizard.FinishButton,
241 _("Go to my Ubuntu One dashboard"))235 _("Go to my Ubuntu One dashboard"))
@@ -269,7 +263,6 @@
269263
270 def __init__(self, close_callback=None):264 def __init__(self, close_callback=None):
271 """Initialize this instance."""265 """Initialize this instance."""
272
273 # Used to decide the next page dynamically266 # Used to decide the next page dynamically
274 self._next_id = None267 self._next_id = None
275268
@@ -279,7 +272,7 @@
279 self.tc_url = TC_URL272 self.tc_url = TC_URL
280 self.ping_url = PING_URL273 self.ping_url = PING_URL
281274
282 QtGui.QWizard.__init__(self)275 super(MainWindow, self).__init__()
283 self.close_callback = close_callback276 self.close_callback = close_callback
284277
285 self.creds = Credentials(278 self.creds = Credentials(
@@ -346,6 +339,8 @@
346339
347 # End of SSO pages340 # End of SSO pages
348341
342 self.local_folders_page = LocalFoldersPage()
343 self.local_folders_page_id = self.addPage(self.local_folders_page)
349 self.SYNC_NOW_OR_LATER_PAGE = self.addPage(SyncNowOrLaterPage())344 self.SYNC_NOW_OR_LATER_PAGE = self.addPage(SyncNowOrLaterPage())
350 self.CONGRATULATIONS_PAGE = self.addPage(CongratulationsPage())345 self.CONGRATULATIONS_PAGE = self.addPage(CongratulationsPage())
351346
@@ -363,13 +358,13 @@
363 """Called on successful login."""358 """Called on successful login."""
364 self._next_id = self.SUCCESS_PAGE359 self._next_id = self.SUCCESS_PAGE
365 self.next()360 self.next()
366 self._next_id = self.SYNC_NOW_OR_LATER_PAGE361 self._next_id = self.local_folders_page_id
367362
368 def registration_success_slot(self):363 def registration_success_slot(self):
369 """Called on successful registration."""364 """Called on successful registration."""
370 self._next_id = self.SUCCESS_PAGE365 self._next_id = self.SUCCESS_PAGE
371 self.next()366 self.next()
372 self._next_id = self.SYNC_NOW_OR_LATER_PAGE367 self._next_id = self.local_folders_page_id
373368
374 def done(self, result):369 def done(self, result):
375 """The main window is being closed, call any custom callback."""370 """The main window is being closed, call any custom callback."""
376371
=== added file 'ubuntuone_installer/gui/qt/local_folders.py'
--- ubuntuone_installer/gui/qt/local_folders.py 1970-01-01 00:00:00 +0000
+++ ubuntuone_installer/gui/qt/local_folders.py 2011-06-29 15:13:36 +0000
@@ -0,0 +1,159 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Roberto Alsina <roberto.alsina@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Widget to create UDFs in the Windows Install Wizard."""
20
21import ctypes
22import gettext
23import os
24import threading
25import Queue
26
27from PyQt4 import QtCore, QtGui
28
29from ubuntuone.controlpanel.gui import humanize
30
31from ubuntuone_installer.gui.qt.ui import local_folders_ui
32
33_ = gettext.gettext
34
35
36class FolderItem(QtGui.QTreeWidgetItem):
37 """Class representing a folder in the folder list UI."""
38 def __init__(self, strings, path=None, queue=None):
39 super(FolderItem, self).__init__(strings)
40 self.thread = CalculateSize(path, queue)
41 self.thread.start()
42 self.size = None
43 self.path = path
44
45
46class CalculateSize(threading.Thread):
47 """Class to calculate the size of a folder in the background."""
48 def __init__(self, path_name, queue):
49 self.path_name = path_name
50 self.queue = queue
51 self._stop = False
52 super(CalculateSize, self).__init__()
53 self.daemon = True
54
55 def run(self):
56 total_size = 0
57 for dirpath, dirnames, filenames in os.walk(self.path_name):
58 for f in filenames:
59 fp = os.path.join(dirpath, f)
60 total_size += os.path.getsize(fp)
61 self.queue.put([self.path_name, total_size])
62
63
64class LocalFoldersPage(QtGui.QWizardPage):
65 """Wizard page to create UDFs in the Windows Installer."""
66 def __init__(self, parent=None):
67 super(LocalFoldersPage, self).__init__(parent)
68 self.setTitle(_("Syncing your computer with the cloud"))
69 self.ui = local_folders_ui.Ui_Form()
70 self.ui.setupUi(self)
71
72 header_view = self.ui.folder_list.header()
73 header_view.setResizeMode(0, header_view.Stretch)
74
75 self.queue = Queue.Queue()
76 self.timer = QtCore.QTimer()
77 self.items = {}
78 for folder_name in self.default_folders():
79 self.add_folder(folder_name)
80 self.update_sizes()
81 self.timer.start(2000)
82 self.timer.timeout.connect(self.update_sizes)
83
84 def initializePage(self):
85 self.wizard()._next_id = None
86
87 def quota(self):
88 """The quota available to the user."""
89 # FIXME: get this from real life
90 return 2 * 1024 * 1024
91
92 def default_folders(self):
93 """Return a list of the folders to add by default."""
94 # Special Folder "My Documents"
95 dll = ctypes.windll.shell32
96 buf = ctypes.create_string_buffer(300)
97 dll.SHGetSpecialFolderPathA(None, buf, 0x0005, False)
98 return [buf.value, ]
99
100 def add_folder(self, path):
101 """Add a folder to the list."""
102 if path in self.items:
103 return None
104 # FIXME: the path should actually be sent to u1cp to verify as valid
105 item = FolderItem([path, "", _("Remove")], path=path, queue=self.queue)
106 self.ui.folder_list.addTopLevelItem(item)
107 self.items[path] = item
108 return item
109
110 def update_sizes(self):
111 """Poll the queue were the threads put the size info."""
112 try:
113 path, size = self.queue.get(False)
114 item = self.items.get(path)
115 if item:
116 item.size = size
117 item.setText(1, humanize(size))
118 except Queue.Empty:
119 pass
120 total = 0
121 for path, item in self.items.items():
122 if item.size is None:
123 total = _("Calculating")
124 break
125 total += item.size
126
127 if isinstance(total, long):
128 self.show_hide_offer(total)
129 total = humanize(total)
130 else:
131 self.show_hide_offer(0)
132 self.ui.folder_list.headerItem().setText(1, _("Space (%s)" % total))
133
134 def show_hide_offer(self, cur_size):
135 """Show or hide the offer to buy space according to the total size."""
136 quota = self.quota()
137
138 if cur_size > quota:
139 self.ui.offer_frame.setVisible(True)
140 else:
141 self.ui.offer_frame.setVisible(False)
142
143 self.ui.offer_label.setText(_("The folders you have selected to sync "
144 "take over your %s space. You can remove some folders or add "
145 "some extra space" % humanize(quota)))
146
147 def stop_threads(self):
148 """Stop all pending threads."""
149 for path, item in self.items:
150 item.thread._stop = True
151
152 def on_folder_list_itemClicked(self, item, column):
153 """Delete folder from the list."""
154 if column == 2:
155 del(self.items[item.path])
156 item.thread._stop = True
157 self.ui.folder_list.takeTopLevelItem(
158 self.ui.folder_list.indexOfTopLevelItem(item))
159 self.update_sizes()
0160
=== modified file 'ubuntuone_installer/gui/qt/tests/test_gui.py'
--- ubuntuone_installer/gui/qt/tests/test_gui.py 2011-06-28 19:18:35 +0000
+++ ubuntuone_installer/gui/qt/tests/test_gui.py 2011-06-29 15:13:36 +0000
@@ -19,6 +19,11 @@
1919
20"""Tests for the Qt UI."""20"""Tests for the Qt UI."""
2121
22import os
23import Queue
24import shutil
25import tempfile
26
22from PyQt4 import QtCore27from PyQt4 import QtCore
2328
24from ubuntuone.credentials import (29from ubuntuone.credentials import (
@@ -32,6 +37,7 @@
32from ubuntuone_installer.gui.qt import gui37from ubuntuone_installer.gui.qt import gui
33from ubuntuone_installer.gui.qt.tests import BaseTestCase38from ubuntuone_installer.gui.qt.tests import BaseTestCase
34from ubuntuone_installer.gui.qt.embedded_sso import UbuntuSSOClientGUI39from ubuntuone_installer.gui.qt.embedded_sso import UbuntuSSOClientGUI
40from ubuntuone_installer.gui.qt import local_folders
3541
36TOKEN = {u'consumer_key': u'xQ7xDAz',42TOKEN = {u'consumer_key': u'xQ7xDAz',
37 u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy',43 u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy',
@@ -96,7 +102,8 @@
96102
97 def test_start_control_panel_on_finishing(self):103 def test_start_control_panel_on_finishing(self):
98 """If done is called with result=1, the control panel104 """If done is called with result=1, the control panel
99 should be called."""105 should be called.
106 """
100 self.patch(gui.subprocess, "Popen", self._set_called)107 self.patch(gui.subprocess, "Popen", self._set_called)
101 self.ui.done(result=1)108 self.ui.done(result=1)
102 self.assertEqual(self._called,109 self.assertEqual(self._called,
@@ -104,7 +111,8 @@
104111
105 def test_not_start_control_panel_on_cancel(self):112 def test_not_start_control_panel_on_cancel(self):
106 """If done is called with result=0, the control panel113 """If done is called with result=0, the control panel
107 should NOT be called."""114 should NOT be called.
115 """
108 self.patch(gui.subprocess, "Popen", self._set_called)116 self.patch(gui.subprocess, "Popen", self._set_called)
109 self.ui.done(result=0)117 self.ui.done(result=0)
110 self.assertEqual(self._called, False)118 self.assertEqual(self._called, False)
@@ -143,8 +151,7 @@
143 congrats_page.ui.progressContainer.isVisible(), False)151 congrats_page.ui.progressContainer.isVisible(), False)
144152
145 def test_credential_parameters(self):153 def test_credential_parameters(self):
146 """Test if the credentials are created the same way154 """Compare credential parameters with control panel's."""
147 as in control panel."""
148 self.assertEqual(self.ui.creds.kwargs, {155 self.assertEqual(self.ui.creds.kwargs, {
149 'app_name': APP_NAME,156 'app_name': APP_NAME,
150 'ui_module': "ubuntuone_installer.gui.qt.embedded_sso",157 'ui_module': "ubuntuone_installer.gui.qt.embedded_sso",
@@ -160,7 +167,6 @@
160167
161 def setUp(self):168 def setUp(self):
162 """Initialize this test instance."""169 """Initialize this test instance."""
163
164 self.kwargs = {170 self.kwargs = {
165 'app_name': APP_NAME,171 'app_name': APP_NAME,
166 'tc_url': TC_URL,172 'tc_url': TC_URL,
@@ -171,8 +177,109 @@
171177
172 def test_sso_client_gui(self):178 def test_sso_client_gui(self):
173 """Ensure the class stores the right parameters."""179 """Ensure the class stores the right parameters."""
174
175 self.assertEqual(isinstance(180 self.assertEqual(isinstance(
176 self.ui.controller,181 self.ui.controller,
177 ubuntu_sso.qt.controllers.UbuntuSSOWizardController), True)182 ubuntu_sso.qt.controllers.UbuntuSSOWizardController), True)
178 self.assertEqual(self.ui.view, True)183 self.assertEqual(self.ui.view, True)
184
185
186class LocalFoldersTestCase(BaseTestCase):
187 """Test the LocalFoldersPage code."""
188
189 class_ui = local_folders.LocalFoldersPage
190
191 def setUp(self):
192 """Initialize this test instance."""
193 # Create a test folder with a known size
194 self.tmpdir = tempfile.mkdtemp()
195 f = open(os.path.join(self.tmpdir, 'test_file'), 'wb')
196 f.write(" " * 600)
197 f.close()
198 os.mkdir(os.path.join(self.tmpdir, 'test_dir'))
199 f = open(os.path.join(self.tmpdir, 'test_dir', 'test_file_2'), 'wb')
200 f.write(" " * 737)
201 f.close()
202 super(LocalFoldersTestCase, self).setUp()
203
204 def tearDown(self):
205 """Remove the temporary tree."""
206 shutil.rmtree(self.tmpdir)
207 BaseTestCase.tearDown(self)
208
209 def test_size_calculation(self):
210 """Test the recursive folder size calculation."""
211 self.queue = Queue.Queue()
212 self.csize = local_folders.CalculateSize(self.tmpdir, self.queue)
213 self.csize.run()
214 path, size = self.queue.get()
215 self.assertEqual(path, self.tmpdir)
216 self.assertEqual(size, 1337)
217
218 def test_item_addition_removal(self):
219 """Add an item (plus the default one), then remove them."""
220 self.ui.add_folder(self.tmpdir)
221 self.assertEqual(2, self.ui.ui.folder_list.topLevelItemCount())
222 self.ui.on_folder_list_itemClicked(
223 self.ui.ui.folder_list.topLevelItem(0), 2)
224 self.ui.on_folder_list_itemClicked(
225 self.ui.ui.folder_list.topLevelItem(0), 2)
226 self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount())
227 self.assertEqual({}, self.ui.items)
228
229 def test_total_size(self):
230 """Test that the header reflects the change in item sizes."""
231 while self.ui.ui.folder_list.topLevelItemCount():
232 self.ui.on_folder_list_itemClicked(
233 self.ui.ui.folder_list.topLevelItem(0), 2)
234 self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount())
235 item = self.ui.add_folder(self.tmpdir)
236 item.size = 1337
237 self.ui.update_sizes()
238 self.assertEqual(unicode(self.ui.ui.folder_list.headerItem().text(1)),
239 u"Space (1337)")
240
241 def test_add_twice(self):
242 """Behaviour for adding the same folder twice:
243
244 * It's added only once.
245 """
246 while self.ui.ui.folder_list.topLevelItemCount():
247 self.ui.on_folder_list_itemClicked(
248 self.ui.ui.folder_list.topLevelItem(0), 2)
249 self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount())
250 self.ui.add_folder(self.tmpdir)
251 self.ui.add_folder(self.tmpdir)
252 self.assertEqual(1, self.ui.ui.folder_list.topLevelItemCount())
253
254 def test_add_missing_folder(self):
255 """Behaviour for adding a folder that doesn't exist:
256
257 * It's added.
258 * Has size 0.
259 """
260
261 while self.ui.ui.folder_list.topLevelItemCount():
262 self.ui.on_folder_list_itemClicked(
263 self.ui.ui.folder_list.topLevelItem(0), 2)
264 self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount())
265 item = self.ui.add_folder(os.path.join("xyzzy", "xyzzy", "xyzzy"))
266 self.assertEqual(1, self.ui.ui.folder_list.topLevelItemCount())
267 item.thread.run()
268 self.ui.update_sizes()
269 self.assertEqual(0, item.size)
270 # world did not explode
271
272 def test_over_quota(self):
273 """After removing all folders, offer_frame should be hidden.
274
275 Push the user over quota, it should be visible.
276 """
277 self.patch(self.ui.ui.offer_frame, "setVisible", self._set_called)
278 while self.ui.ui.folder_list.topLevelItemCount():
279 self.ui.on_folder_list_itemClicked(
280 self.ui.ui.folder_list.topLevelItem(0), 2)
281 self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount())
282 self.ui.update_sizes()
283 self.assertEqual(self._called, ((False,), {}))
284 self.ui.show_hide_offer(self.ui.quota() + 1)
285 self.assertEqual(self._called, ((True,), {}))

Subscribers

People subscribed via source and target branches