You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
8.2 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package autofile
  2. import (
  3. "io"
  4. "os"
  5. "path/filepath"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. "github.com/tendermint/tendermint/libs/log"
  10. tmos "github.com/tendermint/tendermint/libs/os"
  11. tmrand "github.com/tendermint/tendermint/libs/rand"
  12. )
  13. func createTestGroupWithHeadSizeLimit(t *testing.T, logger log.Logger, headSizeLimit int64) *Group {
  14. testID := tmrand.Str(12)
  15. testDir := "_test_" + testID
  16. err := tmos.EnsureDir(testDir, 0700)
  17. require.NoError(t, err, "Error creating dir")
  18. headPath := testDir + "/myfile"
  19. g, err := OpenGroup(logger, headPath, GroupHeadSizeLimit(headSizeLimit))
  20. require.NoError(t, err, "Error opening Group")
  21. require.NotEqual(t, nil, g, "Failed to create Group")
  22. return g
  23. }
  24. func destroyTestGroup(t *testing.T, g *Group) {
  25. g.Close()
  26. err := os.RemoveAll(g.Dir)
  27. require.NoError(t, err, "Error removing test Group directory")
  28. }
  29. func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) {
  30. assert.Equal(t, minIndex, gInfo.MinIndex)
  31. assert.Equal(t, maxIndex, gInfo.MaxIndex)
  32. assert.Equal(t, totalSize, gInfo.TotalSize)
  33. assert.Equal(t, headSize, gInfo.HeadSize)
  34. }
  35. func TestCheckHeadSizeLimit(t *testing.T) {
  36. logger := log.TestingLogger()
  37. g := createTestGroupWithHeadSizeLimit(t, logger, 1000*1000)
  38. // At first, there are no files.
  39. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0)
  40. // Write 1000 bytes 999 times.
  41. for i := 0; i < 999; i++ {
  42. err := g.WriteLine(tmrand.Str(999))
  43. require.NoError(t, err, "Error appending to head")
  44. }
  45. err := g.FlushAndSync()
  46. require.NoError(t, err)
  47. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
  48. // Even calling checkHeadSizeLimit manually won't rotate it.
  49. g.checkHeadSizeLimit()
  50. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
  51. // Write 1000 more bytes.
  52. err = g.WriteLine(tmrand.Str(999))
  53. require.NoError(t, err, "Error appending to head")
  54. err = g.FlushAndSync()
  55. require.NoError(t, err)
  56. // Calling checkHeadSizeLimit this time rolls it.
  57. g.checkHeadSizeLimit()
  58. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0)
  59. // Write 1000 more bytes.
  60. err = g.WriteLine(tmrand.Str(999))
  61. require.NoError(t, err, "Error appending to head")
  62. err = g.FlushAndSync()
  63. require.NoError(t, err)
  64. // Calling checkHeadSizeLimit does nothing.
  65. g.checkHeadSizeLimit()
  66. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
  67. // Write 1000 bytes 999 times.
  68. for i := 0; i < 999; i++ {
  69. err = g.WriteLine(tmrand.Str(999))
  70. require.NoError(t, err, "Error appending to head")
  71. }
  72. err = g.FlushAndSync()
  73. require.NoError(t, err)
  74. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
  75. // Calling checkHeadSizeLimit rolls it again.
  76. g.checkHeadSizeLimit()
  77. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
  78. // Write 1000 more bytes.
  79. _, err = g.Head.Write([]byte(tmrand.Str(999) + "\n"))
  80. require.NoError(t, err, "Error appending to head")
  81. err = g.FlushAndSync()
  82. require.NoError(t, err)
  83. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
  84. // Calling checkHeadSizeLimit does nothing.
  85. g.checkHeadSizeLimit()
  86. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
  87. // Cleanup
  88. destroyTestGroup(t, g)
  89. }
  90. func TestRotateFile(t *testing.T) {
  91. logger := log.TestingLogger()
  92. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  93. // Create a different temporary directory and move into it, to make sure
  94. // relative paths are resolved at Group creation
  95. origDir, err := os.Getwd()
  96. require.NoError(t, err)
  97. defer func() {
  98. if err := os.Chdir(origDir); err != nil {
  99. t.Error(err)
  100. }
  101. }()
  102. dir, err := os.MkdirTemp("", "rotate_test")
  103. require.NoError(t, err)
  104. defer os.RemoveAll(dir)
  105. err = os.Chdir(dir)
  106. require.NoError(t, err)
  107. require.True(t, filepath.IsAbs(g.Head.Path))
  108. require.True(t, filepath.IsAbs(g.Dir))
  109. // Create and rotate files
  110. err = g.WriteLine("Line 1")
  111. require.NoError(t, err)
  112. err = g.WriteLine("Line 2")
  113. require.NoError(t, err)
  114. err = g.WriteLine("Line 3")
  115. require.NoError(t, err)
  116. err = g.FlushAndSync()
  117. require.NoError(t, err)
  118. g.RotateFile()
  119. err = g.WriteLine("Line 4")
  120. require.NoError(t, err)
  121. err = g.WriteLine("Line 5")
  122. require.NoError(t, err)
  123. err = g.WriteLine("Line 6")
  124. require.NoError(t, err)
  125. err = g.FlushAndSync()
  126. require.NoError(t, err)
  127. // Read g.Head.Path+"000"
  128. body1, err := os.ReadFile(g.Head.Path + ".000")
  129. assert.NoError(t, err, "Failed to read first rolled file")
  130. if string(body1) != "Line 1\nLine 2\nLine 3\n" {
  131. t.Errorf("got unexpected contents: [%v]", string(body1))
  132. }
  133. // Read g.Head.Path
  134. body2, err := os.ReadFile(g.Head.Path)
  135. assert.NoError(t, err, "Failed to read first rolled file")
  136. if string(body2) != "Line 4\nLine 5\nLine 6\n" {
  137. t.Errorf("got unexpected contents: [%v]", string(body2))
  138. }
  139. // Make sure there are no files in the current, temporary directory
  140. files, err := os.ReadDir(".")
  141. require.NoError(t, err)
  142. assert.Empty(t, files)
  143. // Cleanup
  144. destroyTestGroup(t, g)
  145. }
  146. func TestWrite(t *testing.T) {
  147. logger := log.TestingLogger()
  148. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  149. written := []byte("Medusa")
  150. _, err := g.Write(written)
  151. require.NoError(t, err)
  152. err = g.FlushAndSync()
  153. require.NoError(t, err)
  154. read := make([]byte, len(written))
  155. gr, err := g.NewReader(0)
  156. require.NoError(t, err, "failed to create reader")
  157. _, err = gr.Read(read)
  158. assert.NoError(t, err, "failed to read data")
  159. assert.Equal(t, written, read)
  160. // Cleanup
  161. destroyTestGroup(t, g)
  162. }
  163. // test that Read reads the required amount of bytes from all the files in the
  164. // group and returns no error if n == size of the given slice.
  165. func TestGroupReaderRead(t *testing.T) {
  166. logger := log.TestingLogger()
  167. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  168. professor := []byte("Professor Monster")
  169. _, err := g.Write(professor)
  170. require.NoError(t, err)
  171. err = g.FlushAndSync()
  172. require.NoError(t, err)
  173. g.RotateFile()
  174. frankenstein := []byte("Frankenstein's Monster")
  175. _, err = g.Write(frankenstein)
  176. require.NoError(t, err)
  177. err = g.FlushAndSync()
  178. require.NoError(t, err)
  179. totalWrittenLength := len(professor) + len(frankenstein)
  180. read := make([]byte, totalWrittenLength)
  181. gr, err := g.NewReader(0)
  182. require.NoError(t, err, "failed to create reader")
  183. n, err := gr.Read(read)
  184. assert.NoError(t, err, "failed to read data")
  185. assert.Equal(t, totalWrittenLength, n, "not enough bytes read")
  186. professorPlusFrankenstein := professor
  187. professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...)
  188. assert.Equal(t, professorPlusFrankenstein, read)
  189. // Cleanup
  190. destroyTestGroup(t, g)
  191. }
  192. // test that Read returns an error if number of bytes read < size of
  193. // the given slice. Subsequent call should return 0, io.EOF.
  194. func TestGroupReaderRead2(t *testing.T) {
  195. logger := log.TestingLogger()
  196. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  197. professor := []byte("Professor Monster")
  198. _, err := g.Write(professor)
  199. require.NoError(t, err)
  200. err = g.FlushAndSync()
  201. require.NoError(t, err)
  202. g.RotateFile()
  203. frankenstein := []byte("Frankenstein's Monster")
  204. frankensteinPart := []byte("Frankenstein")
  205. _, err = g.Write(frankensteinPart) // note writing only a part
  206. require.NoError(t, err)
  207. err = g.FlushAndSync()
  208. require.NoError(t, err)
  209. totalLength := len(professor) + len(frankenstein)
  210. read := make([]byte, totalLength)
  211. gr, err := g.NewReader(0)
  212. require.NoError(t, err, "failed to create reader")
  213. // 1) n < (size of the given slice), io.EOF
  214. n, err := gr.Read(read)
  215. assert.Equal(t, io.EOF, err)
  216. assert.Equal(t, len(professor)+len(frankensteinPart), n, "Read more/less bytes than it is in the group")
  217. // 2) 0, io.EOF
  218. n, err = gr.Read([]byte("0"))
  219. assert.Equal(t, io.EOF, err)
  220. assert.Equal(t, 0, n)
  221. // Cleanup
  222. destroyTestGroup(t, g)
  223. }
  224. func TestMinIndex(t *testing.T) {
  225. logger := log.TestingLogger()
  226. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  227. assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning")
  228. // Cleanup
  229. destroyTestGroup(t, g)
  230. }
  231. func TestMaxIndex(t *testing.T) {
  232. logger := log.TestingLogger()
  233. g := createTestGroupWithHeadSizeLimit(t, logger, 0)
  234. assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning")
  235. err := g.WriteLine("Line 1")
  236. require.NoError(t, err)
  237. err = g.FlushAndSync()
  238. require.NoError(t, err)
  239. g.RotateFile()
  240. assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file")
  241. // Cleanup
  242. destroyTestGroup(t, g)
  243. }