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.

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