github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/modelcmd/apiopener_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelcmd_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils/clock" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/api" 15 "github.com/juju/juju/cmd/modelcmd" 16 "github.com/juju/juju/jujuclient" 17 ) 18 19 type APIOpenerSuite struct { 20 // Don't need any base suites 21 } 22 23 var _ = gc.Suite(&APIOpenerSuite{}) 24 25 func (*APIOpenerSuite) TestPassthrough(c *gc.C) { 26 var controllerName, modelName string 27 open := func(_ jujuclient.ClientStore, controllerNameArg, modelNameArg string) (api.Connection, error) { 28 controllerName = controllerNameArg 29 modelName = modelNameArg 30 // Lets do the bad thing and return both a connection instance 31 // and an error to check they both come through. 32 return &mockConnection{}, errors.New("boom") 33 } 34 opener := modelcmd.OpenFunc(open) 35 conn, err := opener.Open(nil, "a-name", "b-name") 36 c.Assert(err, gc.ErrorMatches, "boom") 37 c.Assert(conn, gc.NotNil) 38 c.Assert(controllerName, gc.Equals, "a-name") 39 c.Assert(modelName, gc.Equals, "b-name") 40 } 41 42 func (*APIOpenerSuite) TestTimoutSuccess(c *gc.C) { 43 var controllerName, modelName string 44 open := func(_ jujuclient.ClientStore, controllerNameArg, modelNameArg string) (api.Connection, error) { 45 controllerName = controllerNameArg 46 modelName = modelNameArg 47 return &mockConnection{}, nil 48 } 49 opener := modelcmd.NewTimeoutOpener(modelcmd.OpenFunc(open), clock.WallClock, 10*time.Second) 50 conn, err := opener.Open(nil, "a-name", "b-name") 51 c.Assert(err, jc.ErrorIsNil) 52 c.Assert(conn, gc.NotNil) 53 c.Assert(controllerName, gc.Equals, "a-name") 54 c.Assert(modelName, gc.Equals, "b-name") 55 } 56 57 func (*APIOpenerSuite) TestTimoutErrors(c *gc.C) { 58 var controllerName, modelName string 59 open := func(_ jujuclient.ClientStore, controllerNameArg, modelNameArg string) (api.Connection, error) { 60 controllerName = controllerNameArg 61 modelName = modelNameArg 62 return nil, errors.New("boom") 63 } 64 opener := modelcmd.NewTimeoutOpener(modelcmd.OpenFunc(open), clock.WallClock, 10*time.Second) 65 conn, err := opener.Open(nil, "a-name", "b-name") 66 c.Assert(err, gc.ErrorMatches, "boom") 67 c.Assert(conn, gc.IsNil) 68 c.Assert(controllerName, gc.Equals, "a-name") 69 c.Assert(modelName, gc.Equals, "b-name") 70 } 71 72 func (*APIOpenerSuite) TestTimoutClosesAPIOnTimeout(c *gc.C) { 73 var controllerName, modelName string 74 finished := make(chan struct{}) 75 mockConn := &mockConnection{closed: make(chan struct{})} 76 open := func(_ jujuclient.ClientStore, controllerNameArg, modelNameArg string) (api.Connection, error) { 77 <-finished 78 controllerName = controllerNameArg 79 modelName = modelNameArg 80 return mockConn, nil 81 } 82 // have the mock clock only wait a microsecond 83 clock := &mockClock{wait: time.Microsecond} 84 // but tell it to wait five seconds 85 opener := modelcmd.NewTimeoutOpener(modelcmd.OpenFunc(open), clock, 5*time.Second) 86 conn, err := opener.Open(nil, "a-name", "b-name") 87 c.Assert(errors.Cause(err), gc.Equals, modelcmd.ErrConnTimedOut) 88 c.Assert(conn, gc.IsNil) 89 // check it was told to wait for 5 seconds 90 c.Assert(clock.duration, gc.Equals, 5*time.Second) 91 // tell the open func to continue now we have timed out 92 close(finished) 93 // wait until the connection has been closed 94 select { 95 case <-mockConn.closed: 96 // continue 97 case <-time.After(5 * time.Second): 98 c.Error("API connection was not closed.") 99 } 100 c.Assert(controllerName, gc.Equals, "a-name") 101 c.Assert(modelName, gc.Equals, "b-name") 102 } 103 104 // mockConnection will panic if anything but close is called. 105 type mockConnection struct { 106 api.Connection 107 108 closed chan struct{} 109 } 110 111 func (m *mockConnection) Close() error { 112 close(m.closed) 113 return nil 114 } 115 116 // mockClock will panic if anything but After is called 117 type mockClock struct { 118 clock.Clock 119 120 wait time.Duration 121 duration time.Duration 122 } 123 124 func (m *mockClock) After(duration time.Duration) <-chan time.Time { 125 m.duration = duration 126 return time.After(m.wait) 127 }