Skip to content

Commit 3f40c94

Browse files
authored
Local fs start end offset (#101)
* Add TestList with empty case. * TestList: add "one" case. * TestList: add "many" case. * Support StartOffset. * Support EndOffset * Include localfs in StartOffset/EndOffset GoDoc. * Move offset filtering inside of filepath.Walk closure.
1 parent f2213e5 commit 3f40c94

3 files changed

Lines changed: 106 additions & 5 deletions

File tree

localfs/store.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,13 @@ func (l *LocalStore) List(ctx context.Context, query cloudstorage.Query) (*cloud
153153
mdkey := strings.Replace(obj, ".metadata", "", 1)
154154
metadatas[mdkey] = md
155155
} else {
156-
157156
oname := strings.TrimPrefix(obj, "/")
157+
158+
if (query.StartOffset != "" && oname < query.StartOffset) ||
159+
(query.EndOffset != "" && oname >= query.EndOffset) {
160+
return nil
161+
}
162+
158163
objects[obj] = &object{
159164
name: oname,
160165
updated: f.ModTime(),

localfs/store_test.go

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import (
77
"path/filepath"
88
"testing"
99

10-
"github.com/stretchr/testify/require"
11-
1210
"github.com/lytics/cloudstorage"
1311
"github.com/lytics/cloudstorage/localfs"
1412
"github.com/lytics/cloudstorage/testutils"
13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
1515
)
1616

1717
func TestAll(t *testing.T) {
@@ -111,3 +111,99 @@ func TestGetDir(t *testing.T) {
111111
err = store.Delete(context.Background(), "test/index.html")
112112
require.NoError(t, err)
113113
}
114+
115+
func TestList(t *testing.T) {
116+
t.Parallel()
117+
118+
for name, tt := range map[string]struct {
119+
objs map[string]string
120+
q cloudstorage.Query
121+
startOffset string
122+
want []string
123+
}{
124+
"empty": {
125+
objs: nil,
126+
want: nil,
127+
},
128+
"one": {
129+
objs: map[string]string{
130+
"nimi": "ijo",
131+
},
132+
want: []string{"nimi"},
133+
},
134+
"many": {
135+
objs: map[string]string{
136+
"wan": "loje",
137+
"tu": "jelo",
138+
"tu wan": "laso",
139+
},
140+
want: []string{"wan", "tu", "tu wan"},
141+
},
142+
"start-offset-inclusive": {
143+
objs: map[string]string{
144+
"a": "ijo",
145+
"b": "ijo",
146+
"c": "ijo",
147+
},
148+
q: cloudstorage.Query{
149+
StartOffset: "b",
150+
},
151+
want: []string{"b", "c"},
152+
},
153+
"end-offset-exclusive": {
154+
objs: map[string]string{
155+
"a": "ijo",
156+
"b": "ijo",
157+
"c": "ijo",
158+
},
159+
q: cloudstorage.Query{
160+
EndOffset: "b",
161+
},
162+
want: []string{"a"},
163+
},
164+
"start-and-end-offsets-together": {
165+
objs: map[string]string{
166+
"a": "ijo",
167+
"b": "ijo",
168+
"c": "ijo",
169+
},
170+
q: cloudstorage.Query{
171+
StartOffset: "b",
172+
EndOffset: "c",
173+
},
174+
want: []string{"b"},
175+
},
176+
} {
177+
t.Run(name, func(t *testing.T) {
178+
ctx := context.Background()
179+
180+
tmpDir, err := ioutil.TempDir("/tmp", "getdir")
181+
require.NoError(t, err)
182+
t.Cleanup(func() { assert.NoError(t, os.RemoveAll(tmpDir)) })
183+
184+
store, err := localfs.NewLocalStore(
185+
"list",
186+
filepath.Join(tmpDir, "mockcloud"),
187+
filepath.Join(tmpDir, "localcache"),
188+
)
189+
require.NoError(t, err)
190+
191+
for k, v := range tt.objs {
192+
w, err := store.NewWriterWithContext(ctx, k, nil)
193+
require.NoError(t, err)
194+
_, err = w.Write([]byte(v))
195+
require.NoError(t, err)
196+
err = w.Close()
197+
require.NoError(t, err)
198+
}
199+
200+
got, err := store.List(ctx, tt.q)
201+
require.NoError(t, err)
202+
var names []string
203+
for _, o := range got.Objects {
204+
names = append(names, o.Name())
205+
}
206+
assert.ElementsMatch(t, tt.want, names)
207+
})
208+
}
209+
}

query.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ type Filter func(objects Objects) Objects
1313
type Query struct {
1414
Delimiter string // Delimiter is most likely "/"
1515
Prefix string // prefix (directory) to search for or object name if one file
16-
StartOffset string // (gcs only) "bar/", Only list objects lexicographically >= "bar/"
17-
EndOffset string // (gcs only) "foo/", Only list objects lexicographically < "foo/"
16+
StartOffset string // (gcs/localfs only) "bar/", Only list objects lexicographically >= "bar/"
17+
EndOffset string // (gcs/localfs only) "foo/", Only list objects lexicographically < "foo/"
1818
Marker string // Next Page Marker if provided is a start next page fetch bookmark.
1919
ShowHidden bool // Show hidden files?
2020
Filters []Filter // Applied to the result sets to filter out Objects (i.e. remove objects by extension)

0 commit comments

Comments
 (0)