Skip to content

Commit 18a7ecf

Browse files
committed
Fix some add errors not bubbling up
1 parent d7ce509 commit 18a7ecf

File tree

2 files changed

+176
-67
lines changed

2 files changed

+176
-67
lines changed

storage/local.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,18 @@ func (s *Local) AddExtension(ctx context.Context, source string) (string, error)
5555
return os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
5656
})
5757
if err != nil {
58-
return "", nil
58+
return "", err
5959
}
6060

6161
// Copy the VSIX itself as well.
6262
vsixName := fmt.Sprintf("%s.%s-%s.vsix", identity.Publisher, identity.ID, identity.Version)
6363
dst, err := os.OpenFile(filepath.Join(dir, vsixName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
6464
if err != nil {
65-
return "", nil
65+
return "", err
6666
}
6767
_, err = io.Copy(dst, bytes.NewReader(vsixBytes))
6868
if err != nil {
69-
return "", nil
69+
return "", err
7070
}
7171

7272
return dir, nil

storage/storage_test.go

Lines changed: 173 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,11 @@ type file struct {
195195
body []byte
196196
}
197197

198-
func createVsix(manifest *storage.VSIXManifest) ([]byte, error) {
199-
manifestBytes, err := xml.Marshal(manifest)
200-
if err != nil {
201-
return nil, err
202-
}
203-
198+
// createVSIX returns the bytes for a VSIX file containing the provided manifest
199+
// and an icon.
200+
func createVSIX(manifestBytes []byte) ([]byte, error) {
204201
files := []file{{"icon.png", []byte("fake icon")}}
205-
if manifest != nil {
202+
if manifestBytes != nil {
206203
files = append(files, file{"extension.vsixmanifest", manifestBytes})
207204
}
208205

@@ -223,6 +220,8 @@ func createVsix(manifest *storage.VSIXManifest) ([]byte, error) {
223220
return buf.Bytes(), nil
224221
}
225222

223+
// requireExtension verifies an extension exists in the extension directory and
224+
// that the received output matches the expected path.
226225
func requireExtension(t *testing.T, ext testutil.Extension, extdir string, got string) {
227226
expected := filepath.Join(extdir, ext.Publisher, ext.Name, ext.LatestVersion)
228227
require.Equal(t, expected, got)
@@ -238,85 +237,192 @@ func requireExtension(t *testing.T, ext testutil.Extension, extdir string, got s
238237
func TestAddExtension(t *testing.T) {
239238
t.Parallel()
240239

241-
t.Run("HTTPOK", func(t *testing.T) {
242-
t.Parallel()
243-
244-
ext := testutil.Extensions[0]
245-
vsix, err := createVsix(testutil.ConvertExtensionToManifest(ext, ext.LatestVersion))
246-
require.NoError(t, err)
247-
248-
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
249-
_, err := rw.Write(vsix)
250-
require.NoError(t, err)
251-
}))
252-
defer server.Close()
240+
ext := testutil.Extensions[0]
241+
manifestBytes, err := xml.Marshal(testutil.ConvertExtensionToManifest(ext, ext.LatestVersion))
242+
require.NoError(t, err)
243+
vsix, err := createVSIX(manifestBytes)
244+
require.NoError(t, err)
253245

254-
extdir := t.TempDir()
255-
s := &storage.Local{ExtDir: extdir}
246+
t.Run("HTTP", func(t *testing.T) {
247+
t.Parallel()
256248

257-
got, err := s.AddExtension(context.Background(), server.URL)
258-
require.NoError(t, err)
259-
requireExtension(t, ext, extdir, got)
260-
})
249+
tests := []struct {
250+
error string
251+
name string
252+
handler http.HandlerFunc
253+
setup func(extdir string) (string, error)
254+
}{
255+
{
256+
name: "OK",
257+
},
258+
{
259+
name: "InternalError",
260+
error: strconv.Itoa(http.StatusInternalServerError),
261+
handler: func(rw http.ResponseWriter, r *http.Request) {
262+
http.Error(rw, "something went wrong", http.StatusInternalServerError)
263+
},
264+
},
265+
{
266+
name: "ReadError",
267+
error: "unexpected EOF",
268+
handler: func(rw http.ResponseWriter, r *http.Request) {
269+
rw.Header().Set("Content-Length", "1")
270+
},
271+
},
272+
{
273+
name: "InvalidZip",
274+
error: "zip: not a valid zip file",
275+
handler: func(rw http.ResponseWriter, r *http.Request) {
276+
_, err := rw.Write([]byte{})
277+
require.NoError(t, err)
278+
},
279+
},
280+
{
281+
name: "ExtensionDirPerms",
282+
error: "permission denied",
283+
setup: func(extdir string) (string, error) {
284+
// Disallow writing to the extension directory.
285+
extdir = filepath.Join(extdir, "no-write")
286+
return extdir, os.MkdirAll(extdir, 0o444)
287+
},
288+
},
289+
{
290+
name: "CopyOverDirectory",
291+
error: "is a directory",
292+
setup: func(extdir string) (string, error) {
293+
// Put a directory in the way of the vsix.
294+
vsixName := fmt.Sprintf("%s.%s-%s.vsix", ext.Publisher, ext.Name, ext.LatestVersion)
295+
vsixPath := filepath.Join(extdir, ext.Publisher, ext.Name, ext.LatestVersion, vsixName)
296+
return extdir, os.MkdirAll(vsixPath, 0o755)
297+
},
298+
},
299+
}
261300

262-
t.Run("HTTPError", func(t *testing.T) {
263-
t.Parallel()
301+
for _, test := range tests {
302+
test := test
303+
t.Run(test.name, func(t *testing.T) {
304+
t.Parallel()
264305

265-
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
266-
http.Error(rw, "something went wrong", http.StatusInternalServerError)
267-
}))
268-
defer server.Close()
306+
handler := test.handler
307+
if handler == nil {
308+
handler = func(rw http.ResponseWriter, r *http.Request) {
309+
_, err := rw.Write(vsix)
310+
require.NoError(t, err)
311+
}
312+
}
269313

270-
s := &storage.Local{ExtDir: t.TempDir()}
314+
server := httptest.NewServer(http.HandlerFunc(handler))
315+
defer server.Close()
271316

272-
_, err := s.AddExtension(context.Background(), server.URL)
273-
require.Error(t, err)
317+
extdir := t.TempDir()
318+
if test.setup != nil {
319+
extdir, err = test.setup(extdir)
320+
require.NoError(t, err)
321+
}
322+
s := &storage.Local{ExtDir: extdir}
274323

275-
// The error should mention the status code.
276-
require.Contains(t, err.Error(), strconv.Itoa(http.StatusInternalServerError))
324+
got, err := s.AddExtension(context.Background(), server.URL)
325+
if test.error != "" {
326+
require.Error(t, err)
327+
require.Regexp(t, test.error, err.Error())
328+
} else {
329+
requireExtension(t, ext, extdir, got)
330+
}
331+
})
332+
}
277333
})
278334

279-
t.Run("FileOK", func(t *testing.T) {
335+
t.Run("File", func(t *testing.T) {
280336
t.Parallel()
281337

282-
ext := testutil.Extensions[0]
283-
vsix, err := createVsix(testutil.ConvertExtensionToManifest(ext, ext.LatestVersion))
284-
require.NoError(t, err)
285-
286-
extdir := t.TempDir()
287-
vsixPath := filepath.Join(extdir, "extension.vsix")
288-
err = os.WriteFile(vsixPath, vsix, 0o644)
289-
require.NoError(t, err)
338+
tests := []struct {
339+
error string
340+
name string
341+
source func(extdir string) (string, error)
342+
}{
343+
{
344+
name: "OK",
345+
source: func(extdir string) (string, error) {
346+
vsixPath := filepath.Join(extdir, "extension.vsix")
347+
return vsixPath, os.WriteFile(vsixPath, vsix, 0o644)
348+
},
349+
},
350+
{
351+
name: "NotFound",
352+
error: "foo\\.vsix.+no such file",
353+
source: func(extdir string) (string, error) {
354+
return filepath.Join(extdir, "foo.vsix"), nil
355+
},
356+
},
357+
{
358+
name: "EmptyFile",
359+
error: "zip: not a valid zip file",
360+
source: func(extdir string) (string, error) {
361+
vsixPath := filepath.Join(extdir, "foo.vsix")
362+
return vsixPath, os.WriteFile(vsixPath, []byte{}, 0o644)
363+
},
364+
},
365+
{
366+
name: "Unreadable",
367+
error: "permission denied",
368+
source: func(extdir string) (string, error) {
369+
vsixPath := filepath.Join(extdir, "extension.vsix")
370+
return vsixPath, os.WriteFile(vsixPath, []byte{}, 0o222)
371+
},
372+
},
373+
}
290374

291-
s := &storage.Local{ExtDir: extdir}
375+
for _, test := range tests {
376+
test := test
377+
t.Run(test.name, func(t *testing.T) {
378+
t.Parallel()
292379

293-
got, err := s.AddExtension(context.Background(), vsixPath)
294-
require.NoError(t, err)
295-
requireExtension(t, ext, extdir, got)
296-
})
380+
extdir := t.TempDir()
381+
s := &storage.Local{ExtDir: extdir}
297382

298-
t.Run("FileError", func(t *testing.T) {
299-
t.Parallel()
383+
source, err := test.source(extdir)
384+
require.NoError(t, err)
300385

301-
extdir := t.TempDir()
302-
s := &storage.Local{ExtDir: extdir}
303-
_, err := s.AddExtension(context.Background(), filepath.Join(extdir, "foo.vsix"))
304-
require.Error(t, err)
386+
got, err := s.AddExtension(context.Background(), source)
387+
if test.error != "" {
388+
require.Error(t, err)
389+
require.Regexp(t, test.error, err.Error())
390+
} else {
391+
requireExtension(t, ext, extdir, got)
392+
}
393+
})
394+
}
305395
})
306396

307-
t.Run("InvalidManifest", func(t *testing.T) {
397+
t.Run("ValidateManifest", func(t *testing.T) {
308398
t.Parallel()
309399

310400
tests := []struct {
311-
error string
312-
manifest *storage.VSIXManifest
313-
name string
401+
error string
402+
manifest *storage.VSIXManifest
403+
manifestBytes []byte
404+
name string
314405
}{
315406
{
316407
error: "not found",
317408
name: "Missing",
318409
manifest: nil,
319410
},
411+
{
412+
error: "EOF",
413+
name: "Empty",
414+
manifestBytes: []byte(""),
415+
},
416+
{
417+
error: "EOF",
418+
name: "TextFile",
419+
manifestBytes: []byte("just some random text"),
420+
},
421+
{
422+
error: "XML syntax error",
423+
name: "SyntaxError",
424+
manifestBytes: []byte("<PackageManifest/PackageManifest>"),
425+
},
320426
{
321427
error: "publisher",
322428
name: "MissingPublisher",
@@ -352,7 +458,12 @@ func TestAddExtension(t *testing.T) {
352458
t.Run(test.name, func(t *testing.T) {
353459
t.Parallel()
354460

355-
vsix, err := createVsix(test.manifest)
461+
manifestBytes := test.manifestBytes
462+
if manifestBytes == nil {
463+
manifestBytes, err = xml.Marshal(test.manifest)
464+
require.NoError(t, err)
465+
}
466+
vsix, err := createVSIX(manifestBytes)
356467
require.NoError(t, err)
357468

358469
extdir := t.TempDir()
@@ -364,9 +475,7 @@ func TestAddExtension(t *testing.T) {
364475

365476
_, err = s.AddExtension(context.Background(), vsixPath)
366477
require.Error(t, err)
367-
368-
// The error should mention what is wrong.
369-
require.Contains(t, err.Error(), test.error)
478+
require.Regexp(t, test.error, err.Error())
370479
})
371480
}
372481
})

0 commit comments

Comments
 (0)