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