Merge lp:~martin-borho/ubuntu-weather-app/sdk_emulator into lp:ubuntu-weather-app/obsolete.trunk

Proposed by Martin Borho
Status: Merged
Approved by: Nicholas Skaggs
Approved revision: 90
Merged at revision: 85
Proposed branch: lp:~martin-borho/ubuntu-weather-app/sdk_emulator
Merge into: lp:ubuntu-weather-app/obsolete.trunk
Diff against target: 602 lines (+98/-225)
9 files modified
debian/control (+1/-0)
tests/autopilot/ubuntu_weather_app/emulators.py (+40/-0)
tests/autopilot/ubuntu_weather_app/emulators/__init__.py (+0/-17)
tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py (+0/-157)
tests/autopilot/ubuntu_weather_app/tests/__init__.py (+15/-7)
tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py (+21/-28)
tests/autopilot/ubuntu_weather_app/tests/test_mainview.py (+5/-3)
tests/autopilot/ubuntu_weather_app/tests/test_settings.py (+13/-9)
tests/autopilot/ubuntu_weather_app/tests/weatherdata.py (+3/-4)
To merge this branch: bzr merge lp:~martin-borho/ubuntu-weather-app/sdk_emulator
Reviewer Review Type Date Requested Status
Nicholas Skaggs (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+178832@code.launchpad.net

Commit message

integrated toolkit emulator from SDK, updated test data

Description of the change

- Integrated toolkit emulator from SDK
- Updated test data with new internal format version

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Well, I'm getting some failures off the cuff on my box, going to try on the device if I can.

89. By Martin Borho

added more assertions to improve test stability

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
90. By Martin Borho

cleaned some test code, removed obsolete test

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Excellent Martin. Thanks for adding the extra asserts and cleanup!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2013-05-14 20:38:57 +0000
+++ debian/control 2013-08-07 17:39:25 +0000
@@ -26,5 +26,6 @@
26 libautopilot-qt,26 libautopilot-qt,
27 libqt5test5,27 libqt5test5,
28 libqt5widgets5,28 libqt5widgets5,
29 ubuntu-ui-toolkit-autopilot,
29Description: Test package for the weather app30Description: Test package for the weather app
30 Autopilot tests for the weather app package31 Autopilot tests for the weather app package
3132
=== removed directory 'tests/autopilot/ubuntu_weather_app/emulators'
=== added file 'tests/autopilot/ubuntu_weather_app/emulators.py'
--- tests/autopilot/ubuntu_weather_app/emulators.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_weather_app/emulators.py 2013-08-07 17:39:25 +0000
@@ -0,0 +1,40 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7#
8# Authored by: Martin Borho <martin@borho.net>
9
10"""weather app autopilot tests and emulators - top level package."""
11
12from ubuntuuitoolkit import emulators as toolkit_emulators
13
14
15class MainView(toolkit_emulators.MainView):
16
17 def get_object(self, typeName, name):
18 """Get a specific object"""
19 return self.select_single(typeName, objectName=name)
20
21 def get_objects(self, typeName, name):
22 """Get more than one object"""
23 return self.select_many(typeName, objectName=name)
24
25 def get_tabs(self):
26 """Return the LocationTabs emulator of the MainView."""
27 tabs = self.select_single(Tabs)
28 assert tabs is not None, toolkit_emulators._NO_TABS_ERROR
29 return tabs
30
31class Tabs(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
32 """LocationTabs Autopilot emulator."""
33
34 def get_current_tab(self):
35 """Return the currently selected tab."""
36 return self.select_many('LocationTab')[self.selectedTabIndex]
37
38 def get_number_of_tabs(self):
39 """Return the number of tabs."""
40 return len(self.select_many('LocationTab'))
041
=== removed file 'tests/autopilot/ubuntu_weather_app/emulators/__init__.py'
--- tests/autopilot/ubuntu_weather_app/emulators/__init__.py 2013-06-20 16:10:06 +0000
+++ tests/autopilot/ubuntu_weather_app/emulators/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# Authored by: Nicholas Skaggs <nicholas.skaggs@canonical.com>
180
=== removed file 'tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py'
--- tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py 2013-07-11 22:04:11 +0000
+++ tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py 1970-01-01 00:00:00 +0000
@@ -1,157 +0,0 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# Authored by: Nicholas Skaggs <nicholas.skaggs@canonical.com>
18
19from testtools.matchers import Equals, NotEquals, Not, Is
20from autopilot.matchers import Eventually
21
22class ubuntusdk(object):
23 """An emulator class that makes it easy to interact with the ubuntu sdk applications."""
24
25 def __init__(self, autopilot, app):
26 self.app = app
27 self.autopilot = autopilot
28
29 def get_qml_view(self):
30 """Get the main QML view"""
31 return self.app.select_single("QQuickView")
32
33 def get_object(self, typeName, name):
34 """Get a specific object"""
35 return self.app.select_single(typeName, objectName=name)
36
37 def get_objects(self, typeName, name):
38 """Get more than one object"""
39 return self.app.select_many(typeName, objectName=name)
40
41 def get_tabs(self):
42 """Return all tabs"""
43 return self.app.select_single("Tabs")
44
45 def switch_to_tab(self, tab):
46 """Switch to the specified tab number"""
47 tabs = self.get_tabs()
48 currentTab = tabs.selectedTabIndex
49
50 #perform operations until tab == currentTab
51 while tab != currentTab:
52 if tab > currentTab:
53 self._next_tab()
54 if tab < currentTab:
55 self._previous_tab()
56 currentTab = tabs.selectedTabIndex
57
58 def _previous_tab(self):
59 """Switch to the previous tab"""
60 qmlView = self.get_qml_view()
61
62 startX = int(qmlView.x + qmlView.width * 0.10)
63 stopX = int(qmlView.x + qmlView.width * 0.45)
64 lineY = int(qmlView.y + qmlView.height * 0.05)
65
66 self.autopilot.pointing_device.drag(startX, lineY, stopX, lineY)
67 self.autopilot.pointing_device.move(startX, lineY)
68 self.autopilot.pointing_device.click()
69 self.autopilot.pointing_device.click()
70
71 def _next_tab(self):
72 """Switch to the next tab"""
73 qmlView = self.get_qml_view()
74
75 startX = int(qmlView.x + qmlView.width * 0.45)
76 stopX = int(qmlView.x + qmlView.width * 0.10)
77 lineY = int(qmlView.y + qmlView.height * 0.05)
78
79 self.autopilot.pointing_device.drag(startX, lineY, stopX, lineY)
80 self.autopilot.pointing_device.move(startX, lineY)
81 self.autopilot.pointing_device.click()
82 self.autopilot.pointing_device.click()
83
84 def toggle_toolbar(self):
85 """Toggle the toolbar between revealed and hidden"""
86 #check and see if the toolbar is open or not
87 if self.get_toolbar().opened:
88 self.hide_toolbar()
89 else:
90 self.open_toolbar()
91
92 def get_toolbar(self):
93 """Returns the toolbar in the main events view."""
94 return self.app.select_single("Toolbar")
95
96 def get_toolbar_button(self, buttonObject):
97 """Returns the toolbar button with objectName buttonObject"""
98 toolbar = self.get_toolbar()
99 if not toolbar.opened:
100 self.open_toolbar()
101 buttonList = toolbar.select_many("ActionItem")
102 #old version is ToolbarButton
103 if not buttonList:
104 buttonList = toolbar.select_many("ToolbarButton")
105 for button in buttonList:
106 if button.objectName == buttonObject:
107 return button
108
109 def click_toolbar_button(self, buttonObject):
110 """Clicks the toolbar button with objectName buttonObject"""
111 #The toolbar button is assumed to be the following format
112 #Toolbar {
113 # ...
114 # ActionItem {
115 # objectName: "name"
116 button = self.get_toolbar_button(buttonObject)
117 self.autopilot.pointing_device.click_object(button)
118 return button
119
120 def open_toolbar(self):
121 """Open the toolbar"""
122 qmlView = self.get_qml_view()
123
124 lineX = int(qmlView.x + qmlView.width * 0.50)
125 startY = int(qmlView.y + qmlView.height - 1)
126 stopY = int(qmlView.y + qmlView.height * 0.95)
127
128 self.autopilot.pointing_device.drag(lineX, startY, lineX, stopY)
129
130 def hide_toolbar(self):
131 """Hide the toolbar"""
132 qmlView = self.get_qml_view()
133
134 lineX = int(qmlView.x + qmlView.width * 0.50)
135 startY = int(qmlView.y + qmlView.height * 0.95)
136 stopY = int(qmlView.y + qmlView.height - 1)
137
138 self.autopilot.pointing_device.drag(lineX, startY, lineX, stopY)
139
140 def set_popup_value(self, popover, button, value):
141 """Changes the given popover selector to the request value
142 At the moment this only works for values that are currently visible. To
143 access the remaining items, a help method to drag and recheck is needed."""
144 #The popover is assumed to be the following format
145 #Component {
146 # id: actionSelectionPopover
147 #
148 #ActionSelectionPopover {
149 # actions: ActionList {
150 # Action {
151
152 popList = self.get_object("ActionSelectionPopover", popover)
153 itemList = popList.select_many("Label")
154 for item in itemList:
155 if item.text == value:
156 self.autopilot.pointing_device.click_object(item)
157 return item
1580
=== modified file 'tests/autopilot/ubuntu_weather_app/tests/__init__.py'
--- tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-07-19 11:39:31 +0000
+++ tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-08-07 17:39:25 +0000
@@ -4,6 +4,8 @@
4# This program is free software: you can redistribute it and/or modify it4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.6# by the Free Software Foundation.
7#
8# Authored by: Martin Borho <martin@borho.net>
79
8"""weather-app autopilot tests."""10"""weather-app autopilot tests."""
911
@@ -16,7 +18,8 @@
16from autopilot.platform import model18from autopilot.platform import model
17from autopilot.testcase import AutopilotTestCase19from autopilot.testcase import AutopilotTestCase
1820
19from ubuntu_weather_app.emulators.ubuntusdk import ubuntusdk21from ubuntuuitoolkit import emulators as toolkit_emulators
22from ubuntu_weather_app.emulators import MainView
2023
21class WeatherTestCase(AutopilotTestCase):24class WeatherTestCase(AutopilotTestCase):
2225
@@ -51,18 +54,20 @@
51 self.app = self.launch_test_application(54 self.app = self.launch_test_application(
52 self.qmlscene(),55 self.qmlscene(),
53 self.local_location,56 self.local_location,
54 app_type='qt')57 app_type='qt',
58 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
5559
56 def launch_test_installed(self):60 def launch_test_installed(self):
57 self.app = self.launch_test_application(61 self.app = self.launch_test_application(
58 self.qmlscene(),62 self.qmlscene(),
59 "/usr/share/ubuntu-weather-app/ubuntu-weather-app.qml",63 "/usr/share/ubuntu-weather-app/ubuntu-weather-app.qml",
60 "--desktop_file_hint=/usr/share/applications/ubuntu-weather-app.desktop",64 "--desktop_file_hint=/usr/share/applications/ubuntu-weather-app.desktop",
61 app_type='qt')65 app_type='qt',
66 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
6267
63 def launch_and_quit_app(self):68 def launch_and_quit_app(self):
64 self.launch_app()69 self.launch_app()
65 self.main_window.get_qml_view().visible.wait_for(True)70 self.get_qml_view().visible.wait_for(True)
6671
67 # When calling launch_app an instance of the spawned process72 # When calling launch_app an instance of the spawned process
68 # control object will be stored in self.app.process, and a cleanup73 # control object will be stored in self.app.process, and a cleanup
@@ -72,19 +77,22 @@
72 # the process during regular test setup.77 # the process during regular test setup.
73 self.doCleanups()78 self.doCleanups()
7479
80 def get_qml_view(self):
81 return self.app.select_single("QQuickView")
82
75 @property83 @property
76 def main_window(self):84 def main_window(self):
77 return ubuntusdk(self, self.app)#MainWindow(self, self.app)85 return self.app.select_single(MainView)
7886
79class SheetMixin(object):87class SheetMixin(object):
80 """A mixin to to give access to common sheet elements"""88 """A mixin to to give access to common sheet elements"""
81 def _click_sheet_confirm(self):89 def _click_sheet_confirm(self):
82 """Clicks the confirm button"""90 """Clicks the confirm button"""
83 self.pointing_device.click_object(self.main_window.app.select_many('Button')[1])91 self.pointing_device.click_object(self.main_window.select_many('Button')[1])
8492
85 def _click_sheet_cancel(self):93 def _click_sheet_cancel(self):
86 """Clicks the cancel button"""94 """Clicks the cancel button"""
87 self.pointing_device.click_object(self.main_window.app.select_many('Button')[0])95 self.pointing_device.click_object(self.main_window.select_many('Button')[0])
8896
89class DatabaseMixin(object):97class DatabaseMixin(object):
9098
9199
=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py'
--- tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2013-08-04 02:26:07 +0000
+++ tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2013-08-07 17:39:25 +0000
@@ -23,13 +23,14 @@
23 self.clean_db()23 self.clean_db()
24 super(TestLocationManager, self).setUp()24 super(TestLocationManager, self).setUp()
25 self.assertThat(25 self.assertThat(
26 self.main_window.get_qml_view().visible, Eventually(Equals(True)))26 self.get_qml_view().visible, Eventually(Equals(True)))
2727
28 def _open_add_location_page(self):28 def _open_add_location_page(self):
29 """Opens the AddLocationPage"""29 """Opens the AddLocationPage"""
30 # click on listitem to open AddLocationPage30 # click on listitem to open AddLocationPage
31 locationList = self.main_window.get_object('QQuickListView', 'LocationList')31 locationList = self.main_window.get_object('QQuickListView', 'LocationList')
32 addCityItem = locationList.get_children()[0]32 addCityItem = locationList.get_children()[0]
33 self.assertThat(lambda: addCityItem, Eventually(NotEquals(None)))
33 self.pointing_device.move_to_object(addCityItem)34 self.pointing_device.move_to_object(addCityItem)
34 self.pointing_device.click()35 self.pointing_device.click()
3536
@@ -54,8 +55,9 @@
5455
55 # insert city name to search for56 # insert city name to search for
56 searchField = self.main_window.get_object("TextField", "SearchField")57 searchField = self.main_window.get_object("TextField", "SearchField")
57 self.pointing_device.move_to_object(searchField)58 self.assertThat(lambda: searchField, Eventually(NotEquals(None)))
58 self.pointing_device.click()59 self.pointing_device.click_object(searchField)
60 self.assertThat(searchField.focus, Eventually(Equals(True)))
59 self.keyboard.type("London")61 self.keyboard.type("London")
60 self.assertThat(searchField.text, Eventually(Equals("London")))62 self.assertThat(searchField.text, Eventually(Equals("London")))
61 self.keyboard.press_and_release('Enter')63 self.keyboard.press_and_release('Enter')
@@ -63,14 +65,16 @@
63 # wait for results and click on the first item65 # wait for results and click on the first item
64 resultsList = self.main_window.get_object('QQuickListView', 'SearchResultList')66 resultsList = self.main_window.get_object('QQuickListView', 'SearchResultList')
65 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))67 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))
66 firstResult = resultsList.get_children()[0].get_children()[0]68 firstResult = self.main_window.get_object('Standard', 'searchResult0')
69 self.assertThat(lambda: firstResult, Eventually(NotEquals(None)))
67 self.pointing_device.move_to_object(firstResult)70 self.pointing_device.move_to_object(firstResult)
68 self.pointing_device.click()71 self.pointing_device.click()
6972
70 # LocationManagerPage should be visible and "London" added73 # LocationManagerPage should be visible and "London" added
71 locationList = self.main_window.get_object('QQuickListView', 'LocationList')74 locationList = self.main_window.get_object('QQuickListView', 'LocationList')
72 addedItem = locationList.get_children()[0]75 addedItem = self.main_window.get_object('Standard', "existingLocation0")
73 self.assertThat(addedItem.get_children()[1].text, Eventually(Equals("London")))76 self.assertThat(lambda: addedItem, Eventually(NotEquals(None)))
77 self.assertThat(addedItem.text, Eventually(Equals("London")))
74 self._click_sheet_confirm()78 self._click_sheet_confirm()
7579
76 # back to locations, wait till data is loaded80 # back to locations, wait till data is loaded
@@ -83,18 +87,15 @@
83 tabObjects = self.main_window.get_objects('LocationTab','LocationTab')87 tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
84 self.assertEqual(1, len(tabObjects))88 self.assertEqual(1, len(tabObjects))
8589
86 def test_toolbar_hidden_when_no_location_is_defined(self):
87 """Toolbar is not visible when there's no location is defined"""
88 toolbar = self.main_window.get_toolbar()
89 self.assertThat(toolbar.opened, Eventually(Equals(False)))
90
91 def test_search_city(self):90 def test_search_city(self):
92 """Search for cities"""91 """Search for cities"""
93 self._open_add_location_page()92 self._open_add_location_page()
9493
95 # insert city name to search for94 # insert city name to search for
96 searchField = self.main_window.get_object("TextField", "SearchField")95 searchField = self.main_window.get_object("TextField", "SearchField")
96 self.assertThat(lambda: searchField, Eventually(NotEquals(None)))
97 self.pointing_device.click_object(searchField)97 self.pointing_device.click_object(searchField)
98 self.assertThat(searchField.focus, Eventually(Equals(True)))
98 self.keyboard.type("London")99 self.keyboard.type("London")
99 self.assertThat(searchField.text, Eventually(Equals("London")))100 self.assertThat(searchField.text, Eventually(Equals("London")))
100 self.keyboard.press_and_release('Enter')101 self.keyboard.press_and_release('Enter')
@@ -103,10 +104,12 @@
103 resultsList = self.main_window.get_object('QQuickListView', 'SearchResultList')104 resultsList = self.main_window.get_object('QQuickListView', 'SearchResultList')
104 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))105 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))
105 firstResult = self.select_single_retry("Standard", objectName="searchResult0")106 firstResult = self.select_single_retry("Standard", objectName="searchResult0")
107 self.assertThat(lambda: firstResult, Eventually(NotEquals(None)))
106 self.assertThat(firstResult.text, Eventually(Equals("London, GB")))108 self.assertThat(firstResult.text, Eventually(Equals("London, GB")))
107109
108 # clear search field and do another search110 # clear search field and do another search
109 clear_button = searchField.select_single("AbstractButton")111 clear_button = searchField.select_single("AbstractButton")
112 self.assertThat(lambda: clear_button, Eventually(NotEquals(None)))
110 self.pointing_device.click_object(clear_button)113 self.pointing_device.click_object(clear_button)
111 self.assertThat(searchField.text, Eventually(Equals("")))114 self.assertThat(searchField.text, Eventually(Equals("")))
112115
@@ -115,6 +118,7 @@
115 self.keyboard.press_and_release('Enter')118 self.keyboard.press_and_release('Enter')
116 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))119 self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30))
117 firstResult = self.select_single_retry("Standard", objectName="searchResult0")120 firstResult = self.select_single_retry("Standard", objectName="searchResult0")
121 self.assertThat(lambda: firstResult, Eventually(NotEquals(None)))
118 self.assertThat(firstResult.text, Eventually(Equals("Hamburg, DE")))122 self.assertThat(firstResult.text, Eventually(Equals("Hamburg, DE")))
119123
120 def test_cancel_adding_location(self):124 def test_cancel_adding_location(self):
@@ -130,8 +134,9 @@
130134
131 # insert city name to search for135 # insert city name to search for
132 searchField = self.main_window.get_object("TextField", "SearchField")136 searchField = self.main_window.get_object("TextField", "SearchField")
133 self.pointing_device.move_to_object(searchField)137 self.assertThat(lambda: searchField, Eventually(NotEquals(None)))
134 self.pointing_device.click()138 self.pointing_device.click_object(searchField)
139 self.assertThat(searchField.focus, Eventually(Equals(True)))
135 self.keyboard.type("UbuntuCity") # Unfortunately, no UbuntuCity in the world140 self.keyboard.type("UbuntuCity") # Unfortunately, no UbuntuCity in the world
136 self.assertThat(searchField.text, Eventually(Equals("UbuntuCity")))141 self.assertThat(searchField.text, Eventually(Equals("UbuntuCity")))
137 self.keyboard.press_and_release('Enter')142 self.keyboard.press_and_release('Enter')
@@ -146,27 +151,20 @@
146 self.clean_db()151 self.clean_db()
147 self.launch_and_quit_app()152 self.launch_and_quit_app()
148 # add one location to storage153 # add one location to storage
149 #self.save_locations_to_storage([locations_data[0]])
150 self.save_locations_to_storage(locations_data)154 self.save_locations_to_storage(locations_data)
151 super(TestLocationManagerWithLocation, self).setUp()155 super(TestLocationManagerWithLocation, self).setUp()
152 self.assertThat(156 self.assertThat(
153 self.main_window.get_qml_view().visible, Eventually(Equals(True)))157 self.get_qml_view().visible, Eventually(Equals(True)))
154158
155 def _open_location_manager(self):159 def _open_location_manager(self):
156 """Opens the location manager"""160 """Opens the location manager"""
157 toolbar = self.main_window.get_toolbar()161 self.main_window.open_toolbar().click_button("EditButton")
158 self.main_window.open_toolbar()
159 self.assertThat(toolbar.animating, Eventually(Equals(False)))
160 self.assertThat(toolbar.state, Eventually(Equals("spread")))
161 self.main_window.click_toolbar_button("EditButton")
162 location_manager_sheet = self.main_window.get_object(
163 "ComposerSheet", "LocationManagerSheet")
164 self.assertThat(location_manager_sheet.opacity, Eventually(Equals(1)))
165162
166 def _swipe_location_to_remove(self):163 def _swipe_location_to_remove(self):
167 """Swipe right to delete the first location"""164 """Swipe right to delete the first location"""
168 number_of_locations = self._get_number_of_locations()165 number_of_locations = self._get_number_of_locations()
169 firstLocation = self.app.select_single("Standard", objectName="existingLocation0")166 firstLocation = self.app.select_single("Standard", objectName="existingLocation0")
167 self.assertThat(lambda: firstLocation, Eventually(NotEquals(None)))
170 168
171 x, y, w, h = firstLocation.globalRect169 x, y, w, h = firstLocation.globalRect
172 tx = x + (w / 8)170 tx = x + (w / 8)
@@ -223,8 +221,3 @@
223 tabObjects = self.main_window.get_objects('LocationTab','LocationTab')221 tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
224 self.assertEqual(tabsSumStart, len(tabObjects))222 self.assertEqual(tabsSumStart, len(tabObjects))
225223
226 def test_toolbar_opened_when_location_is_defined(self):
227 """Toolbar is visible since there's a location defined"""
228 self._open_location_manager()
229 toolbar = self.main_window.get_toolbar()
230 self.assertThat(toolbar.opened, Eventually(Equals(True)))
231224
=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_mainview.py'
--- tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-07-27 16:31:15 +0000
+++ tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-08-07 17:39:25 +0000
@@ -4,6 +4,8 @@
4# This program is free software: you can redistribute it and/or modify it4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.6# by the Free Software Foundation.
7#
8# Authored by: Martin Borho <martin@borho.net>
79
8"""Tests for Weather app"""10"""Tests for Weather app"""
911
@@ -26,7 +28,7 @@
26 self.save_locations_to_storage(locations_data)28 self.save_locations_to_storage(locations_data)
27 super(TestMainView, self).setUp()29 super(TestMainView, self).setUp()
28 self.assertThat(30 self.assertThat(
29 self.main_window.get_qml_view().visible, Eventually(Equals(True)))31 self.get_qml_view().visible, Eventually(Equals(True)))
3032
31 def tearDown(self):33 def tearDown(self):
32 super(TestMainView, self).tearDown()34 super(TestMainView, self).tearDown()
@@ -42,7 +44,7 @@
42 self.assertThat(tabObjects[1].visible, Eventually(Equals(False)))44 self.assertThat(tabObjects[1].visible, Eventually(Equals(False)))
43 self.assertThat(tabObjects[0].title, Eventually(Equals("London")))45 self.assertThat(tabObjects[0].title, Eventually(Equals("London")))
44 # switch to next tab46 # switch to next tab
45 self.main_window.switch_to_tab(1)47 self.main_window.switch_to_tab_by_index(1)
46 self.assertThat(tabs.selectedTabIndex, Eventually(Equals(1)))48 self.assertThat(tabs.selectedTabIndex, Eventually(Equals(1)))
47 self.assertThat(tabObjects[0].visible, Eventually(Equals(False)))49 self.assertThat(tabObjects[0].visible, Eventually(Equals(False)))
48 self.assertThat(tabObjects[1].visible, Eventually(Equals(True)))50 self.assertThat(tabObjects[1].visible, Eventually(Equals(True)))
@@ -55,7 +57,7 @@
55 tab2_curr_date = curr_dates[2].text57 tab2_curr_date = curr_dates[2].text
5658
57 # refresh and wait till loading has finished59 # refresh and wait till loading has finished
58 self.main_window.click_toolbar_button("RefreshButton")60 self.main_window.open_toolbar().click_button("RefreshButton")
59 load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')61 load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')
60 self.assertThat(load_indicator.running, Eventually(Equals(False)))62 self.assertThat(load_indicator.running, Eventually(Equals(False)))
6163
6264
=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_settings.py'
--- tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-07-27 16:31:15 +0000
+++ tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-08-07 17:39:25 +0000
@@ -9,7 +9,7 @@
99
10from __future__ import absolute_import10from __future__ import absolute_import
1111
12from testtools.matchers import Equals12from testtools.matchers import Equals, NotEquals
13from autopilot.matchers import Eventually13from autopilot.matchers import Eventually
1414
15from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, SheetMixin15from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, SheetMixin
@@ -22,28 +22,27 @@
22 self.save_locations_to_storage(locations_data)22 self.save_locations_to_storage(locations_data)
23 super(TestSettings, self).setUp()23 super(TestSettings, self).setUp()
24 self.assertThat(24 self.assertThat(
25 self.main_window.get_qml_view().visible, Eventually(Equals(True)))25 self.get_qml_view().visible, Eventually(Equals(True)))
2626
27 def _open_settings_sheet(self):27 def _open_settings_sheet(self):
28 """Opens the settings sheet"""28 """Opens the settings sheet"""
29 self.main_window.open_toolbar()29 self.main_window.open_toolbar().click_button("SettingsButton")
30 self.assertThat(self.main_window.get_toolbar().opened, Eventually(Equals(True)))
31 self.main_window.click_toolbar_button("SettingsButton")
3230
33 def _move_pointer_around(self):31 def _move_pointer_around(self):
34 """Helper method to move the pointer around, to assure selector is opened"""32 """Helper method to move the pointer around, to assure selector is opened"""
35 sheet = self.main_window.get_object('ComposerSheet', 'SettingsSheet')33 sheet = self.main_window.get_object('ComposerSheet', 'SettingsSheet')
34 self.assertThat(lambda: sheet, Eventually(NotEquals(None)))
36 self.pointing_device.move_to_object(sheet)35 self.pointing_device.move_to_object(sheet)
3736
38 def _check_units(self, units):37 def _check_units(self, units):
39 """Checks selected units by values from the first location tab"""38 """Checks selected units by values from the first location tab"""
40 current_temps = self.main_window.get_objects('QQuickText', 'CurrentTempText')39 current_temps = self.main_window.get_objects('QQuickText', 'CurrentTempText')
41 if units == "imperial":40 if units == "imperial":
42 self.assertThat(current_temps[0].text, Eventually(Equals(u'76°F')))41 self.assertThat(current_temps[0].text, Eventually(Equals(u'70°F')))
43 self.assertThat(current_temps[2].text, Eventually(Equals(u'78°F')))42 self.assertThat(current_temps[2].text, Eventually(Equals(u'72°F')))
44 else:43 else:
45 self.assertThat(current_temps[0].text, Eventually(Equals(u'25°C')))44 self.assertThat(current_temps[0].text, Eventually(Equals(u'21°C')))
46 self.assertThat(current_temps[2].text, Eventually(Equals(u'25°C')))45 self.assertThat(current_temps[2].text, Eventually(Equals(u'22°C')))
4746
48 def test_switch_scale(self):47 def test_switch_scale(self):
49 """Tests switching the scale in the settings"""48 """Tests switching the scale in the settings"""
@@ -59,6 +58,7 @@
59 # choose second option, fahrenheit58 # choose second option, fahrenheit
60 self._move_pointer_around()59 self._move_pointer_around()
61 imperial_option = units_selector.get_children()[3]60 imperial_option = units_selector.get_children()[3]
61 self.assertThat(lambda: imperial_option, Eventually(NotEquals(None)))
62 self.pointing_device.click_object(imperial_option)62 self.pointing_device.click_object(imperial_option)
63 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))63 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))
64 self._click_sheet_confirm()64 self._click_sheet_confirm()
@@ -71,6 +71,7 @@
71 # switch back to metric values again71 # switch back to metric values again
72 self._open_settings_sheet()72 self._open_settings_sheet()
73 units_selector = self.main_window.get_object('ValueSelector', "UnitsSelector")73 units_selector = self.main_window.get_object('ValueSelector', "UnitsSelector")
74 self.assertThat(lambda: units_selector, Eventually(NotEquals(None)))
74 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))75 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))
75 self.pointing_device.click_object(units_selector)76 self.pointing_device.click_object(units_selector)
76 self.assertThat(units_selector.expanded, Eventually(Equals(True)))77 self.assertThat(units_selector.expanded, Eventually(Equals(True)))
@@ -78,6 +79,7 @@
78 # click celsius option79 # click celsius option
79 self._move_pointer_around()80 self._move_pointer_around()
80 metric_option = units_selector.get_children()[4]81 metric_option = units_selector.get_children()[4]
82 self.assertThat(lambda: metric_option, Eventually(NotEquals(None)))
81 self.pointing_device.click_object(metric_option)83 self.pointing_device.click_object(metric_option)
8284
83 # confirm85 # confirm
@@ -96,12 +98,14 @@
96 self._open_settings_sheet()98 self._open_settings_sheet()
9799
98 units_selector = self.main_window.get_object('ValueSelector', "UnitsSelector")100 units_selector = self.main_window.get_object('ValueSelector', "UnitsSelector")
101 self.assertThat(lambda: units_selector, Eventually(NotEquals(None)))
99 self.assertThat(units_selector.selectedIndex, Eventually(Equals(0)))102 self.assertThat(units_selector.selectedIndex, Eventually(Equals(0)))
100 self.pointing_device.click_object(units_selector)103 self.pointing_device.click_object(units_selector)
101104
102 # choose second option, fahrenheit105 # choose second option, fahrenheit
103 self._move_pointer_around()106 self._move_pointer_around()
104 imperial_option = units_selector.get_children()[3]107 imperial_option = units_selector.get_children()[3]
108 self.assertThat(lambda: imperial_option, Eventually(NotEquals(None)))
105 self.pointing_device.click_object(imperial_option)109 self.pointing_device.click_object(imperial_option)
106 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))110 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))
107111
108112
=== modified file 'tests/autopilot/ubuntu_weather_app/tests/weatherdata.py'
--- tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 2013-07-27 16:31:15 +0000
+++ tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 2013-08-07 17:39:25 +0000
@@ -6,8 +6,7 @@
6# by the Free Software Foundation.6# by the Free Software Foundation.
7locations_data = []7locations_data = []
88
9locations_data.append("""{"location":{"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"},"db":{"updated":"2013-07-27T16:06:14.606Z","id":1},"format":20130727,"data":[{"date":"2013-07-27","timestamp":1374926400,"metric":{"tempMin":15.55,"tempMax":24.5},"imperial":{"tempMin":59.99,"tempMax":76.1},"pressure":1009.81,"humidity":63,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"wind_speed":3.3,"wind_deg":101,"hourly":[],"current":{"timestamp":1374940874,"date":"2013-07-27 18:01","metric":{"temp":24.5},"imperial":{"temp":76.1},"humidity":64,"pressure":1004,"wind_speed_kmh":6.2,"wind_speed_mph":3.852494,"wind_deg":110,"condition":{"id":520,"main":"Rain","description":"light intensity shower rain","icon":"09d"},"service":"openweathermap","service_id":2643743}},{"date":"2013-07-28","timestamp":1375012800,"metric":{"tempMin":14.7,"tempMax":19.86},"imperial":{"tempMin":58.46,"tempMax":67.74799999999999},"pressure":1013.76,"humidity":91,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":4.46,"wind_deg":213,"hourly":[]},{"date":"2013-07-29","timestamp":1375099200,"metric":{"tempMin":14.67,"tempMax":17.63},"imperial":{"tempMin":58.406,"tempMax":63.733999999999995},"pressure":1016.16,"humidity":95,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":4.73,"wind_deg":213,"hourly":[]},{"date":"2013-07-30","timestamp":1375185600,"metric":{"tempMin":14.29,"tempMax":19.79},"imperial":{"tempMin":57.721999999999994,"tempMax":67.622},"pressure":1023.8,"humidity":70,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.98,"wind_deg":252,"hourly":[]},{"date":"2013-07-31","timestamp":1375272000,"metric":{"tempMin":15.19,"tempMax":24.08},"imperial":{"tempMin":59.342,"tempMax":75.344},"pressure":1021.26,"humidity":69,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":4.3,"wind_deg":217,"hourly":[]},{"date":"2013-08-01","timestamp":1375358400,"metric":{"tempMin":19.05,"tempMax":28.47},"imperial":{"tempMin":66.28999999999999,"tempMax":83.24600000000001},"pressure":1018.91,"humidity":59,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":3.45,"wind_deg":176,"hourly":[]},{"date":"2013-08-02","timestamp":1375444800,"metric":{"tempMin":14.26,"tempMax":18.83},"imperial":{"tempMin":57.668,"tempMax":65.894},"pressure":1016.86,"humidity":0,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":7.11,"wind_deg":207,"hourly":[]},{"date":"2013-08-03","timestamp":1375531200,"metric":{"tempMin":13.28,"tempMax":20.37},"imperial":{"tempMin":55.903999999999996,"tempMax":68.666},"pressure":1024.05,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.05,"wind_deg":249,"hourly":[]},{"date":"2013-08-04","timestamp":1375617600,"metric":{"tempMin":14.07,"tempMax":21.59},"imperial":{"tempMin":57.326,"tempMax":70.862},"pressure":1020.85,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.55,"wind_deg":165,"hourly":[]},{"date":"2013-08-05","timestamp":1375704000,"metric":{"tempMin":13.76,"tempMax":19.47},"imperial":{"tempMin":56.768,"tempMax":67.04599999999999},"pressure":1014.62,"humidity":0,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":5.38,"wind_deg":196,"hourly":[]}],"save":true}""")9locations_data.append("""{"location":{"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"},"db":{"updated":"2013-08-06T18:31:16.155Z","id":1},"format":20130801,"data":[{"date":"2013-08-06","timestamp":1375738207,"metric":{"tempMin":17.38,"tempMax":21.29,"windSpeed":5.22},"imperial":{"tempMin":63.284,"tempMax":70.322,"windSpeed":3.248,"rain":null},"pressure":1020.63,"humidity":58,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"windDeg":272,"hourly":[],"current":{"timestamp":1375813805,"date":"2013-08-06 20:30","metric":{"temp":21.29,"windSpeed":null},"imperial":{"temp":70.322,"windSpeed":null,"rain":null},"humidity":56,"pressure":1013,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"service":"openweathermap","service_id":2643743}},{"date":"2013-08-07","timestamp":1375876800,"metric":{"tempMin":14.25,"tempMax":22.14,"windSpeed":9.54},"imperial":{"tempMin":57.650000000000006,"tempMax":71.852,"windSpeed":5.936,"rain":null},"pressure":1019.36,"humidity":58,"condition":{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"},"windDeg":66,"hourly":[]},{"date":"2013-08-08","timestamp":1375963200,"metric":{"tempMin":13.13,"tempMax":22.86,"windSpeed":5.796},"imperial":{"tempMin":55.634,"tempMax":73.148,"windSpeed":3.6064000000000007,"rain":null},"pressure":1026.02,"humidity":58,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"windDeg":357,"hourly":[]},{"date":"2013-08-09","timestamp":1376049600,"metric":{"tempMin":14.09,"tempMax":23.71,"windSpeed":12.276000000000002},"imperial":{"tempMin":57.362,"tempMax":74.678,"windSpeed":7.638400000000001,"rain":null},"pressure":1025.05,"humidity":56,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"windDeg":260,"hourly":[]},{"date":"2013-08-10","timestamp":1376136000,"metric":{"tempMin":11.82,"tempMax":21.31,"windSpeed":9.395999999999999,"rain":1},"imperial":{"tempMin":53.275999999999996,"tempMax":70.358,"windSpeed":5.8464,"rain":0.03937007874015748},"pressure":1026.7,"humidity":69,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":224,"hourly":[]},{"date":"2013-08-11","timestamp":1376222400,"metric":{"tempMin":15.38,"tempMax":22.5,"windSpeed":11.916},"imperial":{"tempMin":59.684,"tempMax":72.5,"windSpeed":7.4144000000000005,"rain":null},"pressure":1021.58,"humidity":61,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"windDeg":255,"hourly":[]},{"date":"2013-08-12","timestamp":1376308800,"metric":{"tempMin":12.79,"tempMax":20.71,"windSpeed":14.148000000000001,"rain":1.14},"imperial":{"tempMin":55.022,"tempMax":69.278,"windSpeed":8.8032,"rain":0.04488188976377953},"pressure":1025.21,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":40,"hourly":[]},{"date":"2013-08-13","timestamp":1376395200,"metric":{"tempMin":11.61,"tempMax":22.22,"windSpeed":11.448,"rain":0.73},"imperial":{"tempMin":52.897999999999996,"tempMax":71.99600000000001,"windSpeed":7.123200000000001,"rain":0.02874015748031496},"pressure":1025.5,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":201,"hourly":[]},{"date":"2013-08-14","timestamp":1376481600,"metric":{"tempMin":16.09,"tempMax":22.97,"windSpeed":28.08,"rain":0.21},"imperial":{"tempMin":60.962,"tempMax":73.346,"windSpeed":17.472,"rain":0.00826771653543307},"pressure":1023.75,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":252,"hourly":[]},{"date":"2013-08-15","timestamp":1376568000,"metric":{"tempMin":14.36,"tempMax":22.61,"windSpeed":16.02,"rain":1.08},"imperial":{"tempMin":57.848,"tempMax":72.69800000000001,"windSpeed":9.968000000000002,"rain":0.042519685039370085},"pressure":1023.89,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":229,"hourly":[]}],"save":true}""")
1010
11locations_data.append( """{"location":{"coord":{"lon":10,"lat":53.549999},"service_id":2911298,"name":"Hamburg","country":"DE","service":"openweathermap"},"db":{"updated":"2013-07-27T16:06:14.628Z","id":2},"format":20130727,"data":[{"date":"2013-07-27","timestamp":1374922800,"metric":{"tempMin":16.77,"tempMax":25.3},"imperial":{"tempMin":62.186,"tempMax":77.53999999999999},"pressure":1018.72,"humidity":66,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":2.15,"wind_deg":102,"hourly":[],"current":{"timestamp":1374940200,"date":"2013-07-27 17:50","metric":{"temp":25.3},"imperial":{"temp":77.53999999999999},"humidity":94,"pressure":1009,"wind_speed_kmh":6.2,"wind_speed_mph":3.852494,"wind_deg":240,"condition":{"id":200,"main":"Thunderstorm","description":"thunderstorm with light rain","icon":"11d"},"service":"openweathermap","service_id":2911298}},{"date":"2013-07-28","timestamp":1375009200,"metric":{"tempMin":17.73,"tempMax":22.74},"imperial":{"tempMin":63.914,"tempMax":72.93199999999999},"pressure":1020.48,"humidity":87,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"wind_speed":6.21,"wind_deg":249,"hourly":[]},{"date":"2013-07-29","timestamp":1375095600,"metric":{"tempMin":15.53,"tempMax":23.35},"imperial":{"tempMin":59.954,"tempMax":74.03},"pressure":1024.02,"humidity":82,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":2.05,"wind_deg":172,"hourly":[]},{"date":"2013-07-30","timestamp":1375182000,"metric":{"tempMin":15.57,"tempMax":18.14},"imperial":{"tempMin":60.025999999999996,"tempMax":64.652},"pressure":1022.58,"humidity":95,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":7.5,"wind_deg":267,"hourly":[]},{"date":"2013-07-31","timestamp":1375268400,"metric":{"tempMin":15.09,"tempMax":23.08},"imperial":{"tempMin":59.162,"tempMax":73.544},"pressure":1028.48,"humidity":78,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"wind_speed":5,"wind_deg":258,"hourly":[]},{"date":"2013-08-01","timestamp":1375354800,"metric":{"tempMin":19.15,"tempMax":27.67},"imperial":{"tempMin":66.47,"tempMax":81.80600000000001},"pressure":1030.67,"humidity":73,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":0.85,"wind_deg":99,"hourly":[]},{"date":"2013-08-02","timestamp":1375441200,"metric":{"tempMin":13.19,"tempMax":18.78},"imperial":{"tempMin":55.742000000000004,"tempMax":65.804},"pressure":1022.53,"humidity":0,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"wind_speed":6.02,"wind_deg":253,"hourly":[]},{"date":"2013-08-03","timestamp":1375527600,"metric":{"tempMin":14.58,"tempMax":21.82},"imperial":{"tempMin":58.244,"tempMax":71.27600000000001},"pressure":1027.5,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.21,"wind_deg":261,"hourly":[]},{"date":"2013-08-04","timestamp":1375614000,"metric":{"tempMin":12.47,"tempMax":19.72},"imperial":{"tempMin":54.446,"tempMax":67.49600000000001},"pressure":1027.54,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":2.71,"wind_deg":1,"hourly":[]},{"date":"2013-08-05","timestamp":1375700400,"metric":{"tempMin":13.23,"tempMax":21.94},"imperial":{"tempMin":55.814,"tempMax":71.492},"pressure":1023.33,"humidity":0,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":2.09,"wind_deg":94,"hourly":[]}],"save":true}""")11locations_data.append("""{"location":{"coord":{"lon":10,"lat":53.549999},"service_id":2911298,"name":"Hamburg","country":"DE","service":"openweathermap"},"db":{"updated":"2013-08-06T18:35:14.332Z","id":2},"format":20130801,"data":[{"date":"2013-08-06","timestamp":1375738207,"metric":{"tempMin":13.37,"tempMax":20,"windSpeed":18.18},"imperial":{"tempMin":56.066,"tempMax":68,"windSpeed":11.312000000000001,"rain":null},"pressure":1024.52,"humidity":55,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"windDeg":302,"hourly":[],"current":{"timestamp":1375813203,"date":"2013-08-06 20:20","metric":{"temp":20,"windSpeed":null},"imperial":{"temp":68,"windSpeed":null,"rain":null},"humidity":64,"pressure":1015,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"service":"openweathermap","service_id":2911298}},{"date":"2013-08-07","timestamp":1375873200,"metric":{"tempMin":11.38,"tempMax":16.98,"windSpeed":13.860000000000001,"rain":22},"imperial":{"tempMin":52.484,"tempMax":62.564,"windSpeed":8.624,"rain":0.8661417322834646},"pressure":1025.03,"humidity":100,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"windDeg":7,"hourly":[]},{"date":"2013-08-08","timestamp":1375959600,"metric":{"tempMin":13.56,"tempMax":15.36,"windSpeed":15.515999999999998,"rain":13},"imperial":{"tempMin":56.408,"tempMax":59.647999999999996,"windSpeed":9.6544,"rain":0.5118110236220472},"pressure":1026.42,"humidity":100,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"windDeg":31,"hourly":[]},{"date":"2013-08-09","timestamp":1376046000,"metric":{"tempMin":11.19,"tempMax":20.06,"windSpeed":14.436},"imperial":{"tempMin":52.141999999999996,"tempMax":68.108,"windSpeed":8.9824,"rain":null},"pressure":1030.49,"humidity":91,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"windDeg":304,"hourly":[]},{"date":"2013-08-10","timestamp":1376132400,"metric":{"tempMin":13.81,"tempMax":21.32,"windSpeed":17.136},"imperial":{"tempMin":56.858000000000004,"tempMax":70.376,"windSpeed":10.6624,"rain":null},"pressure":1030.51,"humidity":80,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"windDeg":250,"hourly":[]},{"date":"2013-08-11","timestamp":1376218800,"metric":{"tempMin":16.51,"tempMax":23.68,"windSpeed":22.715999999999998,"rain":3},"imperial":{"tempMin":61.718,"tempMax":74.624,"windSpeed":14.134400000000001,"rain":0.11811023622047245},"pressure":1024.9,"humidity":68,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":238,"hourly":[]},{"date":"2013-08-12","timestamp":1376305200,"metric":{"tempMin":14.79,"tempMax":20.61,"windSpeed":10.044,"rain":0.59},"imperial":{"tempMin":58.622,"tempMax":69.098,"windSpeed":6.249600000000001,"rain":0.023228346456692913},"pressure":1028.45,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":275,"hourly":[]},{"date":"2013-08-13","timestamp":1376391600,"metric":{"tempMin":13.23,"tempMax":21.47,"windSpeed":5.184},"imperial":{"tempMin":55.814,"tempMax":70.646,"windSpeed":3.2256,"rain":null},"pressure":1029.35,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":48,"hourly":[]},{"date":"2013-08-14","timestamp":1376478000,"metric":{"tempMin":15.49,"tempMax":22.37,"windSpeed":7.704000000000001,"rain":0.33},"imperial":{"tempMin":59.882000000000005,"tempMax":72.266,"windSpeed":4.7936000000000005,"rain":0.01299212598425197},"pressure":1027.6,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":226,"hourly":[]},{"date":"2013-08-15","timestamp":1376564400,"metric":{"tempMin":15.3,"tempMax":23.26,"windSpeed":26.316},"imperial":{"tempMin":59.540000000000006,"tempMax":73.868,"windSpeed":16.3744,"rain":null},"pressure":1027.33,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"windDeg":253,"hourly":[]}],"save":true}""")
12
1312

Subscribers

People subscribed via source and target branches