launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/httpstorage/storage_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package httpstorage_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"path/filepath"
    13  
    14  	gc "launchpad.net/gocheck"
    15  
    16  	"launchpad.net/juju-core/environs/httpstorage"
    17  	"launchpad.net/juju-core/environs/storage"
    18  	"launchpad.net/juju-core/errors"
    19  	coretesting "launchpad.net/juju-core/testing"
    20  	jc "launchpad.net/juju-core/testing/checkers"
    21  )
    22  
    23  type storageSuite struct{}
    24  
    25  var _ = gc.Suite(&storageSuite{})
    26  
    27  func (s *storageSuite) TestClientTLS(c *gc.C) {
    28  	listener, _, storageDir := startServerTLS(c)
    29  	defer listener.Close()
    30  	stor, err := httpstorage.ClientTLS(listener.Addr().String(), []byte(coretesting.CACert), testAuthkey)
    31  	c.Assert(err, gc.IsNil)
    32  
    33  	data := []byte("hello")
    34  	err = ioutil.WriteFile(filepath.Join(storageDir, "filename"), data, 0644)
    35  	c.Assert(err, gc.IsNil)
    36  	names, err := storage.List(stor, "filename")
    37  	c.Assert(err, gc.IsNil)
    38  	c.Assert(names, gc.DeepEquals, []string{"filename"})
    39  	checkFileHasContents(c, stor, "filename", data)
    40  
    41  	// Put, Remove and RemoveAll should all succeed.
    42  	checkPutFile(c, stor, "filenamethesecond", data)
    43  	checkFileHasContents(c, stor, "filenamethesecond", data)
    44  	c.Assert(stor.Remove("filenamethesecond"), gc.IsNil)
    45  	c.Assert(stor.RemoveAll(), gc.IsNil)
    46  }
    47  
    48  func (s *storageSuite) TestClientTLSInvalidAuth(c *gc.C) {
    49  	listener, _, storageDir := startServerTLS(c)
    50  	defer listener.Close()
    51  	const invalidAuthkey = testAuthkey + "!"
    52  	stor, err := httpstorage.ClientTLS(listener.Addr().String(), []byte(coretesting.CACert), invalidAuthkey)
    53  	c.Assert(err, gc.IsNil)
    54  
    55  	// Get and List should succeed.
    56  	data := []byte("hello")
    57  	err = ioutil.WriteFile(filepath.Join(storageDir, "filename"), data, 0644)
    58  	c.Assert(err, gc.IsNil)
    59  	names, err := storage.List(stor, "filename")
    60  	c.Assert(err, gc.IsNil)
    61  	c.Assert(names, gc.DeepEquals, []string{"filename"})
    62  	checkFileHasContents(c, stor, "filename", data)
    63  
    64  	// Put, Remove and RemoveAll should all fail.
    65  	const authErrorPattern = ".*401 Unauthorized"
    66  	err = putFile(c, stor, "filenamethesecond", data)
    67  	c.Assert(err, gc.ErrorMatches, authErrorPattern)
    68  	c.Assert(stor.Remove("filenamethesecond"), gc.ErrorMatches, authErrorPattern)
    69  	c.Assert(stor.RemoveAll(), gc.ErrorMatches, authErrorPattern)
    70  }
    71  
    72  func (s *storageSuite) TestList(c *gc.C) {
    73  	listener, _, _ := startServer(c)
    74  	defer listener.Close()
    75  	stor := httpstorage.Client(listener.Addr().String())
    76  	names, err := storage.List(stor, "a/b/c")
    77  	c.Assert(err, gc.IsNil)
    78  	c.Assert(names, gc.HasLen, 0)
    79  }
    80  
    81  // TestPersistence tests the adding, reading, listing and removing
    82  // of files from the local storage.
    83  func (s *storageSuite) TestPersistence(c *gc.C) {
    84  	listener, _, _ := startServer(c)
    85  	defer listener.Close()
    86  
    87  	stor := httpstorage.Client(listener.Addr().String())
    88  	names := []string{
    89  		"aa",
    90  		"zzz/aa",
    91  		"zzz/bb",
    92  	}
    93  	for _, name := range names {
    94  		checkFileDoesNotExist(c, stor, name)
    95  		checkPutFile(c, stor, name, []byte(name))
    96  	}
    97  	checkList(c, stor, "", names)
    98  	checkList(c, stor, "a", []string{"aa"})
    99  	checkList(c, stor, "zzz/", []string{"zzz/aa", "zzz/bb"})
   100  
   101  	storage2 := httpstorage.Client(listener.Addr().String())
   102  	for _, name := range names {
   103  		checkFileHasContents(c, storage2, name, []byte(name))
   104  	}
   105  
   106  	// remove the first file and check that the others remain.
   107  	err := storage2.Remove(names[0])
   108  	c.Check(err, gc.IsNil)
   109  
   110  	// check that it's ok to remove a file twice.
   111  	err = storage2.Remove(names[0])
   112  	c.Check(err, gc.IsNil)
   113  
   114  	// ... and check it's been removed in the other environment
   115  	checkFileDoesNotExist(c, stor, names[0])
   116  
   117  	// ... and that the rest of the files are still around
   118  	checkList(c, storage2, "", names[1:])
   119  
   120  	for _, name := range names[1:] {
   121  		err := storage2.Remove(name)
   122  		c.Assert(err, gc.IsNil)
   123  	}
   124  
   125  	// check they've all gone
   126  	checkList(c, storage2, "", nil)
   127  
   128  	// Check that RemoveAll works.
   129  	checkRemoveAll(c, storage2)
   130  }
   131  
   132  func checkList(c *gc.C, stor storage.StorageReader, prefix string, names []string) {
   133  	lnames, err := storage.List(stor, prefix)
   134  	c.Assert(err, gc.IsNil)
   135  	c.Assert(lnames, gc.DeepEquals, names)
   136  }
   137  
   138  type readerWithClose struct {
   139  	*bytes.Buffer
   140  	closeCalled bool
   141  }
   142  
   143  var _ io.Reader = (*readerWithClose)(nil)
   144  var _ io.Closer = (*readerWithClose)(nil)
   145  
   146  func (r *readerWithClose) Close() error {
   147  	r.closeCalled = true
   148  	return nil
   149  }
   150  
   151  func putFile(c *gc.C, stor storage.StorageWriter, name string, contents []byte) error {
   152  	c.Logf("check putting file %s ...", name)
   153  	reader := &readerWithClose{bytes.NewBuffer(contents), false}
   154  	err := stor.Put(name, reader, int64(len(contents)))
   155  	c.Assert(reader.closeCalled, jc.IsFalse)
   156  	return err
   157  }
   158  
   159  func checkPutFile(c *gc.C, stor storage.StorageWriter, name string, contents []byte) {
   160  	err := putFile(c, stor, name, contents)
   161  	c.Assert(err, gc.IsNil)
   162  }
   163  
   164  func checkFileDoesNotExist(c *gc.C, stor storage.StorageReader, name string) {
   165  	r, err := storage.Get(stor, name)
   166  	c.Assert(r, gc.IsNil)
   167  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   168  }
   169  
   170  func checkFileHasContents(c *gc.C, stor storage.StorageReader, name string, contents []byte) {
   171  	r, err := storage.Get(stor, name)
   172  	c.Assert(err, gc.IsNil)
   173  	c.Check(r, gc.NotNil)
   174  	defer r.Close()
   175  	data, err := ioutil.ReadAll(r)
   176  	c.Check(err, gc.IsNil)
   177  	c.Check(data, gc.DeepEquals, contents)
   178  
   179  	url, err := stor.URL(name)
   180  	c.Assert(err, gc.IsNil)
   181  	resp, err := http.Get(url)
   182  	c.Assert(err, gc.IsNil)
   183  	data, err = ioutil.ReadAll(resp.Body)
   184  	c.Assert(err, gc.IsNil)
   185  	defer resp.Body.Close()
   186  	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK, gc.Commentf("error response: %s", data))
   187  	c.Check(data, gc.DeepEquals, contents)
   188  }
   189  
   190  func checkRemoveAll(c *gc.C, stor storage.Storage) {
   191  	contents := []byte("File contents.")
   192  	aFile := "a-file.txt"
   193  	err := stor.Put(aFile, bytes.NewBuffer(contents), int64(len(contents)))
   194  	c.Assert(err, gc.IsNil)
   195  	err = stor.Put("empty-file", bytes.NewBuffer(nil), 0)
   196  	c.Assert(err, gc.IsNil)
   197  
   198  	err = stor.RemoveAll()
   199  	c.Assert(err, gc.IsNil)
   200  
   201  	files, err := storage.List(stor, "")
   202  	c.Assert(err, gc.IsNil)
   203  	c.Check(files, gc.HasLen, 0)
   204  
   205  	_, err = storage.Get(stor, aFile)
   206  	c.Assert(err, gc.NotNil)
   207  	c.Check(err, gc.ErrorMatches, fmt.Sprintf("file %q not found", aFile))
   208  }