@@ -195,14 +195,11 @@ type file struct {
195195body []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 ) {
204201files := []file {{"icon.png" , []byte ("fake icon" )}}
205- if manifest != nil {
202+ if manifestBytes != nil {
206203files = append (files , file {"extension.vsixmanifest" , manifestBytes })
207204}
208205
@@ -223,6 +220,8 @@ func createVsix(manifest *storage.VSIXManifest) ([]byte, error) {
223220return 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.
226225func requireExtension (t * testing.T , ext testutil.Extension , extdir string , got string ) {
227226expected := filepath .Join (extdir , ext .Publisher , ext .Name , ext .LatestVersion )
228227require .Equal (t , expected , got )
@@ -238,85 +237,192 @@ func requireExtension(t *testing.T, ext testutil.Extension, extdir string, got s
238237func TestAddExtension (t * testing.T ) {
239238t .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 ) {
280336t .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 ) {
308398t .Parallel ()
309399
310400tests := []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{
316407error : "not found" ,
317408name : "Missing" ,
318409manifest : 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{
321427error : "publisher" ,
322428name : "MissingPublisher" ,
@@ -352,7 +458,12 @@ func TestAddExtension(t *testing.T) {
352458t .Run (test .name , func (t * testing.T ) {
353459t .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 )
356467require .NoError (t , err )
357468
358469extdir := t .TempDir ()
@@ -364,9 +475,7 @@ func TestAddExtension(t *testing.T) {
364475
365476_ , err = s .AddExtension (context .Background (), vsixPath )
366477require .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