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.
 
 
 

297 lines
7.2 KiB

  1. // Copyright 2015 Google LLC
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gensupport
  5. import (
  6. "bytes"
  7. "io"
  8. "io/ioutil"
  9. "reflect"
  10. "testing"
  11. "testing/iotest"
  12. "google.golang.org/api/googleapi"
  13. )
  14. // getChunkAsString reads a chunk from mb, but does not call Next.
  15. func getChunkAsString(t *testing.T, mb *MediaBuffer) (string, error) {
  16. chunk, _, size, err := mb.Chunk()
  17. buf, e := ioutil.ReadAll(chunk)
  18. if e != nil {
  19. t.Fatalf("Failed reading chunk: %v", e)
  20. }
  21. if size != len(buf) {
  22. t.Fatalf("reported chunk size doesn't match actual chunk size: got: %v; want: %v", size, len(buf))
  23. }
  24. return string(buf), err
  25. }
  26. func TestChunking(t *testing.T) {
  27. type testCase struct {
  28. data string // the data to read from the Reader
  29. finalErr error // error to return after data has been read
  30. chunkSize int
  31. wantChunks []string
  32. }
  33. for _, singleByteReads := range []bool{true, false} {
  34. for _, tc := range []testCase{
  35. {
  36. data: "abcdefg",
  37. finalErr: nil,
  38. chunkSize: 3,
  39. wantChunks: []string{"abc", "def", "g"},
  40. },
  41. {
  42. data: "abcdefg",
  43. finalErr: nil,
  44. chunkSize: 1,
  45. wantChunks: []string{"a", "b", "c", "d", "e", "f", "g"},
  46. },
  47. {
  48. data: "abcdefg",
  49. finalErr: nil,
  50. chunkSize: 7,
  51. wantChunks: []string{"abcdefg"},
  52. },
  53. {
  54. data: "abcdefg",
  55. finalErr: nil,
  56. chunkSize: 8,
  57. wantChunks: []string{"abcdefg"},
  58. },
  59. {
  60. data: "abcdefg",
  61. finalErr: io.ErrUnexpectedEOF,
  62. chunkSize: 3,
  63. wantChunks: []string{"abc", "def", "g"},
  64. },
  65. {
  66. data: "abcdefg",
  67. finalErr: io.ErrUnexpectedEOF,
  68. chunkSize: 8,
  69. wantChunks: []string{"abcdefg"},
  70. },
  71. } {
  72. var r io.Reader = &errReader{buf: []byte(tc.data), err: tc.finalErr}
  73. if singleByteReads {
  74. r = iotest.OneByteReader(r)
  75. }
  76. mb := NewMediaBuffer(r, tc.chunkSize)
  77. var gotErr error
  78. got := []string{}
  79. for {
  80. chunk, err := getChunkAsString(t, mb)
  81. if len(chunk) != 0 {
  82. got = append(got, string(chunk))
  83. }
  84. if err != nil {
  85. gotErr = err
  86. break
  87. }
  88. mb.Next()
  89. }
  90. if !reflect.DeepEqual(got, tc.wantChunks) {
  91. t.Errorf("Failed reading buffer: got: %v; want:%v", got, tc.wantChunks)
  92. }
  93. expectedErr := tc.finalErr
  94. if expectedErr == nil {
  95. expectedErr = io.EOF
  96. }
  97. if gotErr != expectedErr {
  98. t.Errorf("Reading buffer error: got: %v; want: %v", gotErr, expectedErr)
  99. }
  100. }
  101. }
  102. }
  103. func TestChunkCanBeReused(t *testing.T) {
  104. er := &errReader{buf: []byte("abcdefg")}
  105. mb := NewMediaBuffer(er, 3)
  106. // expectChunk reads a chunk and checks that it got what was wanted.
  107. expectChunk := func(want string, wantErr error) {
  108. got, err := getChunkAsString(t, mb)
  109. if err != wantErr {
  110. t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
  111. }
  112. if !reflect.DeepEqual(got, want) {
  113. t.Errorf("Failed reading buffer: got: %q; want:%q", got, want)
  114. }
  115. }
  116. expectChunk("abc", nil)
  117. // On second call, should get same chunk again.
  118. expectChunk("abc", nil)
  119. mb.Next()
  120. expectChunk("def", nil)
  121. expectChunk("def", nil)
  122. mb.Next()
  123. expectChunk("g", io.EOF)
  124. expectChunk("g", io.EOF)
  125. mb.Next()
  126. expectChunk("", io.EOF)
  127. }
  128. func TestPos(t *testing.T) {
  129. er := &errReader{buf: []byte("abcdefg")}
  130. mb := NewMediaBuffer(er, 3)
  131. expectChunkAtOffset := func(want int64, wantErr error) {
  132. _, off, _, err := mb.Chunk()
  133. if err != wantErr {
  134. t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
  135. }
  136. if got := off; got != want {
  137. t.Errorf("resumable buffer Pos: got: %v; want: %v", got, want)
  138. }
  139. }
  140. // We expect the first chunk to be at offset 0.
  141. expectChunkAtOffset(0, nil)
  142. // Fetching the same chunk should return the same offset.
  143. expectChunkAtOffset(0, nil)
  144. // Calling Next multiple times should only cause off to advance by 3, since off is not advanced until
  145. // the chunk is actually read.
  146. mb.Next()
  147. mb.Next()
  148. expectChunkAtOffset(3, nil)
  149. mb.Next()
  150. // Load the final 1-byte chunk.
  151. expectChunkAtOffset(6, io.EOF)
  152. // Next will advance 1 byte. But there are no more chunks, so off will not increase beyond 7.
  153. mb.Next()
  154. expectChunkAtOffset(7, io.EOF)
  155. mb.Next()
  156. expectChunkAtOffset(7, io.EOF)
  157. }
  158. // bytes.Reader implements both Reader and ReaderAt. The following types
  159. // implement various combinations of Reader, ReaderAt and ContentTyper, by
  160. // wrapping bytes.Reader. All implement at least ReaderAt, so they can be
  161. // passed to ReaderAtToReader. The following table summarizes which types
  162. // implement which interfaces:
  163. //
  164. // ReaderAt Reader ContentTyper
  165. // reader x x
  166. // typerReader x x x
  167. // readerAt x
  168. // typerReaderAt x x
  169. // reader implements Reader, in addition to ReaderAt.
  170. type reader struct {
  171. r *bytes.Reader
  172. }
  173. func (r *reader) ReadAt(b []byte, off int64) (n int, err error) {
  174. return r.r.ReadAt(b, off)
  175. }
  176. func (r *reader) Read(b []byte) (n int, err error) {
  177. return r.r.Read(b)
  178. }
  179. // typerReader implements Reader and ContentTyper, in addition to ReaderAt.
  180. type typerReader struct {
  181. r *bytes.Reader
  182. }
  183. func (tr *typerReader) ReadAt(b []byte, off int64) (n int, err error) {
  184. return tr.r.ReadAt(b, off)
  185. }
  186. func (tr *typerReader) Read(b []byte) (n int, err error) {
  187. return tr.r.Read(b)
  188. }
  189. func (tr *typerReader) ContentType() string {
  190. return "ctype"
  191. }
  192. // readerAt implements only ReaderAt.
  193. type readerAt struct {
  194. r *bytes.Reader
  195. }
  196. func (ra *readerAt) ReadAt(b []byte, off int64) (n int, err error) {
  197. return ra.r.ReadAt(b, off)
  198. }
  199. // typerReaderAt implements ContentTyper, in addition to ReaderAt.
  200. type typerReaderAt struct {
  201. r *bytes.Reader
  202. }
  203. func (tra *typerReaderAt) ReadAt(b []byte, off int64) (n int, err error) {
  204. return tra.r.ReadAt(b, off)
  205. }
  206. func (tra *typerReaderAt) ContentType() string {
  207. return "ctype"
  208. }
  209. func TestAdapter(t *testing.T) {
  210. data := "abc"
  211. checkConversion := func(to io.Reader, wantTyper bool) {
  212. if _, ok := to.(googleapi.ContentTyper); ok != wantTyper {
  213. t.Errorf("reader implements typer? got: %v; want: %v", ok, wantTyper)
  214. }
  215. if typer, ok := to.(googleapi.ContentTyper); ok && typer.ContentType() != "ctype" {
  216. t.Errorf("content type: got: %s; want: ctype", typer.ContentType())
  217. }
  218. buf, err := ioutil.ReadAll(to)
  219. if err != nil {
  220. t.Errorf("error reading data: %v", err)
  221. return
  222. }
  223. if !bytes.Equal(buf, []byte(data)) {
  224. t.Errorf("failed reading data: got: %s; want: %s", buf, data)
  225. }
  226. }
  227. type testCase struct {
  228. from io.ReaderAt
  229. wantTyper bool
  230. }
  231. for _, tc := range []testCase{
  232. {
  233. from: &reader{bytes.NewReader([]byte(data))},
  234. wantTyper: false,
  235. },
  236. {
  237. // Reader and ContentTyper
  238. from: &typerReader{bytes.NewReader([]byte(data))},
  239. wantTyper: true,
  240. },
  241. {
  242. // ReaderAt
  243. from: &readerAt{bytes.NewReader([]byte(data))},
  244. wantTyper: false,
  245. },
  246. {
  247. // ReaderAt and ContentTyper
  248. from: &typerReaderAt{bytes.NewReader([]byte(data))},
  249. wantTyper: true,
  250. },
  251. } {
  252. to := ReaderAtToReader(tc.from, int64(len(data)))
  253. checkConversion(to, tc.wantTyper)
  254. // tc.from is a ReaderAt, and should be treated like one, even
  255. // if it also implements Reader. Specifically, it can be
  256. // reused and read from the beginning.
  257. to = ReaderAtToReader(tc.from, int64(len(data)))
  258. checkConversion(to, tc.wantTyper)
  259. }
  260. }