FileLogHandlerTest.kt 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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
  21. import org.junit.Assert.assertEquals
  22. import org.junit.Assert.assertFalse
  23. import org.junit.Assert.assertTrue
  24. import org.junit.Before
  25. import org.junit.Test
  26. import java.io.File
  27. import java.nio.charset.Charset
  28. import java.nio.file.Files
  29. class FileLogHandlerTest {
  30. private lateinit var logDir: File
  31. private fun readLogFile(name: String): String {
  32. val logFile = File(logDir, name)
  33. val raw = Files.readAllBytes(logFile.toPath())
  34. return String(raw, Charset.forName("UTF-8"))
  35. }
  36. /**
  37. * Write raw content to file in log dir.
  38. *
  39. * @return size of written data in bytes
  40. */
  41. private fun writeLogFile(name: String, content: String): Int {
  42. val logFile = File(logDir, name)
  43. val rawContent = content.toByteArray(Charsets.UTF_8)
  44. Files.write(logFile.toPath(), rawContent)
  45. return rawContent.size
  46. }
  47. @Before
  48. fun setUp() {
  49. logDir = Files.createTempDirectory("logger-test-").toFile()
  50. }
  51. @Test
  52. fun `logs dir is created on open`() {
  53. // GIVEN
  54. // logs directory does not exist
  55. val nonexistingLogsDir = File(logDir, "subdir")
  56. assertFalse(nonexistingLogsDir.exists())
  57. // WHEN
  58. // file is opened
  59. val handler = FileLogHandler(nonexistingLogsDir, "log.txt", 1000)
  60. handler.open()
  61. // THEN
  62. // directory is created
  63. assertTrue(nonexistingLogsDir.exists())
  64. }
  65. @Test
  66. fun `log test helpers`() {
  67. val filename = "test.txt"
  68. val expected = "Hello, world!"
  69. writeLogFile(filename, expected)
  70. val readBack = readLogFile(filename)
  71. assertEquals(expected, readBack)
  72. }
  73. @Test
  74. fun `rotate files`() {
  75. // GIVEN
  76. // log contains files
  77. writeLogFile("log.txt", "0")
  78. writeLogFile("log.txt.0", "1")
  79. writeLogFile("log.txt.1", "2")
  80. writeLogFile("log.txt.2", "3")
  81. val writer = FileLogHandler(logDir, "log.txt", 1024)
  82. // WHEN
  83. // files are rotated
  84. writer.rotateLogs()
  85. // THEN
  86. // last file is removed
  87. // all remaining files are advanced by 1 step
  88. assertFalse(File(logDir, "log.txt").exists())
  89. assertEquals("0", readLogFile("log.txt.0"))
  90. assertEquals("1", readLogFile("log.txt.1"))
  91. assertEquals("2", readLogFile("log.txt.2"))
  92. }
  93. @Test
  94. fun `log file is rotated when crossed max size`() {
  95. // GIVEN
  96. // log file contains 10 bytes
  97. // log file limit is 20 bytes
  98. // log writer is opened
  99. writeLogFile("log.txt", "0123456789")
  100. val writer = FileLogHandler(logDir, "log.txt", 20)
  101. writer.open()
  102. // WHEN
  103. // writing 2nd log entry of 11 bytes
  104. writer.write("0123456789!") // 11 bytes
  105. // THEN
  106. // log file is closed and rotated
  107. val rotatedContent = readLogFile("log.txt.0")
  108. assertEquals("01234567890123456789!", rotatedContent)
  109. }
  110. @Test
  111. fun `log file is reopened after rotation`() {
  112. // GIVEN
  113. // log file contains 10 bytes
  114. // log file limit is 20 bytes
  115. // log writer is opened
  116. writeLogFile("log.txt", "0123456789")
  117. val writer = FileLogHandler(logDir, "log.txt", 20)
  118. writer.open()
  119. // WHEN
  120. // writing 2nd log entry of 11 bytes
  121. // writing another log entry
  122. // closing log
  123. writer.write("0123456789!") // 11 bytes
  124. writer.write("Hello!")
  125. writer.close()
  126. // THEN
  127. // current log contains last entry
  128. val lastEntry = readLogFile("log.txt")
  129. assertEquals("Hello!", lastEntry)
  130. }
  131. @Test
  132. fun `load log lines from files`() {
  133. // GIVEN
  134. // multiple log files exist
  135. // log files have lines
  136. var totalLogsSize = 0L
  137. totalLogsSize += writeLogFile("log.txt.2", "line1\nline2\nline3")
  138. totalLogsSize += writeLogFile("log.txt.1", "line4\nline5\nline6")
  139. totalLogsSize += writeLogFile("log.txt.0", "line7\nline8\nline9")
  140. totalLogsSize += writeLogFile("log.txt", "line10\nline11\nline12")
  141. // WHEN
  142. // log file is read including rotated content
  143. val writer = FileLogHandler(logDir, "log.txt", 1000)
  144. val rawLogs = writer.loadLogFiles(3)
  145. // THEN
  146. // all files are loaded
  147. // lines are loaded in correct order
  148. // log files size is correctly reported
  149. assertEquals(12, rawLogs.lines.size)
  150. assertEquals(
  151. listOf(
  152. "line1", "line2", "line3",
  153. "line4", "line5", "line6",
  154. "line7", "line8", "line9",
  155. "line10", "line11", "line12"
  156. ),
  157. rawLogs.lines
  158. )
  159. assertEquals(totalLogsSize, rawLogs.logSize)
  160. }
  161. @Test
  162. fun `load log lines from files with gaps between rotated files`() {
  163. // GIVEN
  164. // multiple log files exist
  165. // log files have lines
  166. // some rotated files are deleted
  167. writeLogFile("log.txt", "line1\nline2\nline3")
  168. writeLogFile("log.txt.2", "line4\nline5\nline6")
  169. // WHEN
  170. // log file is read including rotated content
  171. val writer = FileLogHandler(logDir, "log.txt", 1000)
  172. val lines = writer.loadLogFiles(3)
  173. // THEN
  174. // all files are loaded
  175. // log file size is non-zero
  176. assertEquals(6, lines.lines.size)
  177. assertTrue(lines.logSize > 0)
  178. }
  179. @Test(expected = IllegalArgumentException::class)
  180. fun `load log lines - negative count is illegal`() {
  181. // WHEN
  182. // requesting negative number of rotated files
  183. val writer = FileLogHandler(logDir, "log.txt", 1000)
  184. val lines = writer.loadLogFiles(-1)
  185. // THEN
  186. // illegal argument exception
  187. }
  188. @Test
  189. fun `all log files are deleted`() {
  190. // GIVEN
  191. // log files exist
  192. val handler = FileLogHandler(logDir, "log.txt", 100)
  193. for (i in 0 until handler.maxLogFilesCount) {
  194. handler.rotateLogs()
  195. handler.open()
  196. handler.write("new log entry")
  197. handler.close()
  198. }
  199. assertEquals(handler.maxLogFilesCount, logDir.listFiles().size)
  200. // WHEN
  201. // files are deleted
  202. handler.deleteAll()
  203. // THEN
  204. // all files are deleted
  205. assertEquals(0, logDir.listFiles().size)
  206. }
  207. }