Merge lp:~nskaggs/ubuntu-calendar-app/fix-infloop-ap-trunk into lp:ubuntu-calendar-app
- fix-infloop-ap-trunk
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Nicholas Skaggs | ||||||||
Approved revision: | 599 | ||||||||
Merged at revision: | 599 | ||||||||
Proposed branch: | lp:~nskaggs/ubuntu-calendar-app/fix-infloop-ap-trunk | ||||||||
Merge into: | lp:ubuntu-calendar-app | ||||||||
Diff against target: |
402 lines (+125/-157) 6 files modified
TimeLineBaseComponent.qml (+1/-0) TimeLineHeader.qml (+3/-2) WeekView.qml (+1/-1) tests/autopilot/calendar_app/__init__.py (+57/-1) tests/autopilot/calendar_app/tests/test_agendaview.py (+5/-14) tests/autopilot/calendar_app/tests/test_weekview.py (+58/-139) |
||||||||
To merge this branch: | bzr merge lp:~nskaggs/ubuntu-calendar-app/fix-infloop-ap-trunk | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Ubuntu Calendar Developers | Pending | ||
Review via email: mp+251122@code.launchpad.net |
Commit message
Fix inifinite loop in weekview tests; add testing stubs
Description of the change
Fix inifinite loop in weekview tests; add testing stubs
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:595
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:596
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:597
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:596
http://
Executed test runs:
None: http://
None: http://
None: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:597
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:598
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:599
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) wrote : | # |
So looks like trunk is more or less fixed. The tests will fail during the crossover period for days; see
This needs to be fixed by setting the date and time properly
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) : | # |
Preview Diff
1 | === modified file 'TimeLineBaseComponent.qml' |
2 | --- TimeLineBaseComponent.qml 2014-12-18 19:44:51 +0000 |
3 | +++ TimeLineBaseComponent.qml 2015-03-04 23:14:07 +0000 |
4 | @@ -31,6 +31,7 @@ |
5 | property var keyboardEventProvider; |
6 | |
7 | property date startDay: DateExt.today(); |
8 | + property int weekNumber: startDay.weekNumber(); |
9 | property bool isActive: false |
10 | property alias contentY: timeLineView.contentY |
11 | property alias contentInteractive: timeLineView.interactive |
12 | |
13 | === modified file 'TimeLineHeader.qml' |
14 | --- TimeLineHeader.qml 2015-02-18 19:11:05 +0000 |
15 | +++ TimeLineHeader.qml 2015-03-04 23:14:07 +0000 |
16 | @@ -44,7 +44,8 @@ |
17 | |
18 | Label{ |
19 | id: weekNumLabel |
20 | - text: i18n.tr("W") + root.startDay.weekNumber() |
21 | + objectName: "weeknumber" |
22 | + text: i18n.tr("W") + root.weekNumber |
23 | fontSize: "small" |
24 | height: units.gu(5) |
25 | width: parent.width |
26 | @@ -144,7 +145,7 @@ |
27 | |
28 | TimeLineHeaderComponent{ |
29 | objectName: "timelineHeader" |
30 | - startDay: headerRoot.startDay |
31 | + startDay: headerRoot.startDay |
32 | type: ViewType.ViewTypeWeek |
33 | width: parent.width |
34 | height: units.gu(5) |
35 | |
36 | === modified file 'WeekView.qml' |
37 | --- WeekView.qml 2015-02-18 19:27:20 +0000 |
38 | +++ WeekView.qml 2015-03-04 23:14:07 +0000 |
39 | @@ -65,7 +65,7 @@ |
40 | |
41 | PathViewBase{ |
42 | id: weekViewPath |
43 | - objectName: "weekViewPath" |
44 | + objectName: "weekviewpathbase" |
45 | |
46 | anchors.fill: parent |
47 | |
48 | |
49 | === modified file 'tests/autopilot/calendar_app/__init__.py' |
50 | --- tests/autopilot/calendar_app/__init__.py 2015-02-26 18:26:10 +0000 |
51 | +++ tests/autopilot/calendar_app/__init__.py 2015-03-04 23:14:07 +0000 |
52 | @@ -24,6 +24,7 @@ |
53 | import ubuntuuitoolkit |
54 | from autopilot import exceptions |
55 | from dateutil import tz |
56 | +import math |
57 | from testtools.matchers import GreaterThan |
58 | |
59 | from calendar_app import data |
60 | @@ -256,7 +257,7 @@ |
61 | """Swipe the given view to up or down. |
62 | |
63 | Args: |
64 | - direction: |
65 | + direction: |
66 | """ |
67 | |
68 | start = (-direction * y_pad) % 1 |
69 | @@ -374,6 +375,58 @@ |
70 | |
71 | """Autopilot helper for the Week View page.""" |
72 | |
73 | + def get_current_weeknumber(self): |
74 | + return self._get_timeline_base().weekNumber |
75 | + |
76 | + def _get_timeline_base(self): |
77 | + return self.select_single("TimeLineBaseComponent", isActive=True) |
78 | + |
79 | + def _get_timeline_header(self): |
80 | + return self._get_timeline_base().select_single(objectName="viewHeader") |
81 | + |
82 | + def _get_date_label_headers(self): |
83 | + return self._get_timeline_header().select_many("Label", |
84 | + objectName="dateLabel") |
85 | + |
86 | + def _get_pathview_base(self): |
87 | + # return self.select_single('PathViewBase', |
88 | + # objectname='weekviewpathbase') |
89 | + # why do you hate me autopilot? ^^ |
90 | + return self.select_single('PathViewBase') |
91 | + |
92 | + def change_week(self, delta): |
93 | + direction = int(math.copysign(1, delta)) |
94 | + main_view = self.get_root_instance().select_single(MainView) |
95 | + |
96 | + pathview_base = self._get_pathview_base() |
97 | + |
98 | + for _ in range(abs(delta)): |
99 | + timeline_header = self._get_timeline_header() |
100 | + |
101 | + main_view.swipe_view(direction, timeline_header) |
102 | + # prevent timing issues with swiping |
103 | + pathview_base.moving.wait_for(False) |
104 | + |
105 | + def get_days_of_week(self): |
106 | + # sort based on text value of the day |
107 | + days = sorted(self._get_date_label_headers(), |
108 | + key=lambda label: label.text) |
109 | + days = [int(item.text) for item in days] |
110 | + |
111 | + # resort so beginning of next month comes after the end |
112 | + # need to support overlapping months 28,30,31 -> 1 |
113 | + sorteddays = [] |
114 | + for day in days: |
115 | + inserted = 0 |
116 | + for index, sortday in enumerate(sorteddays): |
117 | + if day - sorteddays[index] == 1: |
118 | + sorteddays.insert(index + 1, day) |
119 | + inserted = 1 |
120 | + break |
121 | + if inserted == 0: |
122 | + sorteddays.insert(0, day) |
123 | + return sorteddays |
124 | + |
125 | |
126 | class MonthView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
127 | |
128 | @@ -445,6 +498,9 @@ |
129 | |
130 | raise CalendarException('No event found for %s' % event_name) |
131 | |
132 | + def get_selected_day(self): |
133 | + return self._get_day_component() |
134 | + |
135 | def _get_day_component(self, day='selected'): |
136 | """Get the selected day component. |
137 | This method considers 'yesterday' to be the selected day - 1 |
138 | |
139 | === modified file 'tests/autopilot/calendar_app/tests/test_agendaview.py' |
140 | --- tests/autopilot/calendar_app/tests/test_agendaview.py 2015-02-25 21:23:53 +0000 |
141 | +++ tests/autopilot/calendar_app/tests/test_agendaview.py 2015-03-04 23:14:07 +0000 |
142 | @@ -22,9 +22,6 @@ |
143 | |
144 | import logging |
145 | |
146 | -from autopilot.matchers import Eventually |
147 | -from testtools.matchers import Equals |
148 | - |
149 | from calendar_app.tests import CalendarAppTestCaseWithVcard |
150 | |
151 | from calendar_app import data |
152 | @@ -48,14 +45,8 @@ |
153 | event_details_page = self.app.main_view.get_event_details() |
154 | event_details = event_details_page.get_event_information() |
155 | |
156 | - self.assertThat( |
157 | - event_details.name, Eventually(Equals(test_event.name))) |
158 | - self.assertThat( |
159 | - event_details.description, |
160 | - Eventually(Equals(test_event.description))) |
161 | - self.assertThat( |
162 | - event_details.calendar, Eventually(Equals(test_event.calendar))) |
163 | - self.assertThat( |
164 | - event_details.location, Eventually(Equals(test_event.location))) |
165 | - self.assertThat( |
166 | - event_details.guests, Eventually(Equals(test_event.guests))) |
167 | + self.assertEquals(event_details.name, test_event.name) |
168 | + self.assertEquals(event_details.description, test_event.description) |
169 | + self.assertEquals(event_details.calendar, test_event.calendar) |
170 | + self.assertEquals(event_details.location, test_event.location) |
171 | + self.assertEquals(event_details.guests, test_event.guests) |
172 | |
173 | === modified file 'tests/autopilot/calendar_app/tests/test_weekview.py' |
174 | --- tests/autopilot/calendar_app/tests/test_weekview.py 2014-12-18 19:44:51 +0000 |
175 | +++ tests/autopilot/calendar_app/tests/test_weekview.py 2015-03-04 23:14:07 +0000 |
176 | @@ -26,7 +26,8 @@ |
177 | |
178 | import datetime |
179 | from autopilot.matchers import Eventually |
180 | -from testtools.matchers import Equals, NotEquals |
181 | +from testtools.matchers import Equals |
182 | +from random import randint, randrange |
183 | |
184 | from calendar_app.tests import CalendarAppTestCase |
185 | import logging |
186 | @@ -40,150 +41,69 @@ |
187 | super(TestWeekView, self).setUp() |
188 | self.week_view = self.app.main_view.go_to_week_view() |
189 | |
190 | - def _change_week(self, direction): |
191 | - first_dow = self._get_first_day_of_week() |
192 | - |
193 | - # prevent timing issues with swiping |
194 | - old_day = self.app.main_view.to_local_date( |
195 | - self.week_view.dayStart.datetime) |
196 | - |
197 | - pathView = self.week_view.select_single("PathViewBase") |
198 | - timeLineBase = pathView.select_single("TimeLineBaseComponent", |
199 | - isActive=True) |
200 | - timelineview = timeLineBase.select_single(objectName="timelineview") |
201 | - val = 0 |
202 | - if direction == 1: |
203 | - val = timelineview.contentWidth - timelineview.width |
204 | - |
205 | - while timelineview.contentX != val: |
206 | - self.app.main_view.swipe_view(direction, self.week_view) |
207 | - |
208 | - self.app.main_view.swipe_view(direction, self.week_view) |
209 | - self.assertThat(lambda: |
210 | - self.app.main_view.to_local_date( |
211 | - self.week_view.dayStart.datetime), |
212 | - Eventually(NotEquals(old_day))) |
213 | - |
214 | - new_day_start = self.app.main_view.to_local_date( |
215 | - self.week_view.dayStart.datetime) |
216 | - |
217 | - expected_day_start = first_dow + datetime.timedelta( |
218 | - days=(7 * direction)) |
219 | - |
220 | - self.assertThat(new_day_start.day, Equals(expected_day_start.day)) |
221 | - |
222 | - def _get_days_of_week(self): |
223 | - # sort based on text value of the day |
224 | - days = sorted(self._get_date_label_headers(), |
225 | - key=lambda label: label.text) |
226 | - days = [int(item.text) for item in days] |
227 | - |
228 | - # resort so beginning of next month comes after the end |
229 | - # need to support overlapping months 28,30,31 -> 1 |
230 | - sorteddays = [] |
231 | - for day in days: |
232 | - inserted = 0 |
233 | - for index, sortday in enumerate(sorteddays): |
234 | - if day - sorteddays[index] == 1: |
235 | - sorteddays.insert(index + 1, day) |
236 | - inserted = 1 |
237 | - break |
238 | - if inserted == 0: |
239 | - sorteddays.insert(0, day) |
240 | - return sorteddays |
241 | - |
242 | - def _get_date_label_headers(self): |
243 | - pathView = self.week_view.select_single("PathViewBase") |
244 | - timeLineBase = pathView.select_single("TimeLineBaseComponent", |
245 | - isActive=True) |
246 | - viewHeader = timeLineBase.select_single(objectName="viewHeader") |
247 | - timeLineHeader = viewHeader.select_single(objectName="timelineHeader") |
248 | - dateLabels = timeLineHeader.select_many("Label", |
249 | - objectName="dateLabel") |
250 | - return dateLabels |
251 | - |
252 | - def _get_first_day_of_week(self): |
253 | - date = self.app.main_view.to_local_date( |
254 | - self.week_view.dayStart.datetime) |
255 | - firstDay = self.app.main_view.to_local_date( |
256 | - self.week_view.firstDay.datetime) |
257 | - |
258 | - # sunday |
259 | - if firstDay.weekday() == 6: |
260 | - logger.debug("Locale has Sunday as first day of week") |
261 | - weekday = date.weekday() |
262 | - diff = datetime.timedelta(days=weekday + 1) |
263 | - # saturday |
264 | - elif firstDay.weekday() == 5: |
265 | - logger.debug("Locale has Saturday as first day of week") |
266 | - weekday = date.weekday() |
267 | - diff = datetime.timedelta(days=weekday + 2) |
268 | - # monday |
269 | - else: |
270 | - logger.debug("Locale has Monday as first day of week") |
271 | - weekday = date.weekday() |
272 | - diff = datetime.timedelta(days=weekday) |
273 | - |
274 | - # set the start of week |
275 | - if date.day != firstDay.day: |
276 | - day_start = date - diff |
277 | - logger.debug("Setting day_start to %s" % firstDay.day) |
278 | - else: |
279 | - day_start = date |
280 | - logger.debug("Using today as day_start %s" % date) |
281 | - return day_start |
282 | - |
283 | - def test_current_month_and_year_is_selected(self): |
284 | - """By default, the week view shows the current month and year.""" |
285 | + def _assert_week_delta(self, original_week, delta): |
286 | + current_week = self.week_view.get_current_weeknumber() |
287 | + expected_week = original_week + delta |
288 | + |
289 | + if expected_week < 0: |
290 | + expected_week += 53 |
291 | + elif expected_week > 52: |
292 | + expected_week -= 53 |
293 | + |
294 | + self.assertEquals(current_week, expected_week) |
295 | + |
296 | + def test_default_view(self): |
297 | + """By default, the week view shows the current week. |
298 | + It also displays the current year and month""" |
299 | |
300 | now = datetime.datetime.now() |
301 | - |
302 | expected_month_name_year = now.strftime("%B %Y") |
303 | - |
304 | self.assertThat(self.app.main_view.get_month_year(self.week_view), |
305 | Equals(expected_month_name_year)) |
306 | |
307 | - def test_current_week_is_selected(self): |
308 | - """By default, the week view shows the current week.""" |
309 | - |
310 | - now = datetime.datetime.now() |
311 | - days = self._get_days_of_week() |
312 | - day_headers = self._get_date_label_headers() |
313 | - |
314 | - first_dow = self._get_first_day_of_week() |
315 | - |
316 | - for i in range(7): |
317 | - current_day = days[i] |
318 | - expected_day = (first_dow + datetime.timedelta(days=i)).day |
319 | - |
320 | - self.assertThat(current_day, Equals(expected_day)) |
321 | - |
322 | - # current day is highlighted in white. |
323 | - # days returned by AP are out of order, so check header and today |
324 | - color = day_headers[i].color |
325 | - label_color = (color[0], color[1], color[2], color[3]) |
326 | - if label_color == (255, 255, 255, 255): |
327 | - self.assertThat(int(day_headers[i].text), Equals(now.day)) |
328 | - |
329 | - def test_show_next_weeks(self): |
330 | - """It must be possible to show next weeks by swiping the view.""" |
331 | - for i in range(6): |
332 | - self._change_week(1) |
333 | - |
334 | - def test_show_previous_weeks(self): |
335 | - """It must be possible to show previous weeks by swiping the view.""" |
336 | - for i in range(6): |
337 | - self._change_week(-1) |
338 | + # TODO: check current day is highlighted |
339 | + |
340 | + # These testing stubs need completed |
341 | + # def test_scroll_week_must_scroll_within_week(self): |
342 | + # """Scrolling inside the timeline should scroll the weekdays""" |
343 | + # pass |
344 | + |
345 | + # def test_change_week_across_month(self): |
346 | + # """Changing week across months should update the month""" |
347 | + # pass |
348 | + |
349 | + # def test_change_week_across_year(self): |
350 | + # """Changing week across years should update the year""" |
351 | + # pass |
352 | + |
353 | + # def test_month_to_week(self): |
354 | + # """Changing from a month to weekview should |
355 | + # start weekview on the first week of the month""" |
356 | + # pass |
357 | + |
358 | + # def test_day_to_week(self): |
359 | + # """Changing from a day to weekview should |
360 | + # start weekview on the same week as the day""" |
361 | + # pass |
362 | + |
363 | + def test_change_week(self): |
364 | + """It must be possible to change weeks by swiping the timeline""" |
365 | + weeks = randint(1, 6) |
366 | + direction = randrange(-1, 1, 2) |
367 | + delta = weeks * direction |
368 | + original_week = self.week_view.get_current_weeknumber() |
369 | + |
370 | + self.week_view.change_week(delta) |
371 | + self._assert_week_delta(original_week, delta) |
372 | |
373 | def test_selecting_a_day_switches_to_day_view(self): |
374 | """It must be possible to show a single day by clicking on it.""" |
375 | - first_day_date = self.week_view.firstDay |
376 | - # expected_day = first_day_date.day |
377 | - expected_month = first_day_date.month |
378 | - expected_year = first_day_date.year |
379 | - |
380 | - days = self._get_days_of_week() |
381 | + days = self.week_view.get_days_of_week() |
382 | day_to_select = self.app.main_view.get_label_with_text(days[0]) |
383 | + expected_day = days[0] |
384 | + dayStart = self.week_view.dayStart |
385 | + expected_month = dayStart.month |
386 | + expected_year = dayStart.year |
387 | |
388 | self.app.pointing_device.click_object(day_to_select) |
389 | |
390 | @@ -192,9 +112,8 @@ |
391 | self.assertThat(day_view.visible, Eventually(Equals(True))) |
392 | |
393 | # Check that the 'Day' view is on the correct/selected day. |
394 | - selected_date = datetime.datetime.strptime( |
395 | - self.app.main_view.get_month_year(day_view), |
396 | - '%B %Y') |
397 | - # self.assertThat(expected_day, Equals(selected_date.day)) |
398 | + selected_date = \ |
399 | + self.app.main_view.get_day_view().get_selected_day().startDay |
400 | + self.assertThat(expected_day, Equals(selected_date.day)) |
401 | self.assertThat(expected_month, Equals(selected_date.month)) |
402 | self.assertThat(expected_year, Equals(selected_date.year)) |
FAILED: Continuous integration, rev:594 91.189. 93.70:8080/ job/ubuntu- calendar- app-ci/ 1088/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic/ 2128/console 91.189. 93.70:8080/ job/ubuntu- calendar- app-vivid- amd64-ci/ 85/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- calendar- app-ci/ 1088/rebuild
http://