github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/environs/configstore/disk_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package configstore_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/user"
    11  	"path/filepath"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/juju/errors"
    16  	jc "github.com/juju/testing/checkers"
    17  	gc "launchpad.net/gocheck"
    18  
    19  	"github.com/juju/juju/environs/configstore"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  var _ = gc.Suite(&diskInterfaceSuite{})
    24  
    25  type diskInterfaceSuite struct {
    26  	interfaceSuite
    27  	dir string
    28  }
    29  
    30  func (s *diskInterfaceSuite) SetUpTest(c *gc.C) {
    31  	s.dir = c.MkDir()
    32  	s.NewStore = func(c *gc.C) configstore.Storage {
    33  		store, err := configstore.NewDisk(s.dir)
    34  		c.Assert(err, gc.IsNil)
    35  		return store
    36  	}
    37  }
    38  
    39  // storePath returns the path to the environment info
    40  // for the named environment in the given directory.
    41  // If envName is empty, it returns the path
    42  // to the info files' containing directory.
    43  func storePath(dir string, envName string) string {
    44  	path := filepath.Join(dir, "environments")
    45  	if envName != "" {
    46  		path = filepath.Join(path, envName+".jenv")
    47  	}
    48  	return path
    49  }
    50  
    51  func (s *diskInterfaceSuite) TearDownTest(c *gc.C) {
    52  	s.NewStore = nil
    53  	// Check that no stray temp files have been left behind
    54  	entries, err := ioutil.ReadDir(storePath(s.dir, ""))
    55  	c.Assert(err, gc.IsNil)
    56  	for _, entry := range entries {
    57  		if !strings.HasSuffix(entry.Name(), ".jenv") {
    58  			c.Errorf("found possible stray temp file %q", entry.Name())
    59  		}
    60  	}
    61  }
    62  
    63  var _ = gc.Suite(&diskStoreSuite{})
    64  
    65  type diskStoreSuite struct {
    66  	testing.BaseSuite
    67  }
    68  
    69  func (*diskStoreSuite) TestNewDisk(c *gc.C) {
    70  	dir := c.MkDir()
    71  	store, err := configstore.NewDisk(filepath.Join(dir, "foo"))
    72  	c.Assert(err, jc.Satisfies, os.IsNotExist)
    73  	c.Assert(store, gc.IsNil)
    74  
    75  	store, err = configstore.NewDisk(filepath.Join(dir))
    76  	c.Assert(err, gc.IsNil)
    77  	c.Assert(store, gc.NotNil)
    78  }
    79  
    80  var sampleInfo = `
    81    user: rog
    82    password: guessit
    83    state-servers:
    84    - example.com
    85    - kremvax.ru
    86    ca-cert: 'first line
    87  
    88      second line'
    89    bootstrap-config:
    90      secret: blah
    91      arble: bletch
    92  `[1:]
    93  
    94  func (*diskStoreSuite) TestRead(c *gc.C) {
    95  	dir := c.MkDir()
    96  	err := os.Mkdir(storePath(dir, ""), 0700)
    97  	c.Assert(err, gc.IsNil)
    98  	err = ioutil.WriteFile(storePath(dir, "someenv"), []byte(sampleInfo), 0666)
    99  	c.Assert(err, gc.IsNil)
   100  	store, err := configstore.NewDisk(dir)
   101  	c.Assert(err, gc.IsNil)
   102  	info, err := store.ReadInfo("someenv")
   103  	c.Assert(err, gc.IsNil)
   104  	c.Assert(info.Initialized(), jc.IsTrue)
   105  	c.Assert(info.APICredentials(), gc.DeepEquals, configstore.APICredentials{
   106  		User:     "rog",
   107  		Password: "guessit",
   108  	})
   109  	c.Assert(info.APIEndpoint(), gc.DeepEquals, configstore.APIEndpoint{
   110  		Addresses: []string{"example.com", "kremvax.ru"},
   111  		CACert:    "first line\nsecond line",
   112  	})
   113  	c.Assert(info.Location(), gc.Equals, fmt.Sprintf("file %q", dir+"/environments/someenv.jenv"))
   114  	c.Assert(info.BootstrapConfig(), gc.DeepEquals, map[string]interface{}{
   115  		"secret": "blah",
   116  		"arble":  "bletch",
   117  	})
   118  }
   119  
   120  func (*diskStoreSuite) TestReadNotFound(c *gc.C) {
   121  	dir := c.MkDir()
   122  	store, err := configstore.NewDisk(dir)
   123  	c.Assert(err, gc.IsNil)
   124  	info, err := store.ReadInfo("someenv")
   125  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   126  	c.Assert(info, gc.IsNil)
   127  }
   128  
   129  func (*diskStoreSuite) TestCreate(c *gc.C) {
   130  	dir := c.MkDir()
   131  	store, err := configstore.NewDisk(dir)
   132  	c.Assert(err, gc.IsNil)
   133  
   134  	// Create some new environment info.
   135  	info, err := store.CreateInfo("someenv")
   136  	c.Assert(err, gc.IsNil)
   137  	c.Assert(info.APIEndpoint(), gc.DeepEquals, configstore.APIEndpoint{})
   138  	c.Assert(info.APICredentials(), gc.DeepEquals, configstore.APICredentials{})
   139  	c.Assert(info.Initialized(), jc.IsFalse)
   140  	data, err := ioutil.ReadFile(storePath(dir, "someenv"))
   141  	c.Assert(err, gc.IsNil)
   142  	c.Assert(data, gc.HasLen, 0)
   143  
   144  	// Check that we can't create it twice.
   145  	info, err = store.CreateInfo("someenv")
   146  	c.Assert(err, gc.Equals, configstore.ErrEnvironInfoAlreadyExists)
   147  	c.Assert(info, gc.IsNil)
   148  
   149  	// Check that we can read it again.
   150  	info, err = store.ReadInfo("someenv")
   151  	c.Assert(err, gc.IsNil)
   152  	c.Assert(info.Initialized(), jc.IsFalse)
   153  }
   154  
   155  func (s *diskStoreSuite) TestCreatePermissions(c *gc.C) {
   156  	// Even though it doesn't test the actual chown, it does test the code path.
   157  	user, err := user.Current()
   158  	c.Assert(err, gc.IsNil)
   159  	s.PatchEnvironment("SUDO_UID", user.Uid)
   160  	s.PatchEnvironment("SUDO_GID", user.Gid)
   161  
   162  	dir := c.MkDir()
   163  	store, err := configstore.NewDisk(dir)
   164  	c.Assert(err, gc.IsNil)
   165  
   166  	// Create some new environment info.
   167  	_, err = store.CreateInfo("someenv")
   168  	c.Assert(err, gc.IsNil)
   169  
   170  	checkPath := func(path string) {
   171  		stat, err := os.Stat(path)
   172  		c.Assert(err, gc.IsNil)
   173  		c.Assert(fmt.Sprint(stat.Sys().(*syscall.Stat_t).Uid), gc.Equals, user.Uid)
   174  		c.Assert(fmt.Sprint(stat.Sys().(*syscall.Stat_t).Gid), gc.Equals, user.Gid)
   175  	}
   176  	checkPath(storePath(dir, ""))
   177  	checkPath(storePath(dir, "someenv"))
   178  }
   179  
   180  func (*diskStoreSuite) TestWriteTempFileFails(c *gc.C) {
   181  	dir := c.MkDir()
   182  	store, err := configstore.NewDisk(dir)
   183  	c.Assert(err, gc.IsNil)
   184  
   185  	info, err := store.CreateInfo("someenv")
   186  	c.Assert(err, gc.IsNil)
   187  
   188  	// Make the directory non-writable
   189  	err = os.Chmod(storePath(dir, ""), 0555)
   190  	c.Assert(err, gc.IsNil)
   191  
   192  	err = info.Write()
   193  	c.Assert(err, gc.ErrorMatches, "cannot create temporary file: .*")
   194  
   195  	// Make the directory writable again so that gocheck can clean it up.
   196  	err = os.Chmod(storePath(dir, ""), 0777)
   197  	c.Assert(err, gc.IsNil)
   198  }
   199  
   200  func (*diskStoreSuite) TestRenameFails(c *gc.C) {
   201  	dir := c.MkDir()
   202  	store, err := configstore.NewDisk(dir)
   203  	c.Assert(err, gc.IsNil)
   204  
   205  	info, err := store.CreateInfo("someenv")
   206  	c.Assert(err, gc.IsNil)
   207  
   208  	// Replace the file by an directory which can't be renamed over.
   209  	path := storePath(dir, "someenv")
   210  	err = os.Remove(path)
   211  	c.Assert(err, gc.IsNil)
   212  	err = os.Mkdir(path, 0777)
   213  	c.Assert(err, gc.IsNil)
   214  
   215  	err = info.Write()
   216  	c.Assert(err, gc.ErrorMatches, "cannot rename new environment info file: .*")
   217  }
   218  
   219  func (*diskStoreSuite) TestDestroyRemovesFiles(c *gc.C) {
   220  	dir := c.MkDir()
   221  	store, err := configstore.NewDisk(dir)
   222  	c.Assert(err, gc.IsNil)
   223  
   224  	info, err := store.CreateInfo("someenv")
   225  	c.Assert(err, gc.IsNil)
   226  
   227  	_, err = os.Stat(storePath(dir, "someenv"))
   228  	c.Assert(err, gc.IsNil)
   229  
   230  	err = info.Destroy()
   231  	c.Assert(err, gc.IsNil)
   232  
   233  	_, err = os.Stat(storePath(dir, "someenv"))
   234  	c.Assert(err, jc.Satisfies, os.IsNotExist)
   235  
   236  	err = info.Destroy()
   237  	c.Assert(err, gc.ErrorMatches, "environment info has already been removed")
   238  }