Merge lp:~jonas-drange/ubuntu-system-settings/vpn into lp:ubuntu-system-settings

Proposed by Jonas G. Drange
Status: Merged
Approved by: Jonas G. Drange
Approved revision: 1612
Merged at revision: 1615
Proposed branch: lp:~jonas-drange/ubuntu-system-settings/vpn
Merge into: lp:ubuntu-system-settings
Diff against target: 905 lines (+763/-5)
11 files modified
debian/control (+4/-4)
plugins/CMakeLists.txt (+1/-0)
plugins/vpn/CMakeLists.txt (+7/-0)
plugins/vpn/PageComponent.qml (+132/-0)
plugins/vpn/network-vpn.svg (+206/-0)
plugins/vpn/vpn.settings (+20/-0)
tests/autopilot/ubuntu_system_settings/__init__.py (+135/-0)
tests/autopilot/ubuntu_system_settings/tests/__init__.py (+61/-0)
tests/autopilot/ubuntu_system_settings/tests/connectivity.py (+129/-1)
tests/autopilot/ubuntu_system_settings/tests/test_plugins.py (+7/-0)
tests/autopilot/ubuntu_system_settings/tests/test_vpn.py (+61/-0)
To merge this branch: bzr merge lp:~jonas-drange/ubuntu-system-settings/vpn
Reviewer Review Type Date Requested Status
Ken VanDine Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+286352@code.launchpad.net

Commit message

New VPN panel with happy path test

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Code review looks good with one nit pick about a blank line, see inline comment. I'm going to go ahead and approve it anyway and trust you'll remove that line. I wasn't able to test it, but I know you and bill have tested it.

review: Approve
1611. By Jonas G. Drange

removing blank line

1612. By Jonas G. Drange

fix bad ref to objectName

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-03-12 03:41:03 +0000
3+++ debian/control 2016-03-14 15:06:51 +0000
4@@ -71,18 +71,18 @@
5 gsettings-desktop-schemas,
6 gsettings-ubuntu-schemas (>= 0.0.4),
7 indicator-bluetooth (>> 0.0.6+13.10.20131010),
8- indicator-network (>= 0.5.0+13.10.20130918),
9+ indicator-network (>= 0.7.1),
10 indicator-power (>= 12.10.6+15.04.20150130),
11 powerd (>= 0.15) | gnome-settings-daemon,
12 qmenumodel-qml,
13 qml-module-qt-labs-folderlistmodel,
14- qml-module-ubuntu-connectivity (>= 0.5.5),
15+ qml-module-ubuntu-connectivity (>= 0.7.1),
16 qml-module-qtmultimedia | qml-module-qtmultimedia-gles,
17 qtdeclarative5-gsettings1.0 (>=0.1+14.10.20140801.1),
18 qtdeclarative5-ofono0.2 (>=0.82~),
19 qml-module-qtsysteminfo,
20 qtdeclarative5-ubuntu-content1,
21- qtdeclarative5-ubuntu-settings-components (>> 0.6),
22+ qtdeclarative5-ubuntu-settings-components (>> 0.7+15.04.20160310),
23 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1584) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1584),
24 suru-icon-theme (>= 14.04+15.04.20150813~),
25 whoopsie-preferences (>= 0.9),
26@@ -96,7 +96,7 @@
27 python3-dbus,
28 python3-xdg,
29 gir1.2-glib-2.0,
30- qml-module-ubuntu-connectivity
31+ qml-module-ubuntu-connectivity (>= 0.7.1)
32 Recommends: ubuntu-system-settings-online-accounts,
33 ubuntu-touch-sounds,
34 Conflicts: ubuntu-system-settings-example
35
36=== modified file 'plugins/CMakeLists.txt'
37--- plugins/CMakeLists.txt 2015-08-25 10:36:13 +0000
38+++ plugins/CMakeLists.txt 2016-03-14 15:06:51 +0000
39@@ -20,4 +20,5 @@
40 add_subdirectory(sound)
41 add_subdirectory(system-update)
42 add_subdirectory(time-date)
43+add_subdirectory(vpn)
44 add_subdirectory(wifi)
45
46=== added directory 'plugins/vpn'
47=== added file 'plugins/vpn/CMakeLists.txt'
48--- plugins/vpn/CMakeLists.txt 1970-01-01 00:00:00 +0000
49+++ plugins/vpn/CMakeLists.txt 2016-03-14 15:06:51 +0000
50@@ -0,0 +1,7 @@
51+set(QML_SOURCES
52+ PageComponent.qml
53+)
54+
55+install(FILES vpn.settings DESTINATION ${PLUGIN_MANIFEST_DIR})
56+install(FILES network-vpn.svg DESTINATION ${PLUGIN_MANIFEST_DIR}/icons)
57+install(FILES ${QML_SOURCES} DESTINATION ${PLUGIN_QML_DIR}/vpn)
58
59=== added file 'plugins/vpn/PageComponent.qml'
60--- plugins/vpn/PageComponent.qml 1970-01-01 00:00:00 +0000
61+++ plugins/vpn/PageComponent.qml 2016-03-14 15:06:51 +0000
62@@ -0,0 +1,132 @@
63+/*
64+ * This file is part of system-settings
65+ *
66+ * Copyright (C) 2016 Canonical Ltd.
67+ *
68+ * Contact: Jonas G. Drange <jonas.drange@canonical.com>
69+ *
70+ * This program is free software: you can redistribute it and/or modify it
71+ * under the terms of the GNU General Public License version 3, as published
72+ * by the Free Software Foundation.
73+ *
74+ * This program is distributed in the hope that it will be useful, but
75+ * WITHOUT ANY WARRANTY; without even the implied warranties of
76+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
77+ * PURPOSE. See the GNU General Public License for more details.
78+ *
79+ * You should have received a copy of the GNU General Public License along
80+ * with this program. If not, see <http://www.gnu.org/licenses/>.
81+ */
82+
83+import QtQuick 2.4
84+import SystemSettings 1.0
85+import Ubuntu.Components 1.3
86+import Ubuntu.Components.ListItems 1.3 as ListItem
87+import Ubuntu.Components.Popups 1.3
88+import Ubuntu.Connectivity 1.0
89+import Ubuntu.Settings.Vpn 0.1
90+
91+ItemPage {
92+ id: root
93+ title: i18n.tr("VPN")
94+ objectName: "vpnPage"
95+ flickable: scrollWidget
96+
97+ property var diag
98+
99+ function openConnection(connection, isNew) {
100+ pageStack.push(vpnEditorDialog, {
101+ "connection": connection,
102+ "isNew": isNew
103+ });
104+ }
105+
106+ function previewConnection(connection) {
107+ diag = PopupUtils.open(vpnPreviewDialog, root, {"connection": connection});
108+ }
109+
110+ Flickable {
111+ id: scrollWidget
112+ anchors {
113+ fill: parent
114+ topMargin: units.gu(1)
115+ bottomMargin: units.gu(1)
116+ }
117+ contentHeight: contentItem.childrenRect.height
118+ boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
119+
120+ Column {
121+ anchors { left: parent.left; right: parent.right }
122+
123+ VpnList {
124+ id: list
125+ anchors { left: parent.left; right: parent.right }
126+ model: Connectivity.vpnConnections
127+
128+ onClickedConnection: previewConnection(connection)
129+ }
130+
131+ ListItem.Caption {
132+ // We do not yet support configuration files.
133+ visible: false
134+ anchors {
135+ left: parent.left
136+ right: parent.right
137+ }
138+ text : i18n.tr("To add a VPN configuration, download its config file or configure it manually.")
139+ }
140+
141+ ListItem.SingleControl {
142+ control: Button {
143+ objectName: "addVpnButton"
144+ text : i18n.tr("Add Manual Configuration…")
145+ onClicked: Connectivity.vpnConnections.add(VpnConnection.OPENVPN)
146+ }
147+ }
148+ }
149+ }
150+
151+ Component {
152+ id: vpnEditorDialog
153+ VpnEditor {
154+ onTypeChanged: {
155+ connection.remove();
156+ pageStack.pop();
157+ Connectivity.vpnConnections.add(type);
158+ }
159+ onReconnectionPrompt: PopupUtils.open(reconnPrompt)
160+ }
161+ }
162+
163+ Component {
164+ id: vpnPreviewDialog
165+ VpnPreviewDialog {
166+ onChangeClicked: {
167+ PopupUtils.close(diag);
168+ openConnection(connection);
169+ }
170+ }
171+ }
172+
173+ Component {
174+ id: reconnPrompt
175+ Dialog {
176+ id: reconnPromptDiag
177+ title: i18n.tr("VPN reconnection required.")
178+ text: i18n.tr("You need to reconnect for changes to have an effect.")
179+
180+ ListItem.SingleControl {
181+ control: Button {
182+ width: parent.width
183+ text : i18n.tr("OK")
184+ onClicked: PopupUtils.close(reconnPromptDiag);
185+ }
186+ }
187+ }
188+ }
189+
190+ Connections {
191+ target: Connectivity.vpnConnections
192+ onAddFinished: openConnection(connection, true)
193+ }
194+}
195
196=== added file 'plugins/vpn/network-vpn.svg'
197--- plugins/vpn/network-vpn.svg 1970-01-01 00:00:00 +0000
198+++ plugins/vpn/network-vpn.svg 2016-03-14 15:06:51 +0000
199@@ -0,0 +1,206 @@
200+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
201+<!-- Created with Inkscape (http://www.inkscape.org/) -->
202+
203+<svg
204+ xmlns:dc="http://purl.org/dc/elements/1.1/"
205+ xmlns:cc="http://creativecommons.org/ns#"
206+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
207+ xmlns:svg="http://www.w3.org/2000/svg"
208+ xmlns="http://www.w3.org/2000/svg"
209+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
210+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
211+ width="96"
212+ height="96"
213+ id="svg4874"
214+ version="1.1"
215+ inkscape:version="0.91+devel r"
216+ viewBox="0 0 96 96.000001"
217+ sodipodi:docname="network-vpn.svg">
218+ <defs
219+ id="defs4876" />
220+ <sodipodi:namedview
221+ id="base"
222+ pagecolor="#ffffff"
223+ bordercolor="#666666"
224+ borderopacity="1.0"
225+ inkscape:pageopacity="0.0"
226+ inkscape:pageshadow="2"
227+ inkscape:zoom="7.0249993"
228+ inkscape:cx="-4.6192206"
229+ inkscape:cy="58.206397"
230+ inkscape:document-units="px"
231+ inkscape:current-layer="g4780"
232+ showgrid="true"
233+ showborder="true"
234+ fit-margin-top="0"
235+ fit-margin-left="0"
236+ fit-margin-right="0"
237+ fit-margin-bottom="0"
238+ inkscape:snap-bbox="true"
239+ inkscape:bbox-paths="true"
240+ inkscape:bbox-nodes="true"
241+ inkscape:snap-bbox-edge-midpoints="true"
242+ inkscape:snap-bbox-midpoints="true"
243+ inkscape:object-paths="true"
244+ inkscape:snap-intersection-paths="true"
245+ inkscape:object-nodes="false"
246+ inkscape:snap-smooth-nodes="false"
247+ inkscape:snap-midpoints="false"
248+ inkscape:snap-object-midpoints="true"
249+ inkscape:snap-center="true"
250+ showguides="true"
251+ inkscape:guide-bbox="true"
252+ inkscape:snap-global="false"
253+ inkscape:snap-nodes="true"
254+ inkscape:snap-others="false">
255+ <inkscape:grid
256+ type="xygrid"
257+ id="grid5451"
258+ empspacing="8" />
259+ <sodipodi:guide
260+ orientation="1,0"
261+ position="8,-8.0000001"
262+ id="guide4063" />
263+ <sodipodi:guide
264+ orientation="1,0"
265+ position="4,-8.0000001"
266+ id="guide4065" />
267+ <sodipodi:guide
268+ orientation="0,1"
269+ position="-8,88.000001"
270+ id="guide4067" />
271+ <sodipodi:guide
272+ orientation="0,1"
273+ position="-8,92.000001"
274+ id="guide4069" />
275+ <sodipodi:guide
276+ orientation="0,1"
277+ position="104,4"
278+ id="guide4071" />
279+ <sodipodi:guide
280+ orientation="0,1"
281+ position="-5,8.0000001"
282+ id="guide4073" />
283+ <sodipodi:guide
284+ orientation="1,0"
285+ position="88,-8.0000001"
286+ id="guide4077" />
287+ <sodipodi:guide
288+ orientation="0,1"
289+ position="-8,84.000001"
290+ id="guide4074" />
291+ <sodipodi:guide
292+ orientation="1,0"
293+ position="12,-8.0000001"
294+ id="guide4076" />
295+ <sodipodi:guide
296+ orientation="1,0"
297+ position="84,-8.0000001"
298+ id="guide4080" />
299+ <sodipodi:guide
300+ position="48,-8.0000001"
301+ orientation="1,0"
302+ id="guide4170" />
303+ <sodipodi:guide
304+ position="-8,48"
305+ orientation="0,1"
306+ id="guide4172" />
307+ <sodipodi:guide
308+ position="92,-8.0000001"
309+ orientation="1,0"
310+ id="guide4760" />
311+ <sodipodi:guide
312+ position="108,12"
313+ orientation="0,1"
314+ id="guide4182" />
315+ </sodipodi:namedview>
316+ <metadata
317+ id="metadata4879">
318+ <rdf:RDF>
319+ <cc:Work
320+ rdf:about="">
321+ <dc:format>image/svg+xml</dc:format>
322+ <dc:type
323+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
324+ <dc:title />
325+ </cc:Work>
326+ </rdf:RDF>
327+ </metadata>
328+ <g
329+ inkscape:label="Layer 1"
330+ inkscape:groupmode="layer"
331+ id="layer1"
332+ transform="translate(67.857146,-78.50504)">
333+ <g
334+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
335+ id="g4845"
336+ style="display:inline">
337+ <g
338+ inkscape:export-ydpi="90"
339+ inkscape:export-xdpi="90"
340+ inkscape:export-filename="next01.png"
341+ transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
342+ id="g4778"
343+ inkscape:label="Layer 1">
344+ <g
345+ transform="matrix(-1,0,0,1,575.99999,611)"
346+ id="g4780"
347+ style="display:inline">
348+ <rect
349+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
350+ id="rect4782"
351+ width="96.037987"
352+ height="96"
353+ x="-438.00244"
354+ y="345.36221"
355+ transform="scale(-1,1)" />
356+ <path
357+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
358+ d="m 351.96875,357.36133 v 72 h 4 v -72 z"
359+ id="path4205"
360+ inkscape:connector-curvature="0" />
361+ <path
362+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
363+ d="m 353.96875,391.36133 v 4.00195 h 14.00586 v -4.00195 z"
364+ id="path4207"
365+ inkscape:connector-curvature="0" />
366+ <ellipse
367+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10.79999924;stroke-opacity:1;marker:none;enable-background:accumulate"
368+ id="path4221"
369+ cx="-393.36218"
370+ cy="-353.96921"
371+ transform="matrix(0,-1,-1,0,0,0)"
372+ rx="5.9999971"
373+ ry="6.0023708" />
374+ <path
375+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
376+ d="m 427.9977,421.38592 c -0.0582,5.03278 0.12032,8.71362 -1.54162,11.72461 -0.83098,1.5055 -2.23647,2.69681 -3.99182,3.35547 -1.75535,0.65866 -3.83983,0.89649 -6.47131,0.89649 h -40.01582 c -2.63147,0 -4.71401,-0.23783 -6.46936,-0.89649 -1.75535,-0.65866 -3.16084,-1.84997 -3.99181,-3.35547 -1.66195,-3.01099 -1.48538,-6.69183 -1.54358,-11.72461 v -0.0117 -56.02344 -0.0117 c 0.0582,-5.03277 -0.11837,-8.71361 1.54358,-11.7246 0.83097,-1.5055 2.23646,-2.69681 3.99181,-3.35547 1.75535,-0.65867 3.83789,-0.89649 6.46936,-0.89649 h 40.01582 c 2.63148,0 4.71596,0.23782 6.47131,0.89649 1.75535,0.65866 3.16084,1.84997 3.99182,3.35547 1.66194,3.01099 1.48341,6.69183 1.54162,11.7246 v 0.0117 56.02344 z m -4.00158,-0.0234 v -56 c -0.0588,-5.03825 -0.23697,-8.35187 -1.04534,-9.8164 -0.40494,-0.73364 -0.85328,-1.15272 -1.89332,-1.54297 -1.04004,-0.39026 -2.694,-0.64063 -5.06451,-0.64063 h -40.01582 c -2.3705,0 -4.02447,0.25037 -5.06451,0.64063 -1.04003,0.39025 -1.48838,0.80933 -1.89332,1.54297 -0.80836,1.46453 -0.98656,4.77815 -1.04534,9.8164 v 55.97656 0.0234 c 0.0588,5.03826 0.23698,8.35188 1.04534,9.81641 0.40494,0.73364 0.85329,1.15076 1.89332,1.54102 1.04004,0.39025 2.69401,0.64257 5.06451,0.64257 h 40.01582 c 2.37051,0 4.02447,-0.25232 5.06451,-0.64257 1.04004,-0.39026 1.48838,-0.80738 1.89332,-1.54102 0.80837,-1.46453 0.98655,-4.77815 1.04534,-9.81641 z"
377+ id="path4179"
378+ inkscape:connector-curvature="0"
379+ sodipodi:nodetypes="ccsssscccccccssccccccccccsscccccccsscccc" />
380+ <path
381+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
382+ d="m 393.98438,374.6875 v 34.63281 h 4.00195 l -0.002,-34.63281 z"
383+ id="path4122"
384+ inkscape:connector-curvature="0" />
385+ <path
386+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.99999976;marker:none;enable-background:accumulate"
387+ d="m 406.2305,378.32915 c 0,0 -3.98402,-9.64528 -10.24547,-19.0012 -6.26145,9.35592 -10.24546,19.0012 -10.24546,19.0012 l 10.24546,0.006 z"
388+ id="path4215"
389+ inkscape:connector-curvature="0"
390+ sodipodi:nodetypes="ccccc"
391+ inkscape:transform-center-x="9.596908"
392+ inkscape:transform-center-y="-0.085309495" />
393+ <path
394+ inkscape:transform-center-y="-0.085309495"
395+ inkscape:transform-center-x="-9.596908"
396+ sodipodi:nodetypes="ccccc"
397+ inkscape:connector-curvature="0"
398+ id="path4216"
399+ d="m 406.2305,408.33395 c 0,0 -3.98402,9.64528 -10.24547,19.0012 -6.26145,-9.35592 -10.24546,-19.0012 -10.24546,-19.0012 l 10.24546,-0.006 z"
400+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.99999976;marker:none;enable-background:accumulate" />
401+ </g>
402+ </g>
403+ </g>
404+ </g>
405+</svg>
406
407=== added file 'plugins/vpn/vpn.settings'
408--- plugins/vpn/vpn.settings 1970-01-01 00:00:00 +0000
409+++ plugins/vpn/vpn.settings 2016-03-14 15:06:51 +0000
410@@ -0,0 +1,20 @@
411+{
412+ "icon": "network-vpn",
413+ "name": "VPN",
414+ "translations": "ubuntu-system-settings",
415+ "category": "network",
416+ "priority": 3,
417+ "keywords": [
418+ "network",
419+ "connect",
420+ "disconnect",
421+ "vpn",
422+ "openvpn",
423+ "ip",
424+ "address",
425+ "routing"
426+ ],
427+ "has-dynamic-keywords": false,
428+ "has-dynamic-visibility": false,
429+ "page-component": "PageComponent.qml"
430+}
431
432=== modified file 'tests/autopilot/ubuntu_system_settings/__init__.py'
433--- tests/autopilot/ubuntu_system_settings/__init__.py 2015-10-20 14:46:24 +0000
434+++ tests/autopilot/ubuntu_system_settings/__init__.py 2016-03-14 15:06:51 +0000
435@@ -120,6 +120,10 @@
436 def go_to_datetime_page(self):
437 return self._go_to_page('entryComponent-time-date', 'timeDatePage')
438
439+ @autopilot.logging.log_action(logger.debug)
440+ def go_to_vpn_page(self):
441+ return self._go_to_page('entryComponent-vpn', 'vpnPage')
442+
443 def _go_to_page(self, item_object_name, page_object_name):
444 self.click_item(item_object_name)
445 page = self.wait_select_single(objectName=page_object_name)
446@@ -1831,3 +1835,134 @@
447 def _click_forget(self):
448 button = self.select_single('Button', objectName='forgetNetwork')
449 self.pointing_device.click_object(button)
450+
451+
452+class VpnPage(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
453+
454+ """Autopilot helper for the VPN page."""
455+
456+ @classmethod
457+ def validate_dbus_object(cls, path, state):
458+ name = introspection.get_classname_from_path(path)
459+ if name == b'PageComponent':
460+ if state['objectName'][1] == 'vpnPage':
461+ return True
462+ return False
463+
464+ @autopilot.logging.log_action(logger.debug)
465+ def add_vpn(self):
466+ obj = self.select_single(objectName='addVpnButton')
467+ self.pointing_device.click_object(obj)
468+ return self.get_root_instance().wait_select_single(
469+ objectName='vpnEditor')
470+
471+ @autopilot.logging.log_action(logger.debug)
472+ def preview_vpn(self, at):
473+ obj = self.wait_select_single(objectName='vpnListConnection%d' % at)
474+ self.pointing_device.click_object(obj)
475+ return self.get_root_instance().wait_select_single(
476+ objectName='vpnPreviewDialog')
477+
478+ @autopilot.logging.log_action(logger.debug)
479+ def change_vpn(self, at):
480+ diag = self.preview_vpn(at)
481+ change_button = diag.wait_select_single(
482+ objectName='vpnPreviewChangeButton'
483+ )
484+ self.pointing_device.click_object(change_button)
485+ return self.get_root_instance().wait_select_single(
486+ objectName='vpnEditor')
487+
488+
489+class VpnEditor(
490+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase
491+):
492+ """Autopilot helper for vpn change dialog."""
493+
494+ @property
495+ def _openvpn_server_field(self):
496+ return self.wait_select_single(
497+ ubuntuuitoolkit.TextField,
498+ objectName='vpnOpenvpnServerField')
499+
500+ @property
501+ def _openvpn_port_field(self):
502+ return self.wait_select_single(
503+ ubuntuuitoolkit.TextField,
504+ objectName='vpnOpenvpnPortField')
505+
506+ @property
507+ def _openvpn_custom_port_toggle(self):
508+ return self.wait_select_single(
509+ ubuntuuitoolkit.CheckBox,
510+ objectName='vpnOpenvpnCustomPortToggle')
511+
512+ @property
513+ def _openvpn_tcp_toggle(self):
514+ return self.wait_select_single(
515+ ubuntuuitoolkit.CheckBox,
516+ objectName='vpnOpenvpnTcpToggle')
517+
518+ @property
519+ def _openvpn_udp_toggle(self):
520+ return self.wait_select_single(
521+ ubuntuuitoolkit.CheckBox,
522+ objectName='vpnOpenvpnUdpToggle')
523+
524+ @property
525+ def _openvpn_ca_field(self):
526+ return self.wait_select_single(objectName='vpnOpenvpnCaField')
527+
528+ @property
529+ def _openvpn_ok_button(self):
530+ return self.wait_select_single(
531+ 'Button', objectName='vpnEditorOkayButton')
532+
533+ @autopilot.logging.log_action(logger.debug)
534+ def set_openvpn_server(self, server):
535+ self._openvpn_server_field.write(server)
536+
537+ @autopilot.logging.log_action(logger.debug)
538+ def set_openvpn_custom_port(self, port):
539+ self._openvpn_custom_port_toggle.check()
540+ # XXX: workaround for lp:1546559, i.e. we need to wait
541+ # some time between writing to the API.
542+ sleep(1)
543+ self._openvpn_port_field.write(port)
544+
545+ @autopilot.logging.log_action(logger.debug)
546+ def set_openvpn_ca(self, paths):
547+ self.set_openvpn_file(self._openvpn_ca_field, paths)
548+
549+ @autopilot.logging.log_action(logger.debug)
550+ def set_openvpn_file(self, field, paths):
551+ self.pointing_device.click_object(field)
552+
553+ # Wait for expanded animation.
554+ sleep(0.5)
555+
556+ # file = field.wait_select_single(objectName='vpnFileSelectorItem0')
557+ choose = field.wait_select_single(objectName='vpnFileSelectorItem1')
558+ self.pointing_device.click_object(choose)
559+ file_dialog = self.get_root_instance().wait_select_single(
560+ objectName='vpnDialogFile'
561+ )
562+
563+ # Go to root /
564+ root = file_dialog.wait_select_single(objectName='vpnFilePathItem_/')
565+ self.pointing_device.click_object(root)
566+
567+ for path in paths:
568+ list_view = file_dialog.wait_select_single(
569+ 'QQuickListView', objectName='vpnFileList'
570+ )
571+ list_view.click_element('vpnFileItem_%s' % path)
572+ accept = file_dialog.wait_select_single(objectName='vpnFileAccept')
573+ self.pointing_device.click_object(accept)
574+
575+ @autopilot.logging.log_action(logger.debug)
576+ def openvpn_okay(self):
577+ utils.dismiss_osk()
578+ self.get_root_instance().main_view.scroll_to_and_click(
579+ self._openvpn_ok_button
580+ )
581
582=== modified file 'tests/autopilot/ubuntu_system_settings/tests/__init__.py'
583--- tests/autopilot/ubuntu_system_settings/tests/__init__.py 2015-12-04 16:18:00 +0000
584+++ tests/autopilot/ubuntu_system_settings/tests/__init__.py 2016-03-14 15:06:51 +0000
585@@ -937,6 +937,67 @@
586 super(LanguageBaseTestCase, self).tearDown()
587
588
589+class UbuntuSystemSettingsVpnTestCase(UbuntuSystemSettingsTestCase,
590+ dbusmock.DBusTestCase):
591+ """Base class for tests that tests the vpn functionality."""
592+ connectivity_parameters = {}
593+ indicatornetwork_parameters = {}
594+
595+ @classmethod
596+ def setUpClass(cls):
597+ cls.session_con = cls.get_dbus(False)
598+
599+ cls.start_system_bus()
600+
601+ super(UbuntuSystemSettingsVpnTestCase, cls).setUpClass()
602+
603+ def setUp(self):
604+ if is_process_running(INDICATOR_NETWORK):
605+ _stop_process(INDICATOR_NETWORK)
606+ self.addCleanup(_start_process, INDICATOR_NETWORK)
607+
608+ ctv_tmpl = os.path.join(os.path.dirname(__file__), 'connectivity.py')
609+ (self.ctv_mock, self.obj_ctv) = self.spawn_server_template(
610+ ctv_tmpl, parameters=self.connectivity_parameters,
611+ stdout=subprocess.PIPE)
612+
613+ self.ctv_private = dbus.Interface(
614+ self.session_con.get_object(CTV_IFACE, CTV_PRIV_OBJ),
615+ 'org.freedesktop.DBus.Properties')
616+
617+ super(UbuntuSystemSettingsVpnTestCase, self).setUp()
618+
619+ def tearDown(self):
620+ self.ctv_mock.terminate()
621+ self.ctv_mock.wait()
622+ super(UbuntuSystemSettingsVpnTestCase, self).tearDown()
623+
624+ @classmethod
625+ def tearDownClass(cls):
626+ if dbusmock.DBusTestCase.system_bus_pid is not None:
627+ cls.stop_dbus(dbusmock.DBusTestCase.system_bus_pid)
628+ del os.environ['DBUS_SYSTEM_BUS_ADDRESS']
629+ dbusmock.DBusTestCase.system_bus_pid = None
630+ if dbusmock.DBusTestCase.session_bus_pid is not None:
631+ cls.stop_dbus(dbusmock.DBusTestCase.session_bus_pid)
632+ del os.environ['DBUS_SESSION_BUS_ADDRESS']
633+ dbusmock.DBusTestCase.session_bus_pid = None
634+ super(UbuntuSystemSettingsVpnTestCase, cls).tearDownClass()
635+
636+
637+class VpnBaseTestCase(UbuntuSystemSettingsVpnTestCase):
638+
639+ def setUp(self):
640+ super(VpnBaseTestCase, self).setUp()
641+ self.vpn_page = self.main_view.go_to_vpn_page()
642+
643+ def get_vpn_connection_object(self, path):
644+ return dbus.Interface(
645+ self.session_con.get_object(CTV_IFACE, path),
646+ 'org.freedesktop.DBus.Properties'
647+ )
648+
649+
650 class WifiBaseTestCase(UbuntuSystemSettingsTestCase,
651 dbusmock.DBusTestCase):
652 """ Base class for wifi settings tests"""
653
654=== modified file 'tests/autopilot/ubuntu_system_settings/tests/connectivity.py'
655--- tests/autopilot/ubuntu_system_settings/tests/connectivity.py 2015-09-15 17:39:23 +0000
656+++ tests/autopilot/ubuntu_system_settings/tests/connectivity.py 2016-03-14 15:06:51 +0000
657@@ -24,6 +24,11 @@
658 NETS_IFACE = 'com.ubuntu.connectivity1.NetworkingStatus'
659 NETS_OBJ = '/com/ubuntu/connectivity1/NetworkingStatus'
660
661+VPN_OBJ = '/com/ubuntu/connectivity1/vpn'
662+VPN_CONN_IFACE = 'com.ubuntu.connectivity1.vpn.VpnConnection'
663+VPN_CONN_OPENVPN_IFACE = 'com.ubuntu.connectivity1.vpn.VpnConnection.OpenVpn'
664+VPN_CONN_PPTP_IFACE = 'com.ubuntu.connectivity1.vpn.VpnConnection.Pptp'
665+
666 NOT_IMPLEMENTED = '''raise dbus.exceptions.DBusException(
667 "org.ofono.Error.NotImplemented")'''
668
669@@ -55,6 +60,117 @@
670 self.SetProperty(NETS_OBJ, NETS_IFACE, 'WifiEnabled', value)
671
672
673+def add_openvpn_object(mock, path):
674+ obj = dbusmock.get_object(path)
675+ obj.AddProperties(VPN_CONN_OPENVPN_IFACE, {
676+ 'connectionType': dbus.UInt32(0),
677+ 'remote': dbus.String(),
678+ 'ca': dbus.String(),
679+ 'cert': dbus.String(),
680+ 'certPass': dbus.String(),
681+ 'key': dbus.String(),
682+ 'username': dbus.String(),
683+ 'password': dbus.String(),
684+ 'localIp': dbus.String(),
685+ 'remoteIp': dbus.String(),
686+ 'staticKey': dbus.String(),
687+ 'staticKeyDirection': dbus.UInt32(0),
688+ 'portSet': dbus.Boolean(False),
689+ 'port': dbus.UInt32(1194),
690+ 'renegSecondsSet': dbus.Boolean(False),
691+ 'renegSeconds': dbus.UInt32(0),
692+ 'compLzo': dbus.Boolean(False),
693+ 'protoTcp': dbus.Boolean(False),
694+ 'devTypeSet': dbus.Boolean(False),
695+ 'devType': dbus.UInt32(0),
696+ 'dev': dbus.String(),
697+ 'tunnelMtuSet': dbus.Boolean(False),
698+ 'tunnelMtu': dbus.UInt32(1500),
699+ 'fragmentSizeSet': dbus.Boolean(False),
700+ 'fragmentSize': dbus.UInt32(1300),
701+ 'mssFix': dbus.Boolean(False),
702+ 'remoteRandom': dbus.Boolean(False),
703+ 'cipher': dbus.UInt32(0),
704+ 'keysizeSet': dbus.Boolean(False),
705+ 'keysize': dbus.UInt32(128),
706+ 'auth': dbus.UInt32(0),
707+ 'tlsRemote': dbus.String(),
708+ 'remoteCertTlsSet': dbus.Boolean(False),
709+ 'remoteCertTls': dbus.UInt32(0),
710+ 'taSet': dbus.Boolean(False),
711+ 'ta': dbus.String(),
712+ 'taDir': dbus.UInt32(0),
713+ 'proxyType': dbus.UInt32(),
714+ 'proxyServer': dbus.String(),
715+ 'proxyPort': dbus.UInt32(80),
716+ 'proxyRetry': dbus.Boolean(False),
717+ 'proxyUsername': dbus.String(),
718+ 'proxyPassword': dbus.String(),
719+ })
720+
721+
722+def add_pptp_object(mock, path):
723+ obj = dbusmock.get_object(path)
724+ obj.AddProperties(VPN_CONN_PPTP_IFACE, {
725+ 'gateway': dbus.String(),
726+ 'user': dbus.String(),
727+ 'password': dbus.String(),
728+ 'domain': dbus.String(),
729+ 'allowPap': dbus.Boolean(True),
730+ 'allowChap': dbus.Boolean(True),
731+ 'allowMschap': dbus.Boolean(True),
732+ 'allowMschapv2': dbus.Boolean(True),
733+ 'allowEap': dbus.Boolean(True),
734+ 'requireMppe': dbus.Boolean(False),
735+ 'mppeType': dbus.UInt32(0),
736+ 'mppeStateful': dbus.Boolean(False),
737+ 'bsdCompression': dbus.Boolean(True),
738+ 'deflateCompression': dbus.Boolean(True),
739+ 'tcpHeaderCompression': dbus.Boolean(True),
740+ 'sendPppEchoPackets': dbus.Boolean(False),
741+ })
742+
743+
744+def add_vpn_object(mock, vpn_type, path):
745+ mock.AddObject(
746+ path,
747+ VPN_CONN_IFACE,
748+ {
749+ 'activatable': dbus.Boolean(True),
750+ 'active': dbus.Boolean(False),
751+ 'type': dbus.UInt32(vpn_type),
752+ 'id': path.split('/')[len(path.split('/'))-1]
753+ },
754+ [
755+ ('UpdateSecrets', '', '', ''),
756+ ]
757+ )
758+
759+ if vpn_type == 0:
760+ add_openvpn_object(mock, path)
761+ elif vpn_type == 1:
762+ add_pptp_object(mock, path)
763+ else:
764+ raise Exception("Unable to add vpn connection, no such type: %d" % (
765+ vpn_type)
766+ )
767+
768+
769+def add_vpn_connection(mock, vpn_type):
770+ conns = mock.Get(PRIV_IFACE, 'VpnConnections')
771+ new_path = '%s/%s%s' % (VPN_OBJ, 'MockVpnConnection', str(len(conns)))
772+ add_vpn_object(mock, vpn_type, new_path)
773+ conns.append(new_path)
774+ mock.SetProperty(PRIV_OBJ, PRIV_IFACE, 'VpnConnections', conns)
775+ return new_path
776+
777+
778+def remove_vpn_connection(mock, path):
779+ conns = mock.Get(PRIV_IFACE, 'VpnConnections')
780+ conns.remove(path)
781+ mock.SetProperty(PRIV_OBJ, PRIV_IFACE, 'VpnConnections', conns)
782+
783+
784 def load(mock, parameters):
785 global _parameters
786 _parameters = parameters
787@@ -64,6 +180,8 @@
788 mock.set_hotspot_password = set_hotspot_password
789 mock.set_wifi_enabled = set_wifi_enabled
790 mock.set_hotspot_auth = set_hotspot_auth
791+ mock.add_vpn_connection = add_vpn_connection
792+ mock.remove_vpn_connection = remove_vpn_connection
793
794 mock.AddObject(
795 NETS_OBJ,
796@@ -106,7 +224,9 @@
797 ),
798 'HotspotAuth': _parameters.get(
799 'HotspotAuth', dbus.String('wpa-psk')
800- )
801+ ),
802+ 'VpnConnections': _parameters.get('VpnConnections',
803+ dbus.Array([], signature='o'))
804 },
805 [
806 (
807@@ -144,6 +264,14 @@
808 (
809 'SetHotspotMode', 's', '',
810 ''
811+ ),
812+ (
813+ 'AddVpnConnection', 'u', 'o',
814+ 'ret = objects["/"].add_vpn_connection(self, args[0])'
815+ ),
816+ (
817+ 'RemoveVpnConnection', 'o', '',
818+ 'objects["/"].remove_vpn_connection(self, args[0])'
819 )
820 ]
821 )
822
823=== modified file 'tests/autopilot/ubuntu_system_settings/tests/test_plugins.py'
824--- tests/autopilot/ubuntu_system_settings/tests/test_plugins.py 2015-09-16 14:28:40 +0000
825+++ tests/autopilot/ubuntu_system_settings/tests/test_plugins.py 2016-03-14 15:06:51 +0000
826@@ -137,6 +137,13 @@
827 )
828 self.assertThat(plugin, NotEquals(None))
829
830+ def test_vpn(self):
831+ """ Checks whether the Vpn plugin is available """
832+ plugin = self.main_view.select_single(
833+ objectName='entryComponent-vpn'
834+ )
835+ self.assertThat(plugin, NotEquals(None))
836+
837
838 class SystemSettingsUpowerTestCases(UbuntuSystemSettingsUpowerTestCase):
839 def setUp(self):
840
841=== added file 'tests/autopilot/ubuntu_system_settings/tests/test_vpn.py'
842--- tests/autopilot/ubuntu_system_settings/tests/test_vpn.py 1970-01-01 00:00:00 +0000
843+++ tests/autopilot/ubuntu_system_settings/tests/test_vpn.py 2016-03-14 15:06:51 +0000
844@@ -0,0 +1,61 @@
845+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
846+# Copyright 2014 Canonical
847+#
848+# This program is free software: you can redistribute it and/or modify it
849+# under the terms of the GNU General Public License version 3, as published
850+# by the Free Software Foundation.
851+
852+from autopilot.matchers import Eventually
853+from testtools.matchers import Equals
854+
855+from ubuntu_system_settings.tests import VpnBaseTestCase
856+
857+from ubuntu_system_settings.tests.connectivity import (
858+ PRIV_IFACE as CTV_PRIV_IFACE, VPN_CONN_OPENVPN_IFACE
859+)
860+
861+
862+class VpnAddTestCase(VpnBaseTestCase):
863+
864+ connectivity_parameters = {}
865+
866+ def test_add_and_configure_openvpn(self):
867+ page = self.vpn_page.add_vpn()
868+
869+ # Wait for length of VpnConnections to become 1
870+ self.assertThat(
871+ lambda: len(
872+ self.ctv_private.Get(CTV_PRIV_IFACE, 'VpnConnections')
873+ ),
874+ Eventually(Equals(1))
875+ )
876+ conn_path = self.ctv_private.Get(CTV_PRIV_IFACE, 'VpnConnections')[0]
877+ conn_obj = self.get_vpn_connection_object(conn_path)
878+
879+ page.set_openvpn_server('vpn.ubuntu.com')
880+ page.set_openvpn_custom_port('1000')
881+
882+ page.set_openvpn_ca(
883+ # Any file will do.
884+ ['etc', 'apt', 'sources.list']
885+ )
886+ page.openvpn_okay()
887+
888+ self.assertThat(
889+ lambda: conn_obj.Get(VPN_CONN_OPENVPN_IFACE, 'remote'),
890+ Eventually(Equals('vpn.ubuntu.com'))
891+ )
892+
893+ self.assertThat(
894+ lambda: conn_obj.Get(VPN_CONN_OPENVPN_IFACE, 'ca'),
895+ Eventually(Equals('/etc/apt/sources.list'))
896+ )
897+
898+ self.assertThat(
899+ lambda: conn_obj.Get(VPN_CONN_OPENVPN_IFACE, 'portSet'),
900+ Eventually(Equals(True))
901+ )
902+ self.assertThat(
903+ lambda: conn_obj.Get(VPN_CONN_OPENVPN_IFACE, 'port'),
904+ Eventually(Equals(1000))
905+ )

Subscribers

People subscribed via source and target branches