Commit 396cc228 authored by Masih H. Derkani's avatar Masih H. Derkani Committed by Masih H. Derkani

Allow `ReadOption`s to be set when getting or generating index

Fix a bug in read options where the value of zero-len option is always
set to `true` even if the flag passed is false. This meant if the option
was present it would have always enabled the zero-len as EOF.

Allow the user to specify read options on `ReadOrGenerateIndex`. Pass
the options onto downstream reader/generators.

Generate a CARv1 file with null padding and check it into `testdata`. In
addition check in another such file from ignite just to have two
different samples of this case.

Enhance index generation tests to expect error when zero-len option is
not set, and generate index when it is for files with null padding.

Make RW blockstore test use the fixed test files from `testdata` instead
of generating every time.
parent 326783fe
...@@ -305,12 +305,9 @@ func (b bufferReaderAt) ReadAt(p []byte, off int64) (int, error) { ...@@ -305,12 +305,9 @@ func (b bufferReaderAt) ReadAt(p []byte, off int64) (int, error) {
} }
func TestBlockstoreNullPadding(t *testing.T) { func TestBlockstoreNullPadding(t *testing.T) {
paddedV1, err := ioutil.ReadFile("../testdata/sample-v1.car") paddedV1, err := ioutil.ReadFile("../testdata/sample-v1-with-zero-len-section.car")
require.NoError(t, err) require.NoError(t, err)
// A sample null-padded CARv1 file.
paddedV1 = append(paddedV1, make([]byte, 2048)...)
rbs, err := blockstore.NewReadOnly(bufferReaderAt(paddedV1), nil, rbs, err := blockstore.NewReadOnly(bufferReaderAt(paddedV1), nil,
carv2.ZeroLengthSectionAsEOF(true)) carv2.ZeroLengthSectionAsEOF(true))
require.NoError(t, err) require.NoError(t, err)
......
...@@ -110,7 +110,7 @@ func GenerateIndexFromFile(path string) (index.Index, error) { ...@@ -110,7 +110,7 @@ func GenerateIndexFromFile(path string) (index.Index, error) {
// //
// Note, the returned index lives entirely in memory and will not depend on the // Note, the returned index lives entirely in memory and will not depend on the
// given reader to fulfill index lookup. // given reader to fulfill index lookup.
func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) { func ReadOrGenerateIndex(rs io.ReadSeeker, opts ...ReadOption) (index.Index, error) {
// Read version. // Read version.
version, err := ReadVersion(rs) version, err := ReadVersion(rs)
if err != nil { if err != nil {
...@@ -124,10 +124,10 @@ func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) { ...@@ -124,10 +124,10 @@ func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) {
switch version { switch version {
case 1: case 1:
// Simply generate the index, since there can't be a pre-existing one. // Simply generate the index, since there can't be a pre-existing one.
return GenerateIndex(rs) return GenerateIndex(rs, opts...)
case 2: case 2:
// Read CARv2 format // Read CARv2 format
v2r, err := NewReader(internalio.ToReaderAt(rs)) v2r, err := NewReader(internalio.ToReaderAt(rs), opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -136,7 +136,7 @@ func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) { ...@@ -136,7 +136,7 @@ func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) {
return index.ReadFrom(v2r.IndexReader()) return index.ReadFrom(v2r.IndexReader())
} }
// Otherwise, generate index from CARv1 payload wrapped within CARv2 format. // Otherwise, generate index from CARv1 payload wrapped within CARv2 format.
return GenerateIndex(v2r.DataReader()) return GenerateIndex(v2r.DataReader(), opts...)
default: default:
return nil, fmt.Errorf("unknown version %v", version) return nil, fmt.Errorf("unknown version %v", version)
} }
......
...@@ -13,12 +13,14 @@ func TestReadOrGenerateIndex(t *testing.T) { ...@@ -13,12 +13,14 @@ func TestReadOrGenerateIndex(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
carPath string carPath string
readOpts []ReadOption
wantIndexer func(t *testing.T) index.Index wantIndexer func(t *testing.T) index.Index
wantErr bool wantErr bool
}{ }{
{ {
"CarV1IsIndexedAsExpected", "CarV1IsIndexedAsExpected",
"testdata/sample-v1.car", "testdata/sample-v1.car",
[]ReadOption{},
func(t *testing.T) index.Index { func(t *testing.T) index.Index {
v1, err := os.Open("testdata/sample-v1.car") v1, err := os.Open("testdata/sample-v1.car")
require.NoError(t, err) require.NoError(t, err)
...@@ -32,6 +34,7 @@ func TestReadOrGenerateIndex(t *testing.T) { ...@@ -32,6 +34,7 @@ func TestReadOrGenerateIndex(t *testing.T) {
{ {
"CarV2WithIndexIsReturnedAsExpected", "CarV2WithIndexIsReturnedAsExpected",
"testdata/sample-wrapped-v2.car", "testdata/sample-wrapped-v2.car",
[]ReadOption{},
func(t *testing.T) index.Index { func(t *testing.T) index.Index {
v2, err := os.Open("testdata/sample-wrapped-v2.car") v2, err := os.Open("testdata/sample-wrapped-v2.car")
require.NoError(t, err) require.NoError(t, err)
...@@ -44,9 +47,45 @@ func TestReadOrGenerateIndex(t *testing.T) { ...@@ -44,9 +47,45 @@ func TestReadOrGenerateIndex(t *testing.T) {
}, },
false, false,
}, },
{
"CarV1WithZeroLenSectionIsGeneratedAsExpected",
"testdata/sample-v1-with-zero-len-section.car",
[]ReadOption{ZeroLengthSectionAsEOF(true)},
func(t *testing.T) index.Index {
v1, err := os.Open("testdata/sample-v1-with-zero-len-section.car")
require.NoError(t, err)
defer v1.Close()
want, err := GenerateIndex(v1, ZeroLengthSectionAsEOF(true))
require.NoError(t, err)
return want
},
false,
},
{
"AnotherCarV1WithZeroLenSectionIsGeneratedAsExpected",
"testdata/sample-v1-with-zero-len-section2.car",
[]ReadOption{ZeroLengthSectionAsEOF(true)},
func(t *testing.T) index.Index {
v1, err := os.Open("testdata/sample-v1-with-zero-len-section2.car")
require.NoError(t, err)
defer v1.Close()
want, err := GenerateIndex(v1, ZeroLengthSectionAsEOF(true))
require.NoError(t, err)
return want
},
false,
},
{
"CarV1WithZeroLenSectionWithoutOptionIsError",
"testdata/sample-v1-with-zero-len-section.car",
[]ReadOption{},
func(t *testing.T) index.Index { return nil },
true,
},
{ {
"CarOtherThanV1OrV2IsError", "CarOtherThanV1OrV2IsError",
"testdata/sample-rootless-v42.car", "testdata/sample-rootless-v42.car",
[]ReadOption{},
func(t *testing.T) index.Index { return nil }, func(t *testing.T) index.Index { return nil },
true, true,
}, },
...@@ -56,7 +95,7 @@ func TestReadOrGenerateIndex(t *testing.T) { ...@@ -56,7 +95,7 @@ func TestReadOrGenerateIndex(t *testing.T) {
carFile, err := os.Open(tt.carPath) carFile, err := os.Open(tt.carPath)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { assert.NoError(t, carFile.Close()) }) t.Cleanup(func() { assert.NoError(t, carFile.Close()) })
got, err := ReadOrGenerateIndex(carFile) got, err := ReadOrGenerateIndex(carFile, tt.readOpts...)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
} }
......
...@@ -48,7 +48,7 @@ type ReadWriteOption interface { ...@@ -48,7 +48,7 @@ type ReadWriteOption interface {
// padding begins. // padding begins.
func ZeroLengthSectionAsEOF(enable bool) ReadOption { func ZeroLengthSectionAsEOF(enable bool) ReadOption {
return func(o *ReadOptions) { return func(o *ReadOptions) {
o.ZeroLengthSectionAsEOF = true o.ZeroLengthSectionAsEOF = enable
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment