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.

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