DownloaderConnectionTest.kt 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /**
  2. * Nextcloud Android client application
  3. *
  4. * @author Chris Narkiewicz
  5. * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.client.files.downloader
  21. import android.content.ComponentName
  22. import android.content.Context
  23. import com.nextcloud.client.account.MockUser
  24. import com.owncloud.android.datamodel.OCFile
  25. import io.mockk.MockKAnnotations
  26. import io.mockk.every
  27. import io.mockk.impl.annotations.MockK
  28. import io.mockk.mockk
  29. import io.mockk.verify
  30. import org.junit.Assert.assertEquals
  31. import org.junit.Assert.assertFalse
  32. import org.junit.Assert.assertTrue
  33. import org.junit.Before
  34. import org.junit.Test
  35. class DownloaderConnectionTest {
  36. lateinit var connection: DownloaderConnection
  37. @MockK
  38. lateinit var context: Context
  39. @MockK
  40. lateinit var firstDownloadListener: (Download) -> Unit
  41. @MockK
  42. lateinit var secondDownloadListener: (Download) -> Unit
  43. @MockK
  44. lateinit var firstStatusListener: (Downloader.Status) -> Unit
  45. @MockK
  46. lateinit var secondStatusListener: (Downloader.Status) -> Unit
  47. @MockK
  48. lateinit var binder: DownloaderService.Binder
  49. val file get() = OCFile("/path")
  50. val componentName = ComponentName("", DownloaderService::class.java.simpleName)
  51. val user = MockUser()
  52. @Before
  53. fun setUp() {
  54. MockKAnnotations.init(this, relaxed = true)
  55. connection = DownloaderConnection(context, user)
  56. }
  57. @Test
  58. fun listeners_are_set_after_connection() {
  59. // GIVEN
  60. // not connected
  61. // listener is added
  62. connection.registerDownloadListener(firstDownloadListener)
  63. connection.registerDownloadListener(secondDownloadListener)
  64. // WHEN
  65. // service is bound
  66. connection.onServiceConnected(componentName, binder)
  67. // THEN
  68. // all listeners are passed to the service
  69. val listeners = mutableListOf<(Download) -> Unit>()
  70. verify { binder.registerDownloadListener(capture(listeners)) }
  71. assertEquals(listOf(firstDownloadListener, secondDownloadListener), listeners)
  72. }
  73. @Test
  74. fun listeners_are_set_immediately_when_connected() {
  75. // GIVEN
  76. // service is bound
  77. connection.onServiceConnected(componentName, binder)
  78. // WHEN
  79. // listeners are added
  80. connection.registerDownloadListener(firstDownloadListener)
  81. // THEN
  82. // listener is forwarded to service
  83. verify { binder.registerDownloadListener(firstDownloadListener) }
  84. }
  85. @Test
  86. fun listeners_are_removed_when_unbinding() {
  87. // GIVEN
  88. // service is bound
  89. // service has some listeners
  90. connection.onServiceConnected(componentName, binder)
  91. connection.registerDownloadListener(firstDownloadListener)
  92. connection.registerDownloadListener(secondDownloadListener)
  93. // WHEN
  94. // service unbound
  95. connection.unbind()
  96. // THEN
  97. // listeners removed from service
  98. verify { binder.removeDownloadListener(firstDownloadListener) }
  99. verify { binder.removeDownloadListener(secondDownloadListener) }
  100. }
  101. @Test
  102. fun missed_updates_are_delivered_on_connection() {
  103. // GIVEN
  104. // not bound
  105. // has listeners
  106. // download is scheduled and is progressing
  107. connection.registerDownloadListener(firstDownloadListener)
  108. connection.registerDownloadListener(secondDownloadListener)
  109. val request1 = Request(user, file)
  110. connection.download(request1)
  111. val download1 = Download(request1.uuid, DownloadState.RUNNING, 50, request1.file, request1)
  112. val request2 = Request(user, file)
  113. connection.download(request2)
  114. val download2 = Download(request2.uuid, DownloadState.RUNNING, 50, request2.file, request1)
  115. every { binder.getDownload(request1.uuid) } returns download1
  116. every { binder.getDownload(request2.uuid) } returns download2
  117. // WHEN
  118. // service is bound
  119. connection.onServiceConnected(componentName, binder)
  120. // THEN
  121. // listeners receive current download state for pending downloads
  122. val firstListenerNotifications = mutableListOf<Download>()
  123. verify { firstDownloadListener(capture(firstListenerNotifications)) }
  124. assertEquals(listOf(download1, download2), firstListenerNotifications)
  125. val secondListenerNotifications = mutableListOf<Download>()
  126. verify { secondDownloadListener(capture(secondListenerNotifications)) }
  127. assertEquals(listOf(download1, download2), secondListenerNotifications)
  128. }
  129. @Test
  130. fun downloader_status_updates_are_delivered_on_connection() {
  131. // GIVEN
  132. // not bound
  133. // has status listeners
  134. val mockStatus: Downloader.Status = mockk()
  135. every { binder.status } returns mockStatus
  136. connection.registerStatusListener(firstStatusListener)
  137. connection.registerStatusListener(secondStatusListener)
  138. // WHEN
  139. // service is bound
  140. connection.onServiceConnected(componentName, binder)
  141. // THEN
  142. // downloader status is delivered
  143. verify { firstStatusListener(mockStatus) }
  144. verify { secondStatusListener(mockStatus) }
  145. }
  146. @Test
  147. fun downloader_status_not_requested_if_no_listeners() {
  148. // GIVEN
  149. // not bound
  150. // no status listeners
  151. // WHEN
  152. // service is bound
  153. connection.onServiceConnected(componentName, binder)
  154. // THEN
  155. // downloader status is not requested
  156. verify(exactly = 0) { binder.status }
  157. }
  158. @Test
  159. fun not_running_if_not_connected() {
  160. // GIVEN
  161. // downloader is running
  162. // connection not bound
  163. every { binder.isRunning } returns true
  164. // THEN
  165. // not running
  166. assertFalse(connection.isRunning)
  167. }
  168. @Test
  169. fun is_running_from_binder_if_connected() {
  170. // GIVEN
  171. // service bound
  172. every { binder.isRunning } returns true
  173. connection.onServiceConnected(componentName, binder)
  174. // WHEN
  175. // is runnign flag accessed
  176. val isRunning = connection.isRunning
  177. // THEN
  178. // call delegated to binder
  179. assertTrue(isRunning)
  180. verify(exactly = 1) { binder.isRunning }
  181. }
  182. @Test
  183. fun missed_updates_not_tracked_before_listeners_registered() {
  184. // GIVEN
  185. // not bound
  186. // some downloads requested without listener
  187. val request = Request(user, file)
  188. connection.download(request)
  189. val download = Download(request.uuid, DownloadState.RUNNING, 50, request.file, request)
  190. connection.registerDownloadListener(firstDownloadListener)
  191. every { binder.getDownload(request.uuid) } returns download
  192. // WHEN
  193. // service is bound
  194. connection.onServiceConnected(componentName, binder)
  195. // THEN
  196. // missed updates not redelivered
  197. verify(exactly = 0) { firstDownloadListener(any()) }
  198. }
  199. }