LogsViewModelTest.kt 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Chris Narkiewicz
  5. * Copyright (C) 2019 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.logger.ui
  21. import android.content.Context
  22. import androidx.arch.core.executor.testing.InstantTaskExecutorRule
  23. import com.nextcloud.client.core.Clock
  24. import com.nextcloud.client.core.ManualAsyncRunner
  25. import com.nextcloud.client.logger.Level
  26. import com.nextcloud.client.logger.LogEntry
  27. import com.nextcloud.client.logger.LogsRepository
  28. import com.nextcloud.client.logger.OnLogsLoaded
  29. import org.junit.Assert.assertEquals
  30. import org.junit.Assert.assertFalse
  31. import org.junit.Assert.assertNotNull
  32. import org.junit.Assert.assertNull
  33. import org.junit.Assert.assertSame
  34. import org.junit.Assert.assertTrue
  35. import org.junit.Before
  36. import org.junit.Rule
  37. import org.junit.Test
  38. import org.junit.runner.RunWith
  39. import org.junit.runners.Suite
  40. import org.mockito.MockitoAnnotations
  41. import org.mockito.kotlin.any
  42. import org.mockito.kotlin.mock
  43. import org.mockito.kotlin.whenever
  44. import java.util.Date
  45. @RunWith(Suite::class)
  46. @Suite.SuiteClasses(
  47. LogsViewModelTest.Loading::class,
  48. LogsViewModelTest.Filtering::class
  49. )
  50. class LogsViewModelTest {
  51. private companion object {
  52. val TEST_LOG_ENTRIES = listOf(
  53. LogEntry(Date(), Level.DEBUG, "test", "entry 1"),
  54. LogEntry(Date(), Level.DEBUG, "test", "entry 2"),
  55. LogEntry(Date(), Level.DEBUG, "test", "entry 3")
  56. )
  57. val TEST_LOG_SIZE_KILOBYTES = 42L
  58. val TEST_LOG_SIZE_BYTES = TEST_LOG_SIZE_KILOBYTES * 1024L
  59. const val TOTAL_ENTRY_COUNT = 3
  60. const val QUERY_TIME = 4
  61. }
  62. class TestLogRepository : LogsRepository {
  63. var loadRequestCount = 0
  64. var onLoadedCallback: OnLogsLoaded? = null
  65. override val lostEntries: Boolean = false
  66. override fun load(onLoaded: OnLogsLoaded) { this.onLoadedCallback = onLoaded; loadRequestCount++ }
  67. override fun deleteAll() { /* no implementation neeeded */
  68. }
  69. }
  70. abstract class Fixture {
  71. protected lateinit var context: Context
  72. protected lateinit var clock: Clock
  73. protected lateinit var repository: TestLogRepository
  74. protected lateinit var runner: ManualAsyncRunner
  75. protected lateinit var vm: LogsViewModel
  76. @get:Rule
  77. val rule = InstantTaskExecutorRule()
  78. @Before
  79. fun setUpFixture() {
  80. MockitoAnnotations.initMocks(this)
  81. context = mock()
  82. clock = mock()
  83. repository = TestLogRepository()
  84. runner = ManualAsyncRunner()
  85. vm = LogsViewModel(context, clock, runner, repository)
  86. whenever(context.getString(any(), any())).thenAnswer {
  87. "${it.arguments}"
  88. }
  89. }
  90. }
  91. class Loading : Fixture() {
  92. @Test
  93. fun `all observable properties have initial values`() {
  94. assertNotNull(vm.isLoading)
  95. assertNotNull(vm.size)
  96. assertNotNull(vm.entries)
  97. assertNotNull(vm.status)
  98. }
  99. @Test
  100. fun `load logs entries from repository`() {
  101. // GIVEN
  102. // entries are not loaded
  103. assertEquals(0, vm.entries.value!!.size)
  104. assertEquals(false, vm.isLoading.value)
  105. // WHEN
  106. // load is initiated
  107. vm.load()
  108. // THEN
  109. // loading status is true
  110. // repository request is posted
  111. assertTrue(vm.isLoading.value!!)
  112. assertNotNull(repository.onLoadedCallback)
  113. }
  114. @Test
  115. fun `on logs loaded`() {
  116. // GIVEN
  117. // logs are being loaded
  118. vm.load()
  119. assertNotNull(repository.onLoadedCallback)
  120. assertTrue(vm.isLoading.value!!)
  121. // WHEN
  122. // logs loading finishes
  123. repository.onLoadedCallback?.invoke(TEST_LOG_ENTRIES, TEST_LOG_SIZE_BYTES)
  124. // THEN
  125. // logs are displayed
  126. // logs size is displyed
  127. // status is displayed
  128. assertFalse(vm.isLoading.value!!)
  129. assertSame(vm.entries.value, TEST_LOG_ENTRIES)
  130. assertNotNull(vm.status.value)
  131. }
  132. @Test
  133. fun `cannot start loading when loading is in progress`() {
  134. // GIVEN
  135. // logs loading is started
  136. vm.load()
  137. assertEquals(1, repository.loadRequestCount)
  138. assertTrue(vm.isLoading.value!!)
  139. // WHEN
  140. // load is requested
  141. repository.onLoadedCallback = null
  142. vm.load()
  143. // THEN
  144. // request is ignored
  145. assertNull(repository.onLoadedCallback)
  146. assertEquals(1, repository.loadRequestCount)
  147. }
  148. }
  149. class Filtering : Fixture() {
  150. @Before
  151. fun setUp() {
  152. vm.load()
  153. repository.onLoadedCallback?.invoke(TEST_LOG_ENTRIES, TEST_LOG_SIZE_BYTES)
  154. assertFalse(vm.isLoading.value!!)
  155. assertEquals(TEST_LOG_ENTRIES.size, vm.entries.value?.size)
  156. }
  157. @Test
  158. fun `filtering cannot be started when loading`() {
  159. // GIVEN
  160. // loading is in progress
  161. vm.load()
  162. assertTrue(vm.isLoading.value!!)
  163. // WHEN
  164. // filtering is requested
  165. vm.filter("some pattern")
  166. // THEN
  167. // filtering is not enqueued
  168. assertTrue(runner.isEmpty)
  169. }
  170. @Test
  171. fun `filtering task is started`() {
  172. // GIVEN
  173. // logs are loaded
  174. assertEquals(TEST_LOG_ENTRIES.size, vm.entries.value?.size)
  175. // WHEN
  176. // logs filtering is not running
  177. // logs filtering is requested
  178. assertTrue(runner.isEmpty)
  179. vm.filter(TEST_LOG_ENTRIES[0].message)
  180. // THEN
  181. // filter request is enqueued
  182. assertEquals(1, runner.size)
  183. }
  184. @Test
  185. fun `filtered logs are displayed`() {
  186. var statusArgs: Array<Any> = emptyArray()
  187. whenever(context.getString(any(), any())).thenAnswer {
  188. statusArgs = it.arguments
  189. "${it.arguments}"
  190. }
  191. // GIVEN
  192. // filtering is in progress
  193. val pattern = TEST_LOG_ENTRIES[0].message
  194. vm.filter(pattern)
  195. // WHEN
  196. // filtering finishes
  197. assertEquals(1, runner.runAll())
  198. // THEN
  199. // vm displays filtered results
  200. // vm displays status
  201. assertNotNull(vm.entries.value)
  202. assertEquals(1, vm.entries.value?.size)
  203. val filteredEntry = vm.entries.value?.get(0)!!
  204. assertTrue(filteredEntry.message.contains(pattern))
  205. assertEquals("Status should contain size in kB", TEST_LOG_SIZE_KILOBYTES, statusArgs[1])
  206. assertEquals("Status should show matched entries count", vm.entries.value?.size, statusArgs[2])
  207. assertEquals(
  208. "Status should contain total entries count",
  209. TEST_LOG_ENTRIES.size,
  210. statusArgs[TOTAL_ENTRY_COUNT]
  211. )
  212. assertTrue("Status should contain query time in ms", statusArgs[QUERY_TIME] is Long)
  213. }
  214. }
  215. }