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.

427 lines
15 KiB

  1. // Copyright (c) 2015-2021 MinIO, Inc.
  2. //
  3. // This file is part of MinIO Object Storage stack
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Affero General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Affero General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. package cmd
  18. import (
  19. "bytes"
  20. "context"
  21. "io"
  22. "io/ioutil"
  23. "reflect"
  24. "sync"
  25. "testing"
  26. )
  27. var loadMetacacheSampleNames = []string{"src/compress/bzip2/", "src/compress/bzip2/bit_reader.go", "src/compress/bzip2/bzip2.go", "src/compress/bzip2/bzip2_test.go", "src/compress/bzip2/huffman.go", "src/compress/bzip2/move_to_front.go", "src/compress/bzip2/testdata/", "src/compress/bzip2/testdata/Isaac.Newton-Opticks.txt.bz2", "src/compress/bzip2/testdata/e.txt.bz2", "src/compress/bzip2/testdata/fail-issue5747.bz2", "src/compress/bzip2/testdata/pass-random1.bin", "src/compress/bzip2/testdata/pass-random1.bz2", "src/compress/bzip2/testdata/pass-random2.bin", "src/compress/bzip2/testdata/pass-random2.bz2", "src/compress/bzip2/testdata/pass-sawtooth.bz2", "src/compress/bzip2/testdata/random.data.bz2", "src/compress/flate/", "src/compress/flate/deflate.go", "src/compress/flate/deflate_test.go", "src/compress/flate/deflatefast.go", "src/compress/flate/dict_decoder.go", "src/compress/flate/dict_decoder_test.go", "src/compress/flate/example_test.go", "src/compress/flate/flate_test.go", "src/compress/flate/huffman_bit_writer.go", "src/compress/flate/huffman_bit_writer_test.go", "src/compress/flate/huffman_code.go", "src/compress/flate/inflate.go", "src/compress/flate/inflate_test.go", "src/compress/flate/reader_test.go", "src/compress/flate/testdata/", "src/compress/flate/testdata/huffman-null-max.dyn.expect", "src/compress/flate/testdata/huffman-null-max.dyn.expect-noinput", "src/compress/flate/testdata/huffman-null-max.golden", "src/compress/flate/testdata/huffman-null-max.in", "src/compress/flate/testdata/huffman-null-max.wb.expect", "src/compress/flate/testdata/huffman-null-max.wb.expect-noinput", "src/compress/flate/testdata/huffman-pi.dyn.expect", "src/compress/flate/testdata/huffman-pi.dyn.expect-noinput", "src/compress/flate/testdata/huffman-pi.golden", "src/compress/flate/testdata/huffman-pi.in", "src/compress/flate/testdata/huffman-pi.wb.expect", "src/compress/flate/testdata/huffman-pi.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-1k.dyn.expect", "src/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput", "src/compress/flate/testdata/huffman-rand-1k.golden", "src/compress/flate/testdata/huffman-rand-1k.in", "src/compress/flate/testdata/huffman-rand-1k.wb.expect", "src/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-limit.dyn.expect", "src/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput", "src/compress/flate/testdata/huffman-rand-limit.golden", "src/compress/flate/testdata/huffman-rand-limit.in", "src/compress/flate/testdata/huffman-rand-limit.wb.expect", "src/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-max.golden", "src/compress/flate/testdata/huffman-rand-max.in", "src/compress/flate/testdata/huffman-shifts.dyn.expect", "src/compress/flate/testdata/huffman-shifts.dyn.expect-noinput", "src/compress/flate/testdata/huffman-shifts.golden", "src/compress/flate/testdata/huffman-shifts.in", "src/compress/flate/testdata/huffman-shifts.wb.expect", "src/compress/flate/testdata/huffman-shifts.wb.expect-noinput", "src/compress/flate/testdata/huffman-text-shift.dyn.expect", "src/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput", "src/compress/flate/testdata/huffman-text-shift.golden", "src/compress/flate/testdata/huffman-text-shift.in", "src/compress/flate/testdata/huffman-text-shift.wb.expect", "src/compress/flate/testdata/huffman-text-shift.wb.expect-noinput", "src/compress/flate/testdata/huffman-text.dyn.expect", "src/compress/flate/testdata/huffman-text.dyn.expect-noinput", "src/compress/flate/testdata/huffman-text.golden", "src/compress/flate/testdata/huffman-text.in", "src/compress/flate/testdata/huffman-text.wb.expect", "src/compress/flate/testdata/huffman-text.wb.expect-noinput", "src/compress/flate/testdata/huffman-zero.dyn.expect", "src/compress/flate/testdata/huffman-zero.dyn.expect-noinput", "src/compress/flate/testdata/huffman-zero.golden", "src/compress/flate/testdata/huffman-zero.in", "src/compress/flate/testdata/huffman-zero.wb.expect", "src/compress/f
  28. func loadMetacacheSample(t testing.TB) *metacacheReader {
  29. b, err := ioutil.ReadFile("testdata/metacache.s2")
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. return newMetacacheReader(bytes.NewReader(b))
  34. }
  35. func loadMetacacheSampleEntries(t testing.TB) metaCacheEntriesSorted {
  36. r := loadMetacacheSample(t)
  37. defer r.Close()
  38. entries, err := r.readN(-1, false, true, "")
  39. if err != io.EOF {
  40. t.Fatal(err)
  41. }
  42. return entries
  43. }
  44. func Test_metacacheReader_readNames(t *testing.T) {
  45. r := loadMetacacheSample(t)
  46. defer r.Close()
  47. names, err := r.readNames(-1)
  48. if err != io.EOF {
  49. t.Fatal(err)
  50. }
  51. want := loadMetacacheSampleNames
  52. if !reflect.DeepEqual(names, want) {
  53. t.Errorf("got unexpected result: %#v", names)
  54. }
  55. }
  56. func Test_metacacheReader_readN(t *testing.T) {
  57. r := loadMetacacheSample(t)
  58. defer r.Close()
  59. entries, err := r.readN(-1, false, true, "")
  60. if err != io.EOF {
  61. t.Fatal(err, entries.len())
  62. }
  63. want := loadMetacacheSampleNames
  64. for i, entry := range entries.entries() {
  65. if entry.name != want[i] {
  66. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  67. }
  68. }
  69. if entries.len() != len(want) {
  70. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  71. }
  72. want = want[:0]
  73. entries, err = r.readN(0, false, true, "")
  74. if err != nil {
  75. t.Fatal(err, entries.len())
  76. }
  77. if entries.len() != len(want) {
  78. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  79. }
  80. // Reload.
  81. r = loadMetacacheSample(t)
  82. defer r.Close()
  83. entries, err = r.readN(0, false, true, "")
  84. if err != nil {
  85. t.Fatal(err, entries.len())
  86. }
  87. if entries.len() != len(want) {
  88. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  89. }
  90. entries, err = r.readN(5, false, true, "")
  91. if err != nil {
  92. t.Fatal(err, entries.len())
  93. }
  94. want = loadMetacacheSampleNames[:5]
  95. if entries.len() != len(want) {
  96. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  97. }
  98. for i, entry := range entries.entries() {
  99. if entry.name != want[i] {
  100. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  101. }
  102. }
  103. }
  104. func Test_metacacheReader_readNDirs(t *testing.T) {
  105. r := loadMetacacheSample(t)
  106. defer r.Close()
  107. entries, err := r.readN(-1, false, true, "")
  108. if err != io.EOF {
  109. t.Fatal(err, entries.len())
  110. }
  111. want := loadMetacacheSampleNames
  112. var noDirs []string
  113. for i, entry := range entries.entries() {
  114. if entry.name != want[i] {
  115. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  116. }
  117. if !entry.isDir() {
  118. noDirs = append(noDirs, entry.name)
  119. }
  120. }
  121. if entries.len() != len(want) {
  122. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  123. }
  124. want = noDirs
  125. r = loadMetacacheSample(t)
  126. defer r.Close()
  127. entries, err = r.readN(-1, false, false, "")
  128. if err != io.EOF {
  129. t.Fatal(err, entries.len())
  130. }
  131. for i, entry := range entries.entries() {
  132. if entry.name != want[i] {
  133. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  134. }
  135. }
  136. if entries.len() != len(want) {
  137. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  138. }
  139. want = want[:0]
  140. entries, err = r.readN(0, false, false, "")
  141. if err != nil {
  142. t.Fatal(err, entries.len())
  143. }
  144. if entries.len() != len(want) {
  145. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  146. }
  147. // Reload.
  148. r = loadMetacacheSample(t)
  149. defer r.Close()
  150. entries, err = r.readN(0, false, false, "")
  151. if err != nil {
  152. t.Fatal(err, entries.len())
  153. }
  154. if entries.len() != len(want) {
  155. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  156. }
  157. entries, err = r.readN(5, false, false, "")
  158. if err != nil {
  159. t.Fatal(err, entries.len())
  160. }
  161. want = noDirs[:5]
  162. if entries.len() != len(want) {
  163. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  164. }
  165. for i, entry := range entries.entries() {
  166. if entry.name != want[i] {
  167. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  168. }
  169. }
  170. }
  171. func Test_metacacheReader_readNPrefix(t *testing.T) {
  172. r := loadMetacacheSample(t)
  173. defer r.Close()
  174. entries, err := r.readN(-1, false, true, "src/compress/bzip2/")
  175. if err != io.EOF {
  176. t.Fatal(err, entries.len())
  177. }
  178. want := loadMetacacheSampleNames[:16]
  179. for i, entry := range entries.entries() {
  180. if entry.name != want[i] {
  181. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  182. }
  183. }
  184. if entries.len() != len(want) {
  185. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  186. }
  187. r = loadMetacacheSample(t)
  188. defer r.Close()
  189. entries, err = r.readN(-1, false, true, "src/nonexist")
  190. if err != io.EOF {
  191. t.Fatal(err, entries.len())
  192. }
  193. want = loadMetacacheSampleNames[:0]
  194. if entries.len() != len(want) {
  195. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  196. }
  197. for i, entry := range entries.entries() {
  198. if entry.name != want[i] {
  199. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  200. }
  201. }
  202. r = loadMetacacheSample(t)
  203. defer r.Close()
  204. entries, err = r.readN(-1, false, true, "src/a")
  205. if err != io.EOF {
  206. t.Fatal(err, entries.len())
  207. }
  208. want = loadMetacacheSampleNames[:0]
  209. if entries.len() != len(want) {
  210. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  211. }
  212. for i, entry := range entries.entries() {
  213. if entry.name != want[i] {
  214. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  215. }
  216. }
  217. r = loadMetacacheSample(t)
  218. defer r.Close()
  219. entries, err = r.readN(-1, false, true, "src/compress/zlib/e")
  220. if err != io.EOF {
  221. t.Fatal(err, entries.len())
  222. }
  223. want = []string{"src/compress/zlib/example_test.go"}
  224. if entries.len() != len(want) {
  225. t.Fatal("unexpected length:", entries.len(), "want:", len(want))
  226. }
  227. for i, entry := range entries.entries() {
  228. if entry.name != want[i] {
  229. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  230. }
  231. }
  232. }
  233. func Test_metacacheReader_readFn(t *testing.T) {
  234. r := loadMetacacheSample(t)
  235. defer r.Close()
  236. i := 0
  237. err := r.readFn(func(entry metaCacheEntry) bool {
  238. want := loadMetacacheSampleNames[i]
  239. if entry.name != want {
  240. t.Errorf("entry %d, want %q, got %q", i, want, entry.name)
  241. }
  242. i++
  243. return true
  244. })
  245. if err != io.EOF {
  246. t.Fatal(err)
  247. }
  248. }
  249. func Test_metacacheReader_readAll(t *testing.T) {
  250. r := loadMetacacheSample(t)
  251. defer r.Close()
  252. var readErr error
  253. objs := make(chan metaCacheEntry, 1)
  254. var wg sync.WaitGroup
  255. wg.Add(1)
  256. go func() {
  257. readErr = r.readAll(context.Background(), objs)
  258. wg.Done()
  259. }()
  260. want := loadMetacacheSampleNames
  261. i := 0
  262. for entry := range objs {
  263. if entry.name != want[i] {
  264. t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name)
  265. }
  266. i++
  267. }
  268. wg.Wait()
  269. if readErr != nil {
  270. t.Fatal(readErr)
  271. }
  272. }
  273. func Test_metacacheReader_forwardTo(t *testing.T) {
  274. r := loadMetacacheSample(t)
  275. defer r.Close()
  276. err := r.forwardTo("src/compress/zlib/reader_test.go")
  277. if err != nil {
  278. t.Fatal(err)
  279. }
  280. names, err := r.readNames(-1)
  281. if err != io.EOF {
  282. t.Fatal(err)
  283. }
  284. want := []string{"src/compress/zlib/reader_test.go", "src/compress/zlib/writer.go", "src/compress/zlib/writer_test.go"}
  285. if !reflect.DeepEqual(names, want) {
  286. t.Errorf("got unexpected result: %#v", names)
  287. }
  288. // Try with prefix
  289. r = loadMetacacheSample(t)
  290. err = r.forwardTo("src/compress/zlib/reader_t")
  291. if err != nil {
  292. t.Fatal(err)
  293. }
  294. names, err = r.readNames(-1)
  295. if err != io.EOF {
  296. t.Fatal(err)
  297. }
  298. if !reflect.DeepEqual(names, want) {
  299. t.Errorf("got unexpected result: %#v", names)
  300. }
  301. }
  302. func Test_metacacheReader_next(t *testing.T) {
  303. r := loadMetacacheSample(t)
  304. defer r.Close()
  305. for i, want := range loadMetacacheSampleNames {
  306. gotObj, err := r.next()
  307. if err != nil {
  308. t.Fatal(err)
  309. }
  310. if gotObj.name != want {
  311. t.Errorf("entry %d, want %q, got %q", i, want, gotObj.name)
  312. }
  313. }
  314. }
  315. func Test_metacacheReader_peek(t *testing.T) {
  316. r := loadMetacacheSample(t)
  317. defer r.Close()
  318. for i, want := range loadMetacacheSampleNames {
  319. got, err := r.peek()
  320. if err == io.EOF {
  321. break
  322. }
  323. if err != nil {
  324. t.Fatal(err)
  325. }
  326. if got.name != want {
  327. t.Errorf("entry %d, want %q, got %q", i, want, got.name)
  328. }
  329. gotObj, err := r.next()
  330. if err != nil {
  331. t.Fatal(err)
  332. }
  333. if gotObj.name != want {
  334. t.Errorf("entry %d, want %q, got %q", i, want, gotObj.name)
  335. }
  336. }
  337. }
  338. func Test_newMetacacheStream(t *testing.T) {
  339. r := loadMetacacheSample(t)
  340. var buf bytes.Buffer
  341. w := newMetacacheWriter(&buf, 1<<20)
  342. defer w.Close()
  343. err := r.readFn(func(object metaCacheEntry) bool {
  344. err := w.write(object)
  345. if err != nil {
  346. t.Fatal(err)
  347. }
  348. return true
  349. })
  350. r.Close()
  351. if err != io.EOF {
  352. t.Fatal(err)
  353. }
  354. err = w.Close()
  355. if err != nil {
  356. t.Fatal(err)
  357. }
  358. r = newMetacacheReader(&buf)
  359. defer r.Close()
  360. names, err := r.readNames(-1)
  361. if err != io.EOF {
  362. t.Fatal(err)
  363. }
  364. want := loadMetacacheSampleNames
  365. if !reflect.DeepEqual(names, want) {
  366. t.Errorf("got unexpected result: %#v", names)
  367. }
  368. }
  369. func Test_metacacheReader_skip(t *testing.T) {
  370. r := loadMetacacheSample(t)
  371. defer r.Close()
  372. names, err := r.readNames(5)
  373. if err != nil {
  374. t.Fatal(err)
  375. }
  376. want := loadMetacacheSampleNames[:5]
  377. if !reflect.DeepEqual(names, want) {
  378. t.Errorf("got unexpected result: %#v", names)
  379. }
  380. err = r.skip(5)
  381. if err != nil {
  382. t.Fatal(err)
  383. }
  384. names, err = r.readNames(5)
  385. if err != nil {
  386. t.Fatal(err)
  387. }
  388. want = loadMetacacheSampleNames[10:15]
  389. if !reflect.DeepEqual(names, want) {
  390. t.Errorf("got unexpected result: %#v", names)
  391. }
  392. err = r.skip(len(loadMetacacheSampleNames))
  393. if err != io.EOF {
  394. t.Fatal(err)
  395. }
  396. }