github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/environment/destroy_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package environment_test
     5  
     6  import (
     7  	"bytes"
     8  	"time"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/cmd/juju/environment"
    17  	cmdtesting "github.com/juju/juju/cmd/testing"
    18  	"github.com/juju/juju/environs/configstore"
    19  	_ "github.com/juju/juju/provider/dummy"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  type DestroySuite struct {
    24  	testing.FakeJujuHomeSuite
    25  	api   *fakeDestroyAPI
    26  	store configstore.Storage
    27  }
    28  
    29  var _ = gc.Suite(&DestroySuite{})
    30  
    31  // fakeDestroyAPI mocks out the cient API
    32  type fakeDestroyAPI struct {
    33  	err error
    34  	env map[string]interface{}
    35  }
    36  
    37  func (f *fakeDestroyAPI) Close() error { return nil }
    38  
    39  func (f *fakeDestroyAPI) DestroyEnvironment() error {
    40  	return f.err
    41  }
    42  
    43  func (s *DestroySuite) SetUpTest(c *gc.C) {
    44  	s.FakeJujuHomeSuite.SetUpTest(c)
    45  	s.api = &fakeDestroyAPI{}
    46  	s.api.err = nil
    47  
    48  	var err error
    49  	s.store, err = configstore.Default()
    50  	c.Assert(err, jc.ErrorIsNil)
    51  
    52  	var envList = []struct {
    53  		name       string
    54  		serverUUID string
    55  		envUUID    string
    56  	}{
    57  		{
    58  			name:       "test1",
    59  			serverUUID: "test1-uuid",
    60  			envUUID:    "test1-uuid",
    61  		}, {
    62  			name:       "test2",
    63  			serverUUID: "test1-uuid",
    64  			envUUID:    "test2-uuid",
    65  		},
    66  	}
    67  	for _, env := range envList {
    68  		info := s.store.CreateInfo(env.name)
    69  		info.SetAPIEndpoint(configstore.APIEndpoint{
    70  			Addresses:   []string{"localhost"},
    71  			CACert:      testing.CACert,
    72  			EnvironUUID: env.envUUID,
    73  			ServerUUID:  env.serverUUID,
    74  		})
    75  
    76  		err := info.Write()
    77  		c.Assert(err, jc.ErrorIsNil)
    78  	}
    79  }
    80  
    81  func (s *DestroySuite) runDestroyCommand(c *gc.C, args ...string) (*cmd.Context, error) {
    82  	cmd := environment.NewDestroyCommand(s.api)
    83  	return testing.RunCommand(c, cmd, args...)
    84  }
    85  
    86  func (s *DestroySuite) newDestroyCommand() *environment.DestroyCommand {
    87  	return environment.NewDestroyCommand(s.api)
    88  }
    89  
    90  func checkEnvironmentExistsInStore(c *gc.C, name string, store configstore.Storage) {
    91  	_, err := store.ReadInfo(name)
    92  	c.Assert(err, jc.ErrorIsNil)
    93  }
    94  
    95  func checkEnvironmentRemovedFromStore(c *gc.C, name string, store configstore.Storage) {
    96  	_, err := store.ReadInfo(name)
    97  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    98  }
    99  
   100  func (s *DestroySuite) TestDestroyNoEnvironmentNameError(c *gc.C) {
   101  	_, err := s.runDestroyCommand(c)
   102  	c.Assert(err, gc.ErrorMatches, "no environment specified")
   103  }
   104  
   105  func (s *DestroySuite) TestDestroyBadFlags(c *gc.C) {
   106  	_, err := s.runDestroyCommand(c, "-n")
   107  	c.Assert(err, gc.ErrorMatches, "flag provided but not defined: -n")
   108  }
   109  
   110  func (s *DestroySuite) TestDestroyUnknownArgument(c *gc.C) {
   111  	_, err := s.runDestroyCommand(c, "environment", "whoops")
   112  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`)
   113  }
   114  
   115  func (s *DestroySuite) TestDestroyUnknownEnvironment(c *gc.C) {
   116  	_, err := s.runDestroyCommand(c, "foo")
   117  	c.Assert(err, gc.ErrorMatches, `cannot read environment info: environment "foo" not found`)
   118  }
   119  
   120  func (s *DestroySuite) TestDestroyCannotConnectToAPI(c *gc.C) {
   121  	s.api.err = errors.New("connection refused")
   122  	_, err := s.runDestroyCommand(c, "test2", "-y")
   123  	c.Assert(err, gc.ErrorMatches, "cannot destroy environment: connection refused")
   124  	c.Check(c.GetTestLog(), jc.Contains, "failed to destroy environment \"test2\"")
   125  	checkEnvironmentExistsInStore(c, "test2", s.store)
   126  }
   127  
   128  func (s *DestroySuite) TestSystemDestroyFails(c *gc.C) {
   129  	_, err := s.runDestroyCommand(c, "test1", "-y")
   130  	c.Assert(err, gc.ErrorMatches, `"test1" is a system; use 'juju system destroy' to destroy it`)
   131  	checkEnvironmentExistsInStore(c, "test1", s.store)
   132  }
   133  
   134  func (s *DestroySuite) TestDestroy(c *gc.C) {
   135  	checkEnvironmentExistsInStore(c, "test2", s.store)
   136  	_, err := s.runDestroyCommand(c, "test2", "-y")
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	checkEnvironmentRemovedFromStore(c, "test2", s.store)
   139  }
   140  
   141  func (s *DestroySuite) TestFailedDestroyEnvironment(c *gc.C) {
   142  	s.api.err = errors.New("permission denied")
   143  	_, err := s.runDestroyCommand(c, "test2", "-y")
   144  	c.Assert(err, gc.ErrorMatches, "cannot destroy environment: permission denied")
   145  	checkEnvironmentExistsInStore(c, "test2", s.store)
   146  }
   147  
   148  func (s *DestroySuite) resetEnvironment(c *gc.C) {
   149  	info := s.store.CreateInfo("test2")
   150  	info.SetAPIEndpoint(configstore.APIEndpoint{
   151  		Addresses:   []string{"localhost"},
   152  		CACert:      testing.CACert,
   153  		EnvironUUID: "test2-uuid",
   154  		ServerUUID:  "test1-uuid",
   155  	})
   156  	err := info.Write()
   157  	c.Assert(err, jc.ErrorIsNil)
   158  }
   159  
   160  func (s *DestroySuite) TestDestroyCommandConfirmation(c *gc.C) {
   161  	var stdin, stdout bytes.Buffer
   162  	ctx, err := cmd.DefaultContext()
   163  	c.Assert(err, jc.ErrorIsNil)
   164  	ctx.Stdout = &stdout
   165  	ctx.Stdin = &stdin
   166  
   167  	// Ensure confirmation is requested if "-y" is not specified.
   168  	stdin.WriteString("n")
   169  	_, errc := cmdtesting.RunCommand(ctx, s.newDestroyCommand(), "test2")
   170  	select {
   171  	case err := <-errc:
   172  		c.Check(err, gc.ErrorMatches, "environment destruction: aborted")
   173  	case <-time.After(testing.LongWait):
   174  		c.Fatalf("command took too long")
   175  	}
   176  	c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*")
   177  	checkEnvironmentExistsInStore(c, "test1", s.store)
   178  
   179  	// EOF on stdin: equivalent to answering no.
   180  	stdin.Reset()
   181  	stdout.Reset()
   182  	_, errc = cmdtesting.RunCommand(ctx, s.newDestroyCommand(), "test2")
   183  	select {
   184  	case err := <-errc:
   185  		c.Check(err, gc.ErrorMatches, "environment destruction: aborted")
   186  	case <-time.After(testing.LongWait):
   187  		c.Fatalf("command took too long")
   188  	}
   189  	c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*")
   190  	checkEnvironmentExistsInStore(c, "test1", s.store)
   191  
   192  	for _, answer := range []string{"y", "Y", "yes", "YES"} {
   193  		stdin.Reset()
   194  		stdout.Reset()
   195  		stdin.WriteString(answer)
   196  		_, errc = cmdtesting.RunCommand(ctx, s.newDestroyCommand(), "test2")
   197  		select {
   198  		case err := <-errc:
   199  			c.Check(err, jc.ErrorIsNil)
   200  		case <-time.After(testing.LongWait):
   201  			c.Fatalf("command took too long")
   202  		}
   203  		checkEnvironmentRemovedFromStore(c, "test2", s.store)
   204  
   205  		// Add the test2 environment back into the store for the next test
   206  		s.resetEnvironment(c)
   207  	}
   208  }
   209  
   210  func (s *DestroySuite) TestBlockedDestroy(c *gc.C) {
   211  	s.api.err = &params.Error{Code: params.CodeOperationBlocked}
   212  	s.runDestroyCommand(c, "test2", "-y")
   213  	c.Check(c.GetTestLog(), jc.Contains, "To remove the block")
   214  }