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.

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