1
2
3
4
5
6
7
8
9
10
11
12 package gcsfs
13
14 import (
15 "context"
16 "io"
17 "os"
18 "strings"
19
20 "cloud.google.com/go/storage"
21 "github.com/googleapis/google-cloud-go-testing/storage/stiface"
22 "github.com/spf13/afero"
23 "google.golang.org/api/iterator"
24 )
25
26
27 func normSeparators(s string) string {
28 return strings.Replace(s, "\\", "/", -1)
29 }
30
31 type clientMock struct {
32 stiface.Client
33 fs afero.Fs
34 }
35
36 func newClientMock() *clientMock {
37 return &clientMock{fs: afero.NewMemMapFs()}
38 }
39
40 func (m *clientMock) Bucket(name string) stiface.BucketHandle {
41 return &bucketMock{bucketName: name, fs: m.fs}
42 }
43
44 type bucketMock struct {
45 stiface.BucketHandle
46
47 bucketName string
48
49 fs afero.Fs
50 }
51
52 func (m *bucketMock) Attrs(context.Context) (*storage.BucketAttrs, error) {
53 return &storage.BucketAttrs{}, nil
54 }
55
56 func (m *bucketMock) Object(name string) stiface.ObjectHandle {
57 return &objectMock{name: name, fs: m.fs}
58 }
59
60 func (m *bucketMock) Objects(_ context.Context, q *storage.Query) (it stiface.ObjectIterator) {
61 return &objectItMock{name: q.Prefix, fs: m.fs}
62 }
63
64 type objectMock struct {
65 stiface.ObjectHandle
66
67 name string
68 fs afero.Fs
69 }
70
71 func (o *objectMock) NewWriter(_ context.Context) stiface.Writer {
72 return &writerMock{name: o.name, fs: o.fs}
73 }
74
75 func (o *objectMock) NewRangeReader(_ context.Context, offset, length int64) (stiface.Reader, error) {
76 if o.name == "" {
77 return nil, ErrEmptyObjectName
78 }
79
80 file, err := o.fs.Open(o.name)
81 if err != nil {
82 return nil, err
83 }
84
85 if offset > 0 {
86 _, err = file.Seek(offset, io.SeekStart)
87 if err != nil {
88 return nil, err
89 }
90 }
91
92 res := &readerMock{file: file}
93 if length > -1 {
94 res.buf = make([]byte, length)
95 _, err = file.Read(res.buf)
96 if err != nil {
97 return nil, err
98 }
99 }
100
101 return res, nil
102 }
103
104 func (o *objectMock) Delete(_ context.Context) error {
105 if o.name == "" {
106 return ErrEmptyObjectName
107 }
108 return o.fs.Remove(o.name)
109 }
110
111 func (o *objectMock) Attrs(_ context.Context) (*storage.ObjectAttrs, error) {
112 if o.name == "" {
113 return nil, ErrEmptyObjectName
114 }
115
116 info, err := o.fs.Stat(o.name)
117 if err != nil {
118 pathError, ok := err.(*os.PathError)
119 if ok {
120 if pathError.Err == os.ErrNotExist {
121 return nil, storage.ErrObjectNotExist
122 }
123 }
124
125 return nil, err
126 }
127
128 res := &storage.ObjectAttrs{Name: normSeparators(o.name), Size: info.Size(), Updated: info.ModTime()}
129
130 if info.IsDir() {
131
132 return nil, ErrObjectDoesNotExist
133 }
134
135 return res, nil
136 }
137
138 type writerMock struct {
139 stiface.Writer
140
141 name string
142 fs afero.Fs
143
144 file afero.File
145 }
146
147 func (w *writerMock) Write(p []byte) (n int, err error) {
148 if w.name == "" {
149 return 0, ErrEmptyObjectName
150 }
151
152 if w.file == nil {
153 w.file, err = w.fs.Create(w.name)
154 if err != nil {
155 return 0, err
156 }
157 }
158
159 return w.file.Write(p)
160 }
161
162 func (w *writerMock) Close() error {
163 if w.name == "" {
164 return ErrEmptyObjectName
165 }
166 if w.file == nil {
167 var err error
168 if strings.HasSuffix(w.name, "/") {
169 err = w.fs.Mkdir(w.name, 0o755)
170 if err != nil {
171 return err
172 }
173 } else {
174 _, err = w.Write([]byte{})
175 if err != nil {
176 return err
177 }
178 }
179 }
180 if w.file != nil {
181 return w.file.Close()
182 }
183 return nil
184 }
185
186 type readerMock struct {
187 stiface.Reader
188
189 file afero.File
190
191 buf []byte
192 }
193
194 func (r *readerMock) Remain() int64 {
195 return 0
196 }
197
198 func (r *readerMock) Read(p []byte) (int, error) {
199 if r.buf != nil {
200 copy(p, r.buf)
201 return len(r.buf), nil
202 }
203 return r.file.Read(p)
204 }
205
206 func (r *readerMock) Close() error {
207 return r.file.Close()
208 }
209
210 type objectItMock struct {
211 stiface.ObjectIterator
212
213 name string
214 fs afero.Fs
215
216 dir afero.File
217 infos []*storage.ObjectAttrs
218 }
219
220 func (it *objectItMock) Next() (*storage.ObjectAttrs, error) {
221 var err error
222 if it.dir == nil {
223 it.dir, err = it.fs.Open(it.name)
224 if err != nil {
225 return nil, err
226 }
227
228 var isDir bool
229 isDir, err = afero.IsDir(it.fs, it.name)
230 if err != nil {
231 return nil, err
232 }
233
234 it.infos = []*storage.ObjectAttrs{}
235
236 if !isDir {
237 var info os.FileInfo
238 info, err = it.dir.Stat()
239 if err != nil {
240 return nil, err
241 }
242 it.infos = append(it.infos, &storage.ObjectAttrs{Name: normSeparators(info.Name()), Size: info.Size(), Updated: info.ModTime()})
243 } else {
244 var fInfos []os.FileInfo
245 fInfos, err = it.dir.Readdir(0)
246 if err != nil {
247 return nil, err
248 }
249 if it.name != "" {
250 it.infos = append(it.infos, &storage.ObjectAttrs{
251 Prefix: normSeparators(it.name) + "/",
252 })
253 }
254
255 for _, info := range fInfos {
256 it.infos = append(it.infos, &storage.ObjectAttrs{Name: normSeparators(info.Name()), Size: info.Size(), Updated: info.ModTime()})
257 }
258 }
259 }
260
261 if len(it.infos) == 0 {
262 return nil, iterator.Done
263 }
264
265 res := it.infos[0]
266 it.infos = it.infos[1:]
267
268 return res, err
269 }
270
View as plain text