package store import ( "bytes" "io" "net/http" "net/http/httptest" "testing" "time" ) // A reader over an in-memory slice, counting the fetches a query would cost. func testReader(data []byte, chunk int64) (*chunkReader, *int) { calls := 0 return newChunkReader(int64(len(data)), chunk, func(off, n int64) ([]byte, error) { calls++ return data[off : off+n], nil }), &calls } func TestChunkReader(t *testing.T) { data := make([]byte, 3<<20+7) for i := range data { data[i] = byte(i * 31) } r, calls := testReader(data, 1000) got, err := io.ReadAll(r) if err != nil || !bytes.Equal(got, data) { t.Fatalf("ReadAll: err %v, %d bytes", err, len(got)) } if want := (len(data) + 999) / 1000; *calls != want { t.Errorf("%d fetches, want %d", *calls, want) } if n, _ := r.Seek(0, io.SeekEnd); n != int64(len(data)) { t.Errorf("SeekEnd = %d", n) } if _, err := r.Seek(-1, io.SeekStart); err == nil { t.Error("negative seek should fail") } r.Seek(1500, io.SeekStart) buf := make([]byte, 1200) if _, err := io.ReadFull(r, buf); err != nil || !bytes.Equal(buf, data[1500:2700]) { t.Errorf("read after seek: %v", err) } if _, err := r.Read(buf); r.off != 2700 && err != nil { t.Errorf("continuing read: %v", err) } } func TestChunkReaderServeContent(t *testing.T) { data := bytes.Repeat([]byte("0123456789"), 500) r, calls := testReader(data, 512) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/media/x", nil) req.Header.Set("Range", "bytes=1500-2499") http.ServeContent(w, req, "x.bin", time.Now(), r) if w.Code != http.StatusPartialContent || !bytes.Equal(w.Body.Bytes(), data[1500:2500]) || w.Header().Get("Content-Range") != "bytes 1500-2499/5000" { t.Errorf("range: code %d, %d bytes, %s", w.Code, w.Body.Len(), w.Header().Get("Content-Range")) } if *calls != 2 { t.Errorf("a 1000-byte range cost %d fetches, want 2", *calls) } r, calls = testReader(data, 512) w = httptest.NewRecorder() http.ServeContent(w, httptest.NewRequest("HEAD", "/media/x", nil), "x.bin", time.Now(), r) if w.Code != http.StatusOK || w.Header().Get("Content-Length") != "5000" || *calls != 0 { t.Errorf("HEAD: code %d, length %s, %d fetches", w.Code, w.Header().Get("Content-Length"), *calls) } }