github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/model/destroy_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package model_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/model"
    17  	"github.com/juju/juju/cmd/modelcmd"
    18  	cmdtesting "github.com/juju/juju/cmd/testing"
    19  	"github.com/juju/juju/jujuclient"
    20  	"github.com/juju/juju/jujuclient/jujuclienttesting"
    21  	_ "github.com/juju/juju/provider/dummy"
    22  	"github.com/juju/juju/testing"
    23  )
    24  
    25  type DestroySuite struct {
    26  	testing.FakeJujuXDGDataHomeSuite
    27  	api   *fakeDestroyAPI
    28  	store *jujuclienttesting.MemStore
    29  }
    30  
    31  var _ = gc.Suite(&DestroySuite{})
    32  
    33  // fakeDestroyAPI mocks out the cient API
    34  type fakeDestroyAPI struct {
    35  	err error
    36  	env map[string]interface{}
    37  }
    38  
    39  func (f *fakeDestroyAPI) Close() error { return nil }
    40  
    41  func (f *fakeDestroyAPI) DestroyModel() error {
    42  	return f.err
    43  }
    44  
    45  func (s *DestroySuite) SetUpTest(c *gc.C) {
    46  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
    47  	s.api = &fakeDestroyAPI{}
    48  	s.api.err = nil
    49  
    50  	err := modelcmd.WriteCurrentController("test1")
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	s.store = jujuclienttesting.NewMemStore()
    53  	s.store.Controllers["test1"] = jujuclient.ControllerDetails{ControllerUUID: "test1-uuid"}
    54  	s.store.Models["test1"] = jujuclient.ControllerAccountModels{
    55  		AccountModels: map[string]*jujuclient.AccountModels{
    56  			"admin@local": {
    57  				Models: map[string]jujuclient.ModelDetails{
    58  					"test1": {"test1-uuid"},
    59  					"test2": {"test2-uuid"},
    60  				},
    61  			},
    62  		},
    63  	}
    64  	s.store.Accounts["test1"] = &jujuclient.ControllerAccounts{
    65  		CurrentAccount: "admin@local",
    66  	}
    67  }
    68  
    69  func (s *DestroySuite) runDestroyCommand(c *gc.C, args ...string) (*cmd.Context, error) {
    70  	cmd := model.NewDestroyCommandForTest(s.api, s.store)
    71  	return testing.RunCommand(c, cmd, args...)
    72  }
    73  
    74  func (s *DestroySuite) NewDestroyCommand() cmd.Command {
    75  	return model.NewDestroyCommandForTest(s.api, s.store)
    76  }
    77  
    78  func checkModelExistsInStore(c *gc.C, name string, store jujuclient.ClientStore) {
    79  	controller, model := modelcmd.SplitModelName(name)
    80  	_, err := store.ModelByName(controller, "admin@local", model)
    81  	c.Assert(err, jc.ErrorIsNil)
    82  }
    83  
    84  func checkModelRemovedFromStore(c *gc.C, name string, store jujuclient.ClientStore) {
    85  	controller, model := modelcmd.SplitModelName(name)
    86  	_, err := store.ModelByName(controller, "admin@local", model)
    87  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    88  }
    89  
    90  func (s *DestroySuite) TestDestroyNoModelNameError(c *gc.C) {
    91  	_, err := s.runDestroyCommand(c)
    92  	c.Assert(err, gc.ErrorMatches, "no model specified")
    93  }
    94  
    95  func (s *DestroySuite) TestDestroyBadFlags(c *gc.C) {
    96  	_, err := s.runDestroyCommand(c, "-n")
    97  	c.Assert(err, gc.ErrorMatches, "flag provided but not defined: -n")
    98  }
    99  
   100  func (s *DestroySuite) TestDestroyUnknownArgument(c *gc.C) {
   101  	_, err := s.runDestroyCommand(c, "model", "whoops")
   102  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`)
   103  }
   104  
   105  func (s *DestroySuite) TestDestroyUnknownModel(c *gc.C) {
   106  	_, err := s.runDestroyCommand(c, "foo")
   107  	c.Assert(err, gc.ErrorMatches, `cannot read model info: model test1:admin@local:foo not found`)
   108  }
   109  
   110  func (s *DestroySuite) TestDestroyCannotConnectToAPI(c *gc.C) {
   111  	s.api.err = errors.New("connection refused")
   112  	_, err := s.runDestroyCommand(c, "test2", "-y")
   113  	c.Assert(err, gc.ErrorMatches, "cannot destroy model: connection refused")
   114  	c.Check(c.GetTestLog(), jc.Contains, "failed to destroy model \"test2\"")
   115  	checkModelExistsInStore(c, "test1:test2", s.store)
   116  }
   117  
   118  func (s *DestroySuite) TestSystemDestroyFails(c *gc.C) {
   119  	_, err := s.runDestroyCommand(c, "test1", "-y")
   120  	c.Assert(err, gc.ErrorMatches, `"test1" is a controller; use 'juju destroy-controller' to destroy it`)
   121  	checkModelExistsInStore(c, "test1:test1", s.store)
   122  }
   123  
   124  func (s *DestroySuite) TestDestroy(c *gc.C) {
   125  	checkModelExistsInStore(c, "test1:test2", s.store)
   126  	_, err := s.runDestroyCommand(c, "test2", "-y")
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	checkModelRemovedFromStore(c, "test1:test2", s.store)
   129  }
   130  
   131  func (s *DestroySuite) TestFailedDestroyModel(c *gc.C) {
   132  	s.api.err = errors.New("permission denied")
   133  	_, err := s.runDestroyCommand(c, "test1:test2", "-y")
   134  	c.Assert(err, gc.ErrorMatches, "cannot destroy model: permission denied")
   135  	checkModelExistsInStore(c, "test1:test2", s.store)
   136  }
   137  
   138  func (s *DestroySuite) resetModel(c *gc.C) {
   139  	s.store.Models["test1"] = jujuclient.ControllerAccountModels{
   140  		AccountModels: map[string]*jujuclient.AccountModels{
   141  			"admin@local": {
   142  				Models: map[string]jujuclient.ModelDetails{
   143  					"test1": {"test1-uuid"},
   144  					"test2": {"test2-uuid"},
   145  				},
   146  			},
   147  		},
   148  	}
   149  }
   150  
   151  func (s *DestroySuite) TestDestroyCommandConfirmation(c *gc.C) {
   152  	var stdin, stdout bytes.Buffer
   153  	ctx, err := cmd.DefaultContext()
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	ctx.Stdout = &stdout
   156  	ctx.Stdin = &stdin
   157  
   158  	// Ensure confirmation is requested if "-y" is not specified.
   159  	stdin.WriteString("n")
   160  	_, errc := cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2")
   161  	select {
   162  	case err := <-errc:
   163  		c.Check(err, gc.ErrorMatches, "model destruction: aborted")
   164  	case <-time.After(testing.LongWait):
   165  		c.Fatalf("command took too long")
   166  	}
   167  	c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*")
   168  	checkModelExistsInStore(c, "test1:test1", s.store)
   169  
   170  	// EOF on stdin: equivalent to answering no.
   171  	stdin.Reset()
   172  	stdout.Reset()
   173  	_, errc = cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2")
   174  	select {
   175  	case err := <-errc:
   176  		c.Check(err, gc.ErrorMatches, "model destruction: aborted")
   177  	case <-time.After(testing.LongWait):
   178  		c.Fatalf("command took too long")
   179  	}
   180  	c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*")
   181  	checkModelExistsInStore(c, "test1:test2", s.store)
   182  
   183  	for _, answer := range []string{"y", "Y", "yes", "YES"} {
   184  		stdin.Reset()
   185  		stdout.Reset()
   186  		stdin.WriteString(answer)
   187  		_, errc = cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2")
   188  		select {
   189  		case err := <-errc:
   190  			c.Check(err, jc.ErrorIsNil)
   191  		case <-time.After(testing.LongWait):
   192  			c.Fatalf("command took too long")
   193  		}
   194  		checkModelRemovedFromStore(c, "test1:test2", s.store)
   195  
   196  		// Add the test2 model back into the store for the next test
   197  		s.resetModel(c)
   198  	}
   199  }
   200  
   201  func (s *DestroySuite) TestBlockedDestroy(c *gc.C) {
   202  	s.api.err = &params.Error{Code: params.CodeOperationBlocked}
   203  	s.runDestroyCommand(c, "test2", "-y")
   204  	c.Check(c.GetTestLog(), jc.Contains, "To remove the block")
   205  }