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.

405 lines
8.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
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. "errors"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. . "github.com/tendermint/tmlibs/common"
  11. )
  12. // NOTE: Returned group has ticker stopped
  13. func createTestGroup(t *testing.T, headSizeLimit int64) *Group {
  14. testID := RandStr(12)
  15. testDir := "_test_" + testID
  16. err := EnsureDir(testDir, 0700)
  17. if err != nil {
  18. t.Fatal("Error creating dir", err)
  19. }
  20. headPath := testDir + "/myfile"
  21. g, err := OpenGroup(headPath)
  22. if err != nil {
  23. t.Fatal("Error opening Group", err)
  24. }
  25. g.SetHeadSizeLimit(headSizeLimit)
  26. g.stopTicker()
  27. if g == nil {
  28. t.Fatal("Failed to create Group")
  29. }
  30. return g
  31. }
  32. func destroyTestGroup(t *testing.T, g *Group) {
  33. err := os.RemoveAll(g.Dir)
  34. if err != nil {
  35. t.Fatal("Error removing test Group directory", err)
  36. }
  37. }
  38. func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) {
  39. if gInfo.MinIndex != minIndex {
  40. t.Errorf("GroupInfo MinIndex expected %v, got %v", minIndex, gInfo.MinIndex)
  41. }
  42. if gInfo.MaxIndex != maxIndex {
  43. t.Errorf("GroupInfo MaxIndex expected %v, got %v", maxIndex, gInfo.MaxIndex)
  44. }
  45. if gInfo.TotalSize != totalSize {
  46. t.Errorf("GroupInfo TotalSize expected %v, got %v", totalSize, gInfo.TotalSize)
  47. }
  48. if gInfo.HeadSize != headSize {
  49. t.Errorf("GroupInfo HeadSize expected %v, got %v", headSize, gInfo.HeadSize)
  50. }
  51. }
  52. func TestCheckHeadSizeLimit(t *testing.T) {
  53. g := createTestGroup(t, 1000*1000)
  54. // At first, there are no files.
  55. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0)
  56. // Write 1000 bytes 999 times.
  57. for i := 0; i < 999; i++ {
  58. err := g.WriteLine(RandStr(999))
  59. if err != nil {
  60. t.Fatal("Error appending to head", err)
  61. }
  62. }
  63. g.Flush()
  64. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
  65. // Even calling checkHeadSizeLimit manually won't rotate it.
  66. g.checkHeadSizeLimit()
  67. assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
  68. // Write 1000 more bytes.
  69. err := g.WriteLine(RandStr(999))
  70. if err != nil {
  71. t.Fatal("Error appending to head", err)
  72. }
  73. g.Flush()
  74. // Calling checkHeadSizeLimit this time rolls it.
  75. g.checkHeadSizeLimit()
  76. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0)
  77. // Write 1000 more bytes.
  78. err = g.WriteLine(RandStr(999))
  79. if err != nil {
  80. t.Fatal("Error appending to head", err)
  81. }
  82. g.Flush()
  83. // Calling checkHeadSizeLimit does nothing.
  84. g.checkHeadSizeLimit()
  85. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
  86. // Write 1000 bytes 999 times.
  87. for i := 0; i < 999; i++ {
  88. err := g.WriteLine(RandStr(999))
  89. if err != nil {
  90. t.Fatal("Error appending to head", err)
  91. }
  92. }
  93. g.Flush()
  94. assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
  95. // Calling checkHeadSizeLimit rolls it again.
  96. g.checkHeadSizeLimit()
  97. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
  98. // Write 1000 more bytes.
  99. _, err = g.Head.Write([]byte(RandStr(999) + "\n"))
  100. if err != nil {
  101. t.Fatal("Error appending to head", err)
  102. }
  103. g.Flush()
  104. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
  105. // Calling checkHeadSizeLimit does nothing.
  106. g.checkHeadSizeLimit()
  107. assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
  108. // Cleanup
  109. destroyTestGroup(t, g)
  110. }
  111. func TestSearch(t *testing.T) {
  112. g := createTestGroup(t, 10*1000)
  113. // Create some files in the group that have several INFO lines in them.
  114. // Try to put the INFO lines in various spots.
  115. for i := 0; i < 100; i++ {
  116. // The random junk at the end ensures that this INFO linen
  117. // is equally likely to show up at the end.
  118. _, err := g.Head.Write([]byte(Fmt("INFO %v %v\n", i, RandStr(123))))
  119. if err != nil {
  120. t.Error("Failed to write to head")
  121. }
  122. g.checkHeadSizeLimit()
  123. for j := 0; j < 10; j++ {
  124. _, err := g.Head.Write([]byte(RandStr(123) + "\n"))
  125. if err != nil {
  126. t.Error("Failed to write to head")
  127. }
  128. g.checkHeadSizeLimit()
  129. }
  130. }
  131. // Create a search func that searches for line
  132. makeSearchFunc := func(target int) SearchFunc {
  133. return func(line string) (int, error) {
  134. parts := strings.Split(line, " ")
  135. if len(parts) != 3 {
  136. return -1, errors.New("Line did not have 3 parts")
  137. }
  138. i, err := strconv.Atoi(parts[1])
  139. if err != nil {
  140. return -1, errors.New("Failed to parse INFO: " + err.Error())
  141. }
  142. if target < i {
  143. return 1, nil
  144. } else if target == i {
  145. return 0, nil
  146. } else {
  147. return -1, nil
  148. }
  149. }
  150. }
  151. // Now search for each number
  152. for i := 0; i < 100; i++ {
  153. t.Log("Testing for i", i)
  154. gr, match, err := g.Search("INFO", makeSearchFunc(i))
  155. if err != nil {
  156. t.Fatal("Failed to search for line:", err)
  157. }
  158. if !match {
  159. t.Error("Expected Search to return exact match")
  160. }
  161. line, err := gr.ReadLine()
  162. if err != nil {
  163. t.Fatal("Failed to read line after search", err)
  164. }
  165. if !strings.HasPrefix(line, Fmt("INFO %v ", i)) {
  166. t.Fatal("Failed to get correct line")
  167. }
  168. // Make sure we can continue to read from there.
  169. cur := i + 1
  170. for {
  171. line, err := gr.ReadLine()
  172. if err == io.EOF {
  173. if cur == 99+1 {
  174. // OK!
  175. break
  176. } else {
  177. t.Fatal("Got EOF after the wrong INFO #")
  178. }
  179. } else if err != nil {
  180. t.Fatal("Error reading line", err)
  181. }
  182. if !strings.HasPrefix(line, "INFO ") {
  183. continue
  184. }
  185. if !strings.HasPrefix(line, Fmt("INFO %v ", cur)) {
  186. t.Fatalf("Unexpected INFO #. Expected %v got:\n%v", cur, line)
  187. }
  188. cur += 1
  189. }
  190. gr.Close()
  191. }
  192. // Now search for something that is too small.
  193. // We should get the first available line.
  194. {
  195. gr, match, err := g.Search("INFO", makeSearchFunc(-999))
  196. if err != nil {
  197. t.Fatal("Failed to search for line:", err)
  198. }
  199. if match {
  200. t.Error("Expected Search to not return exact match")
  201. }
  202. line, err := gr.ReadLine()
  203. if err != nil {
  204. t.Fatal("Failed to read line after search", err)
  205. }
  206. if !strings.HasPrefix(line, "INFO 0 ") {
  207. t.Error("Failed to fetch correct line, which is the earliest INFO")
  208. }
  209. err = gr.Close()
  210. if err != nil {
  211. t.Error("Failed to close GroupReader", err)
  212. }
  213. }
  214. // Now search for something that is too large.
  215. // We should get an EOF error.
  216. {
  217. gr, _, err := g.Search("INFO", makeSearchFunc(999))
  218. if err != io.EOF {
  219. t.Error("Expected to get an EOF error")
  220. }
  221. if gr != nil {
  222. t.Error("Expected to get nil GroupReader")
  223. }
  224. }
  225. // Cleanup
  226. destroyTestGroup(t, g)
  227. }
  228. func TestRotateFile(t *testing.T) {
  229. g := createTestGroup(t, 0)
  230. g.WriteLine("Line 1")
  231. g.WriteLine("Line 2")
  232. g.WriteLine("Line 3")
  233. g.Flush()
  234. g.RotateFile()
  235. g.WriteLine("Line 4")
  236. g.WriteLine("Line 5")
  237. g.WriteLine("Line 6")
  238. g.Flush()
  239. // Read g.Head.Path+"000"
  240. body1, err := ioutil.ReadFile(g.Head.Path + ".000")
  241. if err != nil {
  242. t.Error("Failed to read first rolled file")
  243. }
  244. if string(body1) != "Line 1\nLine 2\nLine 3\n" {
  245. t.Errorf("Got unexpected contents: [%v]", string(body1))
  246. }
  247. // Read g.Head.Path
  248. body2, err := ioutil.ReadFile(g.Head.Path)
  249. if err != nil {
  250. t.Error("Failed to read first rolled file")
  251. }
  252. if string(body2) != "Line 4\nLine 5\nLine 6\n" {
  253. t.Errorf("Got unexpected contents: [%v]", string(body2))
  254. }
  255. // Cleanup
  256. destroyTestGroup(t, g)
  257. }
  258. func TestFindLast1(t *testing.T) {
  259. g := createTestGroup(t, 0)
  260. g.WriteLine("Line 1")
  261. g.WriteLine("Line 2")
  262. g.WriteLine("# a")
  263. g.WriteLine("Line 3")
  264. g.Flush()
  265. g.RotateFile()
  266. g.WriteLine("Line 4")
  267. g.WriteLine("Line 5")
  268. g.WriteLine("Line 6")
  269. g.WriteLine("# b")
  270. g.Flush()
  271. match, found, err := g.FindLast("#")
  272. if err != nil {
  273. t.Error("Unexpected error", err)
  274. }
  275. if !found {
  276. t.Error("Expected found=True")
  277. }
  278. if match != "# b" {
  279. t.Errorf("Unexpected match: [%v]", match)
  280. }
  281. // Cleanup
  282. destroyTestGroup(t, g)
  283. }
  284. func TestFindLast2(t *testing.T) {
  285. g := createTestGroup(t, 0)
  286. g.WriteLine("Line 1")
  287. g.WriteLine("Line 2")
  288. g.WriteLine("Line 3")
  289. g.Flush()
  290. g.RotateFile()
  291. g.WriteLine("# a")
  292. g.WriteLine("Line 4")
  293. g.WriteLine("Line 5")
  294. g.WriteLine("# b")
  295. g.WriteLine("Line 6")
  296. g.Flush()
  297. match, found, err := g.FindLast("#")
  298. if err != nil {
  299. t.Error("Unexpected error", err)
  300. }
  301. if !found {
  302. t.Error("Expected found=True")
  303. }
  304. if match != "# b" {
  305. t.Errorf("Unexpected match: [%v]", match)
  306. }
  307. // Cleanup
  308. destroyTestGroup(t, g)
  309. }
  310. func TestFindLast3(t *testing.T) {
  311. g := createTestGroup(t, 0)
  312. g.WriteLine("Line 1")
  313. g.WriteLine("# a")
  314. g.WriteLine("Line 2")
  315. g.WriteLine("# b")
  316. g.WriteLine("Line 3")
  317. g.Flush()
  318. g.RotateFile()
  319. g.WriteLine("Line 4")
  320. g.WriteLine("Line 5")
  321. g.WriteLine("Line 6")
  322. g.Flush()
  323. match, found, err := g.FindLast("#")
  324. if err != nil {
  325. t.Error("Unexpected error", err)
  326. }
  327. if !found {
  328. t.Error("Expected found=True")
  329. }
  330. if match != "# b" {
  331. t.Errorf("Unexpected match: [%v]", match)
  332. }
  333. // Cleanup
  334. destroyTestGroup(t, g)
  335. }
  336. func TestFindLast4(t *testing.T) {
  337. g := createTestGroup(t, 0)
  338. g.WriteLine("Line 1")
  339. g.WriteLine("Line 2")
  340. g.WriteLine("Line 3")
  341. g.Flush()
  342. g.RotateFile()
  343. g.WriteLine("Line 4")
  344. g.WriteLine("Line 5")
  345. g.WriteLine("Line 6")
  346. g.Flush()
  347. match, found, err := g.FindLast("#")
  348. if err != nil {
  349. t.Error("Unexpected error", err)
  350. }
  351. if found {
  352. t.Error("Expected found=False")
  353. }
  354. if match != "" {
  355. t.Errorf("Unexpected match: [%v]", match)
  356. }
  357. // Cleanup
  358. destroyTestGroup(t, g)
  359. }