Merge lp:~ahayzen/music-app/ap-helper-refactor-004 into lp:music-app/trusty
- ap-helper-refactor-004
- Merge into trusty
Status: | Merged |
---|---|
Approved by: | Nicholas Skaggs |
Approved revision: | 616 |
Merged at revision: | 634 |
Proposed branch: | lp:~ahayzen/music-app/ap-helper-refactor-004 |
Merge into: | lp:music-app/trusty |
Prerequisite: | lp:~ahayzen/music-app/ap-helper-refactor-003 |
Diff against target: |
701 lines (+210/-189) 3 files modified
MusicToolbar.qml (+3/-0) tests/autopilot/music_app/__init__.py (+25/-7) tests/autopilot/music_app/tests/test_music.py (+182/-182) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/ap-helper-refactor-004 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nicholas Skaggs (community) | Approve | ||
Victor Thompson | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+233291@code.launchpad.net |
Commit message
* Remove main_view and pointing_device properties
* Use virtual model of metadata rather than hardcoding track_index, track_title etc
* Improve toolbar handling
* Make click_play_button helper automatically choose the correct button
* Improve some tests especially ones with 'while'
* Improve code comments
Description of the change
* Remove main_view and pointing_device properties
* Use virtual model of metadata rather than hardcoding track_index, track_title etc
* Improve toolbar handling
* Make click_play_button helper automatically choose the correct button
* Improve some tests especially ones with 'while'
* Improve code comments
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:610
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Andrew Hayzen (ahayzen) wrote : | # |
#blocked bug 1365247 (mediascanner2 db schema change)
Andrew Hayzen (ahayzen) wrote : | # |
#unblocked
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:611
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:612
http://
Executed test runs:
UNSTABLE: 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:613
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
See inline comments.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:614
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:614
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: Continuous integration, rev:616
http://
Executed test runs:
UNSTABLE: 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:616
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
I think having this "virtual model" for metadata currently hurts the readability of the tests that use it, but I know having it will prove useful in the future. Also, the restructuring of some of the various loops looks good. Approved, but waiting for a secondary review by balloons.
Nicholas Skaggs (nskaggs) : | # |
Preview Diff
1 | === modified file 'MusicToolbar.qml' | |||
2 | --- MusicToolbar.qml 2014-08-22 23:41:29 +0000 | |||
3 | +++ MusicToolbar.qml 2014-09-10 13:42:37 +0000 | |||
4 | @@ -51,6 +51,9 @@ | |||
5 | 51 | property alias animating: musicToolbarPanel.animating | 51 | property alias animating: musicToolbarPanel.animating |
6 | 52 | property alias opened: musicToolbarPanel.opened | 52 | property alias opened: musicToolbarPanel.opened |
7 | 53 | 53 | ||
8 | 54 | // Alias for autopilot | ||
9 | 55 | property alias currentMode: musicToolbarPanel.currentMode | ||
10 | 56 | |||
11 | 54 | Connections { | 57 | Connections { |
12 | 55 | id: pageStackConn | 58 | id: pageStackConn |
13 | 56 | target: mainPageStack | 59 | target: mainPageStack |
14 | 57 | 60 | ||
15 | === modified file 'tests/autopilot/music_app/__init__.py' | |||
16 | --- tests/autopilot/music_app/__init__.py 2014-09-04 20:02:14 +0000 | |||
17 | +++ tests/autopilot/music_app/__init__.py 2014-09-10 13:42:37 +0000 | |||
18 | @@ -15,8 +15,19 @@ | |||
19 | 15 | 15 | ||
20 | 16 | def click_object(func): | 16 | def click_object(func): |
21 | 17 | """Wrapper which clicks the returned object""" | 17 | """Wrapper which clicks the returned object""" |
24 | 18 | def func_wrapper(self, *args): | 18 | def func_wrapper(self, *args, **kwargs): |
25 | 19 | return self.pointing_device.click_object(func(self, *args)) | 19 | return self.pointing_device.click_object(func(self, *args, **kwargs)) |
26 | 20 | |||
27 | 21 | return func_wrapper | ||
28 | 22 | |||
29 | 23 | |||
30 | 24 | def ensure_toolbar_visible(func): | ||
31 | 25 | """Wrapper which ensures the toolbar is shown before clicking""" | ||
32 | 26 | def func_wrapper(self, *args, **kwargs): | ||
33 | 27 | if not self.opened: | ||
34 | 28 | self.show() | ||
35 | 29 | |||
36 | 30 | return func(self, *args, **kwargs) | ||
37 | 20 | 31 | ||
38 | 21 | return func_wrapper | 32 | return func_wrapper |
39 | 22 | 33 | ||
40 | @@ -268,30 +279,35 @@ | |||
41 | 268 | root = self.get_root_instance() | 279 | root = self.get_root_instance() |
42 | 269 | self.player = root.select_single(Player, objectName="player") | 280 | self.player = root.select_single(Player, objectName="player") |
43 | 270 | 281 | ||
48 | 271 | @click_object | 282 | @ensure_toolbar_visible |
45 | 272 | def click_small_play_button(self): | ||
46 | 273 | return self.wait_select_single("*", objectName="smallPlayShape") | ||
47 | 274 | |||
49 | 275 | @click_object | 283 | @click_object |
50 | 276 | def click_forward_button(self): | 284 | def click_forward_button(self): |
51 | 277 | return self.wait_select_single("*", objectName="forwardShape") | 285 | return self.wait_select_single("*", objectName="forwardShape") |
52 | 278 | 286 | ||
53 | 287 | @ensure_toolbar_visible | ||
54 | 279 | @click_object | 288 | @click_object |
55 | 280 | def click_play_button(self): | 289 | def click_play_button(self): |
57 | 281 | return self.wait_select_single("*", objectName="playShape") | 290 | if self.currentMode == "full": |
58 | 291 | return self.wait_select_single("*", objectName="playShape") | ||
59 | 292 | else: | ||
60 | 293 | return self.wait_select_single("*", objectName="smallPlayShape") | ||
61 | 282 | 294 | ||
62 | 295 | @ensure_toolbar_visible | ||
63 | 283 | @click_object | 296 | @click_object |
64 | 284 | def click_previous_button(self): | 297 | def click_previous_button(self): |
65 | 285 | return self.wait_select_single("*", objectName="previousShape") | 298 | return self.wait_select_single("*", objectName="previousShape") |
66 | 286 | 299 | ||
67 | 300 | @ensure_toolbar_visible | ||
68 | 287 | @click_object | 301 | @click_object |
69 | 288 | def click_repeat_button(self): | 302 | def click_repeat_button(self): |
70 | 289 | return self.wait_select_single("*", objectName="repeatShape") | 303 | return self.wait_select_single("*", objectName="repeatShape") |
71 | 290 | 304 | ||
72 | 305 | @ensure_toolbar_visible | ||
73 | 291 | @click_object | 306 | @click_object |
74 | 292 | def click_shuffle_button(self): | 307 | def click_shuffle_button(self): |
75 | 293 | return self.wait_select_single("*", objectName="shuffleShape") | 308 | return self.wait_select_single("*", objectName="shuffleShape") |
76 | 294 | 309 | ||
77 | 310 | @ensure_toolbar_visible | ||
78 | 295 | def seek_to(self, percentage): | 311 | def seek_to(self, percentage): |
79 | 296 | progress_bar = self.wait_select_single( | 312 | progress_bar = self.wait_select_single( |
80 | 297 | "*", objectName="progressBarShape") | 313 | "*", objectName="progressBarShape") |
81 | @@ -303,12 +319,14 @@ | |||
82 | 303 | 319 | ||
83 | 304 | self.pointing_device.drag(x1, y1, x2, y1) | 320 | self.pointing_device.drag(x1, y1, x2, y1) |
84 | 305 | 321 | ||
85 | 322 | @ensure_toolbar_visible | ||
86 | 306 | def set_repeat(self, state): | 323 | def set_repeat(self, state): |
87 | 307 | if self.player.repeat != state: | 324 | if self.player.repeat != state: |
88 | 308 | self.click_repeat_button() | 325 | self.click_repeat_button() |
89 | 309 | 326 | ||
90 | 310 | self.player.repeat.wait_for(state) | 327 | self.player.repeat.wait_for(state) |
91 | 311 | 328 | ||
92 | 329 | @ensure_toolbar_visible | ||
93 | 312 | def set_shuffle(self, state): | 330 | def set_shuffle(self, state): |
94 | 313 | if self.player.shuffle != state: | 331 | if self.player.shuffle != state: |
95 | 314 | self.click_shuffle_button() | 332 | self.click_shuffle_button() |
96 | 315 | 333 | ||
97 | === modified file 'tests/autopilot/music_app/tests/test_music.py' | |||
98 | --- tests/autopilot/music_app/tests/test_music.py 2014-09-04 20:02:14 +0000 | |||
99 | +++ tests/autopilot/music_app/tests/test_music.py 2014-09-10 13:42:37 +0000 | |||
100 | @@ -9,7 +9,6 @@ | |||
101 | 9 | 9 | ||
102 | 10 | from __future__ import absolute_import | 10 | from __future__ import absolute_import |
103 | 11 | 11 | ||
104 | 12 | import time | ||
105 | 13 | import logging | 12 | import logging |
106 | 14 | from autopilot.matchers import Eventually | 13 | from autopilot.matchers import Eventually |
107 | 15 | from testtools.matchers import Equals, LessThan, NotEquals | 14 | from testtools.matchers import Equals, LessThan, NotEquals |
108 | @@ -25,36 +24,44 @@ | |||
109 | 25 | def setUp(self): | 24 | def setUp(self): |
110 | 26 | super(TestMainWindow, self).setUp() | 25 | super(TestMainWindow, self).setUp() |
111 | 27 | 26 | ||
123 | 28 | self.album_artist_index = 0 # position on AlbumsPage | 27 | # metadata for test tracks sorted by title |
124 | 29 | self.album_index = 0 # position on MusicAlbums | 28 | # tests should sort themselves if they require by artist/album |
125 | 30 | self.artist_index = 0 # position on MusicArtists | 29 | self.tracks = [ |
126 | 31 | self.track_index = 0 # position on MusicTracks | 30 | { |
127 | 32 | self.track_title = u"Gran Vals" | 31 | "album": "", |
128 | 33 | self.artist_name = u"Francisco Tárrega" | 32 | "artist": u"Francisco Tárrega", |
129 | 34 | self.last_track_title = u"TestMP3Title" | 33 | "source": "1.ogg", |
130 | 35 | 34 | "title": u"Gran Vals" | |
131 | 36 | @property | 35 | }, |
132 | 37 | def main_view(self): | 36 | { |
133 | 38 | return self.app.main_view | 37 | "album": "", |
134 | 38 | "artist": "Josh Woodward", | ||
135 | 39 | "source": "2.ogg", | ||
136 | 40 | "title": "Swansong" | ||
137 | 41 | }, | ||
138 | 42 | { | ||
139 | 43 | "album": "TestMP3Album", | ||
140 | 44 | "artist": "TestMP3Artist", | ||
141 | 45 | "source": "3.mp3", | ||
142 | 46 | "title": "TestMP3Title", | ||
143 | 47 | } | ||
144 | 48 | ] | ||
145 | 39 | 49 | ||
146 | 40 | @property | 50 | @property |
147 | 41 | def player(self): | 51 | def player(self): |
148 | 42 | return self.app.player | 52 | return self.app.player |
149 | 43 | 53 | ||
150 | 44 | @property | ||
151 | 45 | def pointing_device(self): | ||
152 | 46 | return self.app.app.pointing_device | ||
153 | 47 | |||
154 | 48 | def test_reads_music_library(self): | 54 | def test_reads_music_library(self): |
155 | 49 | """ tests if the music library is populated from our | 55 | """ tests if the music library is populated from our |
156 | 50 | fake mediascanner database""" | 56 | fake mediascanner database""" |
157 | 51 | 57 | ||
158 | 52 | self.app.populate_queue() # populate queue | 58 | self.app.populate_queue() # populate queue |
159 | 53 | 59 | ||
164 | 54 | title = lambda: self.player.currentMetaTitle | 60 | # Check current meta data is correct |
165 | 55 | artist = lambda: self.player.currentMetaArtist | 61 | self.assertThat(self.player.currentMetaTitle, |
166 | 56 | self.assertThat(title, Eventually(Equals(self.track_title))) | 62 | Eventually(Equals(self.tracks[0]["title"]))) |
167 | 57 | self.assertThat(artist, Eventually(Equals(self.artist_name))) | 63 | self.assertThat(self.player.currentMetaArtist, |
168 | 64 | Eventually(Equals(self.tracks[0]["artist"]))) | ||
169 | 58 | 65 | ||
170 | 59 | def test_play_pause_library(self): | 66 | def test_play_pause_library(self): |
171 | 60 | """ Test playing and pausing a track (Music Library must exist) """ | 67 | """ Test playing and pausing a track (Music Library must exist) """ |
172 | @@ -65,21 +72,17 @@ | |||
173 | 65 | # get number of tracks in queue before queuing a track | 72 | # get number of tracks in queue before queuing a track |
174 | 66 | initial_tracks_count = now_playing_page.get_count() | 73 | initial_tracks_count = now_playing_page.get_count() |
175 | 67 | 74 | ||
179 | 68 | # switch to albums tab | 75 | # switch to albums tab and select the album |
180 | 69 | albums_page = self.app.get_albums_page() | 76 | self.app.get_albums_page().click_album(0) |
178 | 70 | albums_page.click_album(self.album_index) # select album | ||
181 | 71 | 77 | ||
182 | 72 | # get track item to swipe and queue | 78 | # get track item to swipe and queue |
186 | 73 | songs_page = self.app.get_songs_page() | 79 | track = self.app.get_songs_page().get_track(0) |
184 | 74 | |||
185 | 75 | track = songs_page.get_track(0) | ||
187 | 76 | track.swipe_reveal_actions() | 80 | track.swipe_reveal_actions() |
188 | 77 | 81 | ||
189 | 78 | track.click_add_to_queue_action() # add track to the queue | 82 | track.click_add_to_queue_action() # add track to the queue |
190 | 79 | 83 | ||
194 | 80 | # verify track queue has added one to initial value | 84 | # wait for track to be queued |
195 | 81 | self.assertThat(now_playing_page.get_count(), | 85 | now_playing_page.get_count().wait_for(initial_tracks_count + 1) |
193 | 82 | Eventually(Equals(initial_tracks_count + 1))) | ||
196 | 83 | 86 | ||
197 | 84 | end_tracks_count = now_playing_page.get_count() | 87 | end_tracks_count = now_playing_page.get_count() |
198 | 85 | 88 | ||
199 | @@ -92,28 +95,19 @@ | |||
200 | 92 | current_track = now_playing_page.get_track(self.player.currentIndex) | 95 | current_track = now_playing_page.get_track(self.player.currentIndex) |
201 | 93 | 96 | ||
202 | 94 | self.assertThat(current_track.get_label_text("artistLabel"), | 97 | self.assertThat(current_track.get_label_text("artistLabel"), |
204 | 95 | Equals(self.artist_name)) | 98 | Equals(self.tracks[0]["artist"])) |
205 | 96 | self.assertThat(current_track.get_label_text("titleLabel"), | 99 | self.assertThat(current_track.get_label_text("titleLabel"), |
207 | 97 | Equals(self.track_title)) | 100 | Equals(self.tracks[0]["title"])) |
208 | 98 | 101 | ||
209 | 99 | # click on close button to close the page | 102 | # click on close button to close the page |
223 | 100 | self.main_view.go_back() | 103 | self.app.main_view.go_back() |
224 | 101 | 104 | ||
225 | 102 | """ Track is playing""" | 105 | # click the play button to start playing |
226 | 103 | if self.main_view.wideAspect: | 106 | toolbar.click_play_button() |
214 | 104 | click_play_button = toolbar.click_play_button | ||
215 | 105 | else: | ||
216 | 106 | if not toolbar.opened: | ||
217 | 107 | toolbar.show() | ||
218 | 108 | |||
219 | 109 | click_play_button = toolbar.click_small_play_button | ||
220 | 110 | |||
221 | 111 | click_play_button() | ||
222 | 112 | |||
227 | 113 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 107 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
228 | 114 | 108 | ||
231 | 115 | """ Track is not playing""" | 109 | # click the play button to stop playing |
232 | 116 | click_play_button() | 110 | toolbar.click_play_button() |
233 | 117 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 111 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
234 | 118 | 112 | ||
235 | 119 | def test_play_pause_now_playing(self): | 113 | def test_play_pause_now_playing(self): |
236 | @@ -123,15 +117,15 @@ | |||
237 | 123 | 117 | ||
238 | 124 | toolbar = self.app.get_toolbar() | 118 | toolbar = self.app.get_toolbar() |
239 | 125 | 119 | ||
241 | 126 | """ Track is playing""" | 120 | # check that the player is playing and then select pause |
242 | 127 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 121 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
243 | 128 | toolbar.click_play_button() | 122 | toolbar.click_play_button() |
244 | 129 | 123 | ||
246 | 130 | """ Track is not playing""" | 124 | # check that the player is paused and then select play |
247 | 131 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 125 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
248 | 132 | |||
249 | 133 | """ Track is playing""" | ||
250 | 134 | toolbar.click_play_button() | 126 | toolbar.click_play_button() |
251 | 127 | |||
252 | 128 | # check that the player is playing | ||
253 | 135 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 129 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
254 | 136 | 130 | ||
255 | 137 | def test_next_previous(self): | 131 | def test_next_previous(self): |
256 | @@ -141,179 +135,177 @@ | |||
257 | 141 | 135 | ||
258 | 142 | toolbar = self.app.get_toolbar() | 136 | toolbar = self.app.get_toolbar() |
259 | 143 | 137 | ||
265 | 144 | title = lambda: self.player.currentMetaTitle | 138 | # save original song data for later |
266 | 145 | artist = lambda: self.player.currentMetaArtist | 139 | org_title = self.player.currentMetaTitle |
267 | 146 | 140 | org_artist = self.player.currentMetaArtist | |
263 | 147 | orgTitle = self.player.currentMetaTitle | ||
264 | 148 | orgArtist = self.player.currentMetaArtist | ||
268 | 149 | 141 | ||
269 | 150 | # check original track | 142 | # check original track |
270 | 151 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 143 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
272 | 152 | logger.debug("Original Song %s, %s" % (orgTitle, orgArtist)) | 144 | logger.debug("Original Song %s, %s" % (org_title, org_artist)) |
273 | 153 | 145 | ||
275 | 154 | """ Pause track """ | 146 | # select pause and check the player has stopped |
276 | 155 | toolbar.click_play_button() | 147 | toolbar.click_play_button() |
277 | 156 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 148 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
278 | 157 | 149 | ||
280 | 158 | toolbar.set_shuffle(False) | 150 | toolbar.set_shuffle(False) # ensure shuffe is off |
281 | 159 | 151 | ||
282 | 160 | """ Select next """ | ||
283 | 161 | # goal is to go back and forth and ensure 2 different songs | 152 | # goal is to go back and forth and ensure 2 different songs |
284 | 162 | toolbar.click_forward_button() | 153 | toolbar.click_forward_button() |
285 | 163 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 154 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
286 | 164 | 155 | ||
288 | 165 | """ Pause track """ | 156 | # select pause and check the player has stopped |
289 | 166 | toolbar.click_play_button() | 157 | toolbar.click_play_button() |
290 | 167 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 158 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
291 | 168 | 159 | ||
292 | 169 | # ensure different song | 160 | # ensure different song |
298 | 170 | self.assertThat(title, Eventually(NotEquals(orgTitle))) | 161 | self.assertThat(self.player.currentMetaTitle, |
299 | 171 | self.assertThat(artist, Eventually(NotEquals(orgArtist))) | 162 | Eventually(NotEquals(org_title))) |
300 | 172 | nextTitle = self.player.currentMetaTitle | 163 | self.assertThat(self.player.currentMetaArtist, |
301 | 173 | nextArtist = self.player.currentMetaArtist | 164 | Eventually(NotEquals(org_artist))) |
302 | 174 | logger.debug("Next Song %s, %s" % (nextTitle, nextArtist)) | 165 | |
303 | 166 | logger.debug("Next Song %s, %s" % (self.player.currentMetaTitle, | ||
304 | 167 | self.player.currentMetaArtist)) | ||
305 | 175 | 168 | ||
306 | 176 | toolbar.seek_to(0) # seek to 0 (start) | 169 | toolbar.seek_to(0) # seek to 0 (start) |
307 | 177 | 170 | ||
309 | 178 | """ Select previous """ | 171 | # select previous and ensure the track is playing |
310 | 179 | toolbar.click_previous_button() | 172 | toolbar.click_previous_button() |
311 | 180 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 173 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
312 | 181 | 174 | ||
314 | 182 | """ Pause track """ | 175 | # select pause and check the player has stopped |
315 | 183 | toolbar.click_play_button() | 176 | toolbar.click_play_button() |
316 | 184 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 177 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
317 | 185 | 178 | ||
318 | 186 | # ensure we're back to original song | 179 | # ensure we're back to original song |
321 | 187 | self.assertThat(title, Eventually(Equals(orgTitle))) | 180 | self.assertThat(self.player.currentMetaTitle, |
322 | 188 | self.assertThat(artist, Eventually(Equals(orgArtist))) | 181 | Eventually(Equals(org_title))) |
323 | 182 | self.assertThat(self.player.currentMetaArtist, | ||
324 | 183 | Eventually(Equals(org_artist))) | ||
325 | 189 | 184 | ||
326 | 190 | def test_mp3(self): | 185 | def test_mp3(self): |
327 | 191 | """ Test that mp3 "plays" or at least doesn't crash on load """ | 186 | """ Test that mp3 "plays" or at least doesn't crash on load """ |
328 | 192 | 187 | ||
329 | 193 | self.app.populate_queue() # populate queue | ||
330 | 194 | |||
331 | 195 | now_playing_page = self.app.get_now_playing_page() | ||
332 | 196 | toolbar = self.app.get_toolbar() | 188 | toolbar = self.app.get_toolbar() |
333 | 197 | 189 | ||
363 | 198 | title = self.player.currentMetaTitle | 190 | # Get list of tracks which are mp3 and then take the index of the first |
364 | 199 | artist = self.player.currentMetaArtist | 191 | i = [i for i, track in enumerate(self.tracks) |
365 | 200 | 192 | if track["source"].endswith("mp3")][0] | |
366 | 201 | toolbar.set_shuffle(False) | 193 | |
367 | 202 | 194 | # switch to tracks page | |
368 | 203 | # ensure track appears before looping through queue more than once | 195 | tracks_page = self.app.get_tracks_page() |
369 | 204 | # needs to contain test mp3 metadata and end in *.mp3 | 196 | |
370 | 205 | queue_size = now_playing_page.get_count() | 197 | # get track row and swipe to reveal actions |
371 | 206 | count = 0 | 198 | track = tracks_page.get_track(i) |
372 | 207 | 199 | track.swipe_reveal_actions() | |
373 | 208 | while title != "TestMP3Title" and artist != "TestMP3Artist": | 200 | |
374 | 209 | count = count + 1 | 201 | track.click_add_to_queue_action() # add track to queue |
375 | 210 | 202 | ||
376 | 211 | self.assertThat(count, LessThan(queue_size)) | 203 | # wait for the player index to change |
377 | 212 | 204 | self.player.currentIndex.wait_for(0) | |
378 | 213 | """ Select next """ | 205 | |
379 | 214 | toolbar.click_forward_button() | 206 | # Ensure the current track is mp3 |
351 | 215 | |||
352 | 216 | """ Pause track """ | ||
353 | 217 | toolbar.click_play_button() | ||
354 | 218 | self.assertThat(self.player.isPlaying, | ||
355 | 219 | Eventually(Equals(False))) | ||
356 | 220 | |||
357 | 221 | title = self.player.currentMetaTitle | ||
358 | 222 | artist = self.player.currentMetaArtist | ||
359 | 223 | logger.debug("Current Song %s, %s" % (title, artist)) | ||
360 | 224 | logger.debug("File found %s" % self.player.currentMetaFile) | ||
361 | 225 | |||
362 | 226 | # make sure mp3 plays | ||
380 | 227 | self.assertThat(self.player.source.endswith("mp3"), | 207 | self.assertThat(self.player.source.endswith("mp3"), |
381 | 228 | Equals(True)) | 208 | Equals(True)) |
382 | 209 | |||
383 | 210 | # Start playing the track | ||
384 | 229 | toolbar.click_play_button() | 211 | toolbar.click_play_button() |
385 | 212 | |||
386 | 213 | # Check that the track is playing | ||
387 | 230 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 214 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
388 | 231 | 215 | ||
389 | 216 | # Stop playing the track | ||
390 | 217 | toolbar.click_play_button() | ||
391 | 218 | |||
392 | 219 | # Check current meta data is correct | ||
393 | 220 | self.assertThat(self.player.currentMetaTitle, | ||
394 | 221 | Eventually(Equals(self.tracks[i]["title"]))) | ||
395 | 222 | self.assertThat(self.player.currentMetaArtist, | ||
396 | 223 | Eventually(Equals(self.tracks[i]["artist"]))) | ||
397 | 224 | |||
398 | 232 | def test_shuffle(self): | 225 | def test_shuffle(self): |
399 | 233 | """ Test shuffle (Music Library must exist) """ | 226 | """ Test shuffle (Music Library must exist) """ |
400 | 234 | 227 | ||
401 | 235 | self.app.populate_queue() # populate queue | 228 | self.app.populate_queue() # populate queue |
402 | 236 | 229 | ||
404 | 237 | """ Track is playing, shuffle is turned on""" | 230 | # at this point the track is playing and shuffle is enabled |
405 | 231 | |||
406 | 238 | toolbar = self.app.get_toolbar() | 232 | toolbar = self.app.get_toolbar() |
407 | 239 | 233 | ||
411 | 240 | # play for a second, then pause | 234 | # pause the track if it is playing |
412 | 241 | if not self.player.isPlaying: | 235 | if self.player.isPlaying: |
410 | 242 | logger.debug("Play not selected") | ||
413 | 243 | toolbar.click_play_button() | 236 | toolbar.click_play_button() |
421 | 244 | else: | 237 | |
422 | 245 | logger.debug("Already playing") | 238 | self.player.isPlaying.wait_for(False) |
423 | 246 | 239 | ||
424 | 247 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 240 | toolbar.set_shuffle(True) # enable shuffle |
425 | 248 | time.sleep(1) | 241 | |
426 | 249 | toolbar.click_play_button() | 242 | # save original song metadata |
427 | 250 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | 243 | org_title = self.player.currentMetaTitle |
428 | 244 | org_artist = self.player.currentMetaArtist | ||
429 | 245 | |||
430 | 246 | logger.debug("Original Song %s, %s" % (org_title, org_artist)) | ||
431 | 251 | 247 | ||
432 | 252 | count = 0 | 248 | count = 0 |
434 | 253 | while True: | 249 | |
435 | 250 | # loop while the track is the same if different then a shuffle occurred | ||
436 | 251 | while (org_title == self.player.currentMetaTitle and | ||
437 | 252 | org_artist == self.player.currentMetaArtist): | ||
438 | 253 | logger.debug("count %s" % (count)) | ||
439 | 254 | |||
440 | 255 | # check count is valid | ||
441 | 254 | self.assertThat(count, LessThan(100)) | 256 | self.assertThat(count, LessThan(100)) |
442 | 255 | 257 | ||
457 | 256 | # goal is to hit next under shuffle mode | 258 | # select next track |
444 | 257 | # then verify original track is not the previous track | ||
445 | 258 | # this means a true shuffle happened | ||
446 | 259 | # if it doesn't try again, up to count times | ||
447 | 260 | |||
448 | 261 | orgTitle = self.player.currentMetaTitle | ||
449 | 262 | orgArtist = self.player.currentMetaArtist | ||
450 | 263 | logger.debug("Original Song %s, %s" % (orgTitle, orgArtist)) | ||
451 | 264 | |||
452 | 265 | if not toolbar.opened: | ||
453 | 266 | toolbar.show() | ||
454 | 267 | |||
455 | 268 | toolbar.set_shuffle(True) | ||
456 | 269 | |||
458 | 270 | toolbar.click_forward_button() | 259 | toolbar.click_forward_button() |
475 | 271 | self.assertThat(self.player.isPlaying, | 260 | |
476 | 272 | Eventually(Equals(True))) | 261 | # pause the track if it is playing |
477 | 273 | 262 | if self.player.isPlaying: | |
478 | 274 | title = self.player.currentMetaTitle | 263 | toolbar.click_play_button() |
479 | 275 | artist = self.player.currentMetaArtist | 264 | |
480 | 276 | logger.debug("Current Song %s, %s" % (title, artist)) | 265 | # check it is paused |
481 | 277 | 266 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) | |
482 | 278 | # go back to previous and check against original | 267 | |
483 | 279 | # play song, then pause before switching | 268 | # save current file so we can check it goes back |
484 | 280 | time.sleep(1) | 269 | source = self.player.currentMetaFile |
485 | 281 | toolbar.click_play_button() | 270 | |
486 | 282 | self.assertThat(self.player.isPlaying, | 271 | # select previous track while will break if this previous track |
487 | 283 | Eventually(Equals(False))) | 272 | # is different and therefore a shuffle has occurred |
472 | 284 | |||
473 | 285 | toolbar.set_shuffle(False) | ||
474 | 286 | |||
488 | 287 | toolbar.click_previous_button() | 273 | toolbar.click_previous_button() |
489 | 288 | 274 | ||
501 | 289 | title = self.player.currentMetaTitle | 275 | # pause the track if it is playing |
502 | 290 | artist = self.player.currentMetaArtist | 276 | if self.player.isPlaying: |
503 | 291 | 277 | toolbar.click_play_button() | |
504 | 292 | if title != orgTitle and artist != orgArtist: | 278 | |
505 | 293 | # we shuffled properly | 279 | # check it is paused |
506 | 294 | logger.debug("Yay, shuffled %s, %s" % (title, artist)) | 280 | self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
507 | 295 | break | 281 | |
508 | 296 | else: | 282 | # check the file has actually changed |
509 | 297 | logger.debug("Same track, no shuffle %s, %s" % (title, artist)) | 283 | self.assertThat(self.player.currentMetaFile, |
510 | 298 | 284 | Eventually(NotEquals(source))) | |
511 | 299 | count += 1 | 285 | |
512 | 286 | count += 1 # increment count | ||
513 | 300 | 287 | ||
514 | 301 | def test_show_albums_page(self): | 288 | def test_show_albums_page(self): |
515 | 302 | """tests navigating to the Albums tab and displaying the album page""" | 289 | """tests navigating to the Albums tab and displaying the album page""" |
516 | 303 | 290 | ||
517 | 304 | # switch to albums tab | 291 | # switch to albums tab |
518 | 305 | albums_page = self.app.get_albums_page() | 292 | albums_page = self.app.get_albums_page() |
520 | 306 | albums_page.click_album(self.album_index) # select album | 293 | albums_page.click_album(0) # select album |
521 | 307 | 294 | ||
522 | 308 | # get songs page album artist | 295 | # get songs page album artist |
523 | 309 | songs_page = self.app.get_songs_page() | 296 | songs_page = self.app.get_songs_page() |
524 | 310 | artist_label = songs_page.get_header_artist_label() | 297 | artist_label = songs_page.get_header_artist_label() |
525 | 311 | 298 | ||
526 | 299 | # build list of tracks sorted by album | ||
527 | 300 | tracks = self.tracks[:] | ||
528 | 301 | tracks.sort(key=lambda track: track["album"]) | ||
529 | 302 | |||
530 | 303 | # check that the first is the same as | ||
531 | 312 | self.assertThat(artist_label.text, | 304 | self.assertThat(artist_label.text, |
533 | 313 | Eventually(Equals(self.artist_name))) | 305 | Eventually(Equals(tracks[0]["artist"]))) |
534 | 314 | 306 | ||
535 | 315 | # click on close button to close songs page | 307 | # click on close button to close songs page |
537 | 316 | self.main_view.go_back() | 308 | self.app.main_view.go_back() |
538 | 317 | 309 | ||
539 | 318 | # check that the albums page is now visible | 310 | # check that the albums page is now visible |
540 | 319 | self.assertThat(albums_page.visible, Eventually(Equals(True))) | 311 | self.assertThat(albums_page.visible, Eventually(Equals(True))) |
541 | @@ -328,7 +320,11 @@ | |||
542 | 328 | 320 | ||
543 | 329 | # switch to albums tab | 321 | # switch to albums tab |
544 | 330 | albums_page = self.app.get_albums_page() | 322 | albums_page = self.app.get_albums_page() |
546 | 331 | albums_page.click_album(self.album_index) # select album | 323 | albums_page.click_album(0) # select album |
547 | 324 | |||
548 | 325 | # build list of tracks sorted by album | ||
549 | 326 | tracks = self.tracks[:] | ||
550 | 327 | tracks.sort(key=lambda track: track["album"]) | ||
551 | 332 | 328 | ||
552 | 333 | # get track item to swipe and queue | 329 | # get track item to swipe and queue |
553 | 334 | songs_page = self.app.get_songs_page() | 330 | songs_page = self.app.get_songs_page() |
554 | @@ -349,12 +345,12 @@ | |||
555 | 349 | current_track = now_playing_page.get_track(self.player.currentIndex) | 345 | current_track = now_playing_page.get_track(self.player.currentIndex) |
556 | 350 | 346 | ||
557 | 351 | self.assertThat(current_track.get_label_text("artistLabel"), | 347 | self.assertThat(current_track.get_label_text("artistLabel"), |
559 | 352 | Equals(self.artist_name)) | 348 | Equals(tracks[0]["artist"])) |
560 | 353 | self.assertThat(current_track.get_label_text("titleLabel"), | 349 | self.assertThat(current_track.get_label_text("titleLabel"), |
562 | 354 | Equals(self.track_title)) | 350 | Equals(tracks[0]["title"])) |
563 | 355 | 351 | ||
564 | 356 | # click on close button to close songs page | 352 | # click on close button to close songs page |
566 | 357 | self.main_view.go_back() | 353 | self.app.main_view.go_back() |
567 | 358 | 354 | ||
568 | 359 | # check that the albums page is now visible | 355 | # check that the albums page is now visible |
569 | 360 | self.assertThat(albums_page.visible, Eventually(Equals(True))) | 356 | self.assertThat(albums_page.visible, Eventually(Equals(True))) |
570 | @@ -386,9 +382,9 @@ | |||
571 | 386 | current_track = now_playing_page.get_track(self.player.currentIndex) | 382 | current_track = now_playing_page.get_track(self.player.currentIndex) |
572 | 387 | 383 | ||
573 | 388 | self.assertThat(current_track.get_label_text("artistLabel"), | 384 | self.assertThat(current_track.get_label_text("artistLabel"), |
575 | 389 | Equals(self.artist_name)) | 385 | Equals(self.tracks[0]["artist"])) |
576 | 390 | self.assertThat(current_track.get_label_text("titleLabel"), | 386 | self.assertThat(current_track.get_label_text("titleLabel"), |
578 | 391 | Equals(self.track_title)) | 387 | Equals(self.tracks[0]["title"])) |
579 | 392 | 388 | ||
580 | 393 | def test_add_song_to_queue_from_songs_tab(self): | 389 | def test_add_song_to_queue_from_songs_tab(self): |
581 | 394 | """tests navigating to the Songs tab and adding a song from the library | 390 | """tests navigating to the Songs tab and adding a song from the library |
582 | @@ -403,7 +399,7 @@ | |||
583 | 403 | tracks_page = self.app.get_tracks_page() | 399 | tracks_page = self.app.get_tracks_page() |
584 | 404 | 400 | ||
585 | 405 | # get track row and swipe to reveal actions | 401 | # get track row and swipe to reveal actions |
587 | 406 | track = tracks_page.get_track(self.track_index) | 402 | track = tracks_page.get_track(0) |
588 | 407 | track.swipe_reveal_actions() | 403 | track.swipe_reveal_actions() |
589 | 408 | 404 | ||
590 | 409 | track.click_add_to_queue_action() # add track to queue | 405 | track.click_add_to_queue_action() # add track to queue |
591 | @@ -421,9 +417,9 @@ | |||
592 | 421 | current_track = now_playing_page.get_track(self.player.currentIndex) | 417 | current_track = now_playing_page.get_track(self.player.currentIndex) |
593 | 422 | 418 | ||
594 | 423 | self.assertThat(current_track.get_label_text("artistLabel"), | 419 | self.assertThat(current_track.get_label_text("artistLabel"), |
596 | 424 | Equals(self.artist_name)) | 420 | Equals(self.tracks[0]["artist"])) |
597 | 425 | self.assertThat(current_track.get_label_text("titleLabel"), | 421 | self.assertThat(current_track.get_label_text("titleLabel"), |
599 | 426 | Equals(self.track_title)) | 422 | Equals(self.tracks[0]["title"])) |
600 | 427 | 423 | ||
601 | 428 | def test_create_playlist_from_songs_tab(self): | 424 | def test_create_playlist_from_songs_tab(self): |
602 | 429 | """tests navigating to the Songs tab and creating a playlist by | 425 | """tests navigating to the Songs tab and creating a playlist by |
603 | @@ -433,7 +429,7 @@ | |||
604 | 433 | tracks_page = self.app.get_tracks_page() | 429 | tracks_page = self.app.get_tracks_page() |
605 | 434 | 430 | ||
606 | 435 | # get track row and swipe to reveal actions | 431 | # get track row and swipe to reveal actions |
608 | 436 | track = tracks_page.get_track(self.track_index) | 432 | track = tracks_page.get_track(0) |
609 | 437 | track.swipe_reveal_actions() | 433 | track.swipe_reveal_actions() |
610 | 438 | 434 | ||
611 | 439 | track.click_add_to_playlist_action() # add track to queue | 435 | track.click_add_to_playlist_action() # add track to queue |
612 | @@ -484,26 +480,30 @@ | |||
613 | 484 | 480 | ||
614 | 485 | # switch to artists tab | 481 | # switch to artists tab |
615 | 486 | artists_page = self.app.get_artists_page() | 482 | artists_page = self.app.get_artists_page() |
617 | 487 | artists_page.click_artist(self.artist_index) | 483 | artists_page.click_artist(0) |
618 | 484 | |||
619 | 485 | # build list of tracks sorted by artist | ||
620 | 486 | tracks = self.tracks[:] | ||
621 | 487 | tracks.sort(key=lambda track: track["artist"]) | ||
622 | 488 | 488 | ||
623 | 489 | # get albums (by an artist) page | 489 | # get albums (by an artist) page |
624 | 490 | albums_page = self.app.get_albums_artist_page() | 490 | albums_page = self.app.get_albums_artist_page() |
625 | 491 | 491 | ||
626 | 492 | # check album artist label is correct | 492 | # check album artist label is correct |
628 | 493 | self.assertThat(albums_page.get_artist(), Equals(self.artist_name)) | 493 | self.assertThat(albums_page.get_artist(), Equals(tracks[0]["artist"])) |
629 | 494 | 494 | ||
630 | 495 | # click on album to show tracks | 495 | # click on album to show tracks |
632 | 496 | albums_page.click_artist(self.album_artist_index) | 496 | albums_page.click_artist(0) |
633 | 497 | 497 | ||
634 | 498 | # get song page album artist | 498 | # get song page album artist |
635 | 499 | songs_page = self.app.get_songs_page() | 499 | songs_page = self.app.get_songs_page() |
636 | 500 | 500 | ||
637 | 501 | # check the artist label | 501 | # check the artist label |
638 | 502 | artist_label = songs_page.get_header_artist_label() | 502 | artist_label = songs_page.get_header_artist_label() |
640 | 503 | self.assertThat(artist_label.text, Equals(self.artist_name)) | 503 | self.assertThat(artist_label.text, Equals(tracks[0]["artist"])) |
641 | 504 | 504 | ||
642 | 505 | # click on track to play | 505 | # click on track to play |
644 | 506 | songs_page.click_track(self.track_index) | 506 | songs_page.click_track(0) |
645 | 507 | 507 | ||
646 | 508 | # get now playing again as it has moved | 508 | # get now playing again as it has moved |
647 | 509 | now_playing_page = self.app.get_now_playing_page() | 509 | now_playing_page = self.app.get_now_playing_page() |
648 | @@ -521,9 +521,9 @@ | |||
649 | 521 | current_track = now_playing_page.get_track(self.player.currentIndex) | 521 | current_track = now_playing_page.get_track(self.player.currentIndex) |
650 | 522 | 522 | ||
651 | 523 | self.assertThat(current_track.get_label_text("artistLabel"), | 523 | self.assertThat(current_track.get_label_text("artistLabel"), |
653 | 524 | Equals(self.artist_name)) | 524 | Equals(tracks[0]["artist"])) |
654 | 525 | self.assertThat(current_track.get_label_text("titleLabel"), | 525 | self.assertThat(current_track.get_label_text("titleLabel"), |
656 | 526 | Equals(self.track_title)) | 526 | Equals(tracks[0]["title"])) |
657 | 527 | 527 | ||
658 | 528 | def test_swipe_to_delete_song(self): | 528 | def test_swipe_to_delete_song(self): |
659 | 529 | """tests navigating to the Now Playing queue, swiping to delete a | 529 | """tests navigating to the Now Playing queue, swiping to delete a |
660 | @@ -537,7 +537,7 @@ | |||
661 | 537 | initial_queue_count = now_playing_page.get_count() | 537 | initial_queue_count = now_playing_page.get_count() |
662 | 538 | 538 | ||
663 | 539 | # get track row and swipe to reveal swipe to delete | 539 | # get track row and swipe to reveal swipe to delete |
665 | 540 | track = now_playing_page.get_track(self.track_index) | 540 | track = now_playing_page.get_track(0) |
666 | 541 | track.swipe_to_delete() | 541 | track.swipe_to_delete() |
667 | 542 | 542 | ||
668 | 543 | track.confirm_removal() # confirm delete | 543 | track.confirm_removal() # confirm delete |
669 | @@ -580,8 +580,8 @@ | |||
670 | 580 | toolbar.click_forward_button() | 580 | toolbar.click_forward_button() |
671 | 581 | 581 | ||
672 | 582 | # Make sure we loop back to first song after last song ends | 582 | # Make sure we loop back to first song after last song ends |
675 | 583 | actual_title = lambda: self.player.currentMetaTitle | 583 | self.assertThat(self.player.currentMetaTitle, |
676 | 584 | self.assertThat(actual_title, Eventually(Equals(self.track_title))) | 584 | Eventually(Equals(self.tracks[0]["title"]))) |
677 | 585 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 585 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
678 | 586 | 586 | ||
679 | 587 | def test_pressing_next_from_last_song_plays_first_when_repeat_on(self): | 587 | def test_pressing_next_from_last_song_plays_first_when_repeat_on(self): |
680 | @@ -599,8 +599,9 @@ | |||
681 | 599 | for count in range(0, now_playing_page.get_count() - 1): | 599 | for count in range(0, now_playing_page.get_count() - 1): |
682 | 600 | toolbar.click_forward_button() | 600 | toolbar.click_forward_button() |
683 | 601 | 601 | ||
686 | 602 | actual_title = lambda: self.player.currentMetaTitle | 602 | # Make sure we loop back to first song after last song ends |
687 | 603 | self.assertThat(actual_title, Eventually(Equals(self.track_title))) | 603 | self.assertThat(self.player.currentMetaTitle, |
688 | 604 | Eventually(Equals(self.tracks[0]["title"]))) | ||
689 | 604 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 605 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
690 | 605 | 606 | ||
691 | 606 | def test_pressing_prev_from_first_song_plays_last_when_repeat_on(self): | 607 | def test_pressing_prev_from_first_song_plays_last_when_repeat_on(self): |
692 | @@ -622,7 +623,6 @@ | |||
693 | 622 | if self.player.currentMetaTitle == initial_song: | 623 | if self.player.currentMetaTitle == initial_song: |
694 | 623 | toolbar.click_previous_button() | 624 | toolbar.click_previous_button() |
695 | 624 | 625 | ||
699 | 625 | actual_title = lambda: self.player.currentMetaTitle | 626 | self.assertThat(self.player.currentMetaTitle, |
700 | 626 | self.assertThat(actual_title, | 627 | Eventually(Equals(self.tracks[-1]["title"]))) |
698 | 627 | Eventually(Equals(self.last_track_title))) | ||
701 | 628 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) | 628 | self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
FAILED: Continuous integration, rev:609 91.189. 93.70:8080/ job/music- app-ci/ 1090/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic/ 1844/console 91.189. 93.70:8080/ job/music- app-utopic- amd64-ci/ 314/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-ci/ 1090/rebuild
http://