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.

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