github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/containerbroker/broker_test.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package containerbroker_test 5 6 import ( 7 "github.com/juju/names/v5" 8 "github.com/juju/testing" 9 "go.uber.org/mock/gomock" 10 gc "gopkg.in/check.v1" 11 12 "github.com/juju/juju/api/agent/provisioner" 13 "github.com/juju/juju/api/base" 14 "github.com/juju/juju/container" 15 "github.com/juju/juju/container/broker" 16 "github.com/juju/juju/core/instance" 17 "github.com/juju/juju/core/life" 18 "github.com/juju/juju/core/network" 19 "github.com/juju/juju/environs" 20 "github.com/juju/juju/rpc/params" 21 "github.com/juju/juju/worker/containerbroker" 22 "github.com/juju/juju/worker/containerbroker/mocks" 23 ) 24 25 type brokerConfigSuite struct { 26 testing.IsolationSuite 27 } 28 29 var _ = gc.Suite(&brokerConfigSuite{}) 30 31 func (s *brokerConfigSuite) TestInvalidConfigValidate(c *gc.C) { 32 ctrl := gomock.NewController(c) 33 defer ctrl.Finish() 34 35 testcases := []struct { 36 description string 37 config containerbroker.Config 38 err string 39 }{ 40 { 41 description: "Test empty configuration", 42 config: containerbroker.Config{}, 43 err: "nil APICaller not valid", 44 }, 45 { 46 description: "Test no api caller", 47 config: containerbroker.Config{}, 48 err: "nil APICaller not valid", 49 }, 50 { 51 description: "Test no agent config", 52 config: containerbroker.Config{ 53 APICaller: mocks.NewMockAPICaller(ctrl), 54 }, 55 err: "nil AgentConfig not valid", 56 }, 57 { 58 description: "Test no machine lock", 59 config: containerbroker.Config{ 60 APICaller: mocks.NewMockAPICaller(ctrl), 61 AgentConfig: mocks.NewMockConfig(ctrl), 62 }, 63 err: "nil MachineLock not valid", 64 }, 65 { 66 description: "Test no broker func", 67 config: containerbroker.Config{ 68 APICaller: mocks.NewMockAPICaller(ctrl), 69 AgentConfig: mocks.NewMockConfig(ctrl), 70 MachineLock: mocks.NewMockLock(ctrl), 71 }, 72 err: "nil NewBrokerFunc not valid", 73 }, 74 { 75 description: "Test no state func", 76 config: containerbroker.Config{ 77 APICaller: mocks.NewMockAPICaller(ctrl), 78 AgentConfig: mocks.NewMockConfig(ctrl), 79 MachineLock: mocks.NewMockLock(ctrl), 80 NewBrokerFunc: func(broker.Config) (environs.InstanceBroker, error) { 81 return mocks.NewMockInstanceBroker(ctrl), nil 82 }, 83 }, 84 err: "nil NewStateFunc not valid", 85 }, 86 } 87 for i, test := range testcases { 88 c.Logf("%d %s", i, test.description) 89 err := test.config.Validate() 90 c.Assert(err, gc.ErrorMatches, test.err) 91 } 92 } 93 94 func (s *brokerConfigSuite) TestValidConfigValidate(c *gc.C) { 95 ctrl := gomock.NewController(c) 96 defer ctrl.Finish() 97 98 config := containerbroker.Config{ 99 APICaller: mocks.NewMockAPICaller(ctrl), 100 AgentConfig: mocks.NewMockConfig(ctrl), 101 MachineLock: mocks.NewMockLock(ctrl), 102 NewBrokerFunc: func(broker.Config) (environs.InstanceBroker, error) { 103 return mocks.NewMockInstanceBroker(ctrl), nil 104 }, 105 NewStateFunc: func(base.APICaller) containerbroker.State { 106 return mocks.NewMockState(ctrl) 107 }, 108 } 109 err := config.Validate() 110 c.Assert(err, gc.IsNil) 111 } 112 113 type trackerSuite struct { 114 testing.IsolationSuite 115 116 apiCaller *mocks.MockAPICaller 117 agentConfig *mocks.MockConfig 118 machineLock *mocks.MockLock 119 broker *mocks.MockInstanceBroker 120 state *mocks.MockState 121 machine *mocks.MockMachineProvisioner 122 123 machineTag names.MachineTag 124 } 125 126 var _ = gc.Suite(&trackerSuite{}) 127 128 func (s *trackerSuite) setup(c *gc.C) *gomock.Controller { 129 ctrl := gomock.NewController(c) 130 131 s.apiCaller = mocks.NewMockAPICaller(ctrl) 132 s.agentConfig = mocks.NewMockConfig(ctrl) 133 s.machineLock = mocks.NewMockLock(ctrl) 134 s.broker = mocks.NewMockInstanceBroker(ctrl) 135 s.state = mocks.NewMockState(ctrl) 136 s.machine = mocks.NewMockMachineProvisioner(ctrl) 137 138 s.machineTag = names.NewMachineTag("machine-0") 139 140 return ctrl 141 } 142 143 func (s *trackerSuite) TestNewTracker(c *gc.C) { 144 defer s.setup(c).Finish() 145 146 _, err := s.withScenario(c, 147 &broker.Config{ 148 Name: "instance-broker", 149 ContainerType: instance.LXD, 150 ManagerConfig: map[string]string{ 151 container.ConfigAvailabilityZone: "0", 152 }, 153 APICaller: s.state, 154 AgentConfig: s.agentConfig, 155 MachineTag: s.machineTag, 156 MachineLock: s.machineLock, 157 GetNetConfig: network.GetObservedNetworkConfig, 158 }, 159 s.expectMachineTag, 160 s.expectMachines, 161 s.expectSupportedContainers, 162 s.expectContainerConfig, 163 ) 164 c.Assert(err, gc.IsNil) 165 } 166 167 func (s *trackerSuite) TestNewTrackerWithNoMachines(c *gc.C) { 168 defer s.setup(c).Finish() 169 170 _, err := s.withScenario(c, 171 nil, 172 s.expectMachineTag, 173 s.expectNoMachines, 174 ) 175 c.Assert(err, gc.ErrorMatches, "expected 1 result, got 0") 176 } 177 178 func (s *trackerSuite) TestNewTrackerWithDeadMachines(c *gc.C) { 179 defer s.setup(c).Finish() 180 181 _, err := s.withScenario(c, 182 nil, 183 s.expectMachineTag, 184 s.expectDeadMachines, 185 ) 186 c.Assert(err, gc.ErrorMatches, "resource permanently unavailable") 187 } 188 189 func (s *trackerSuite) TestNewTrackerWithNoContainers(c *gc.C) { 190 defer s.setup(c).Finish() 191 192 _, err := s.withScenario(c, 193 nil, 194 s.expectMachineTag, 195 s.expectMachines, 196 s.expectNoSupportedContainers, 197 ) 198 c.Assert(err, gc.ErrorMatches, "resource permanently unavailable") 199 } 200 201 func (s *trackerSuite) TestNewTrackerWithNoDeterminedContainers(c *gc.C) { 202 defer s.setup(c).Finish() 203 204 _, err := s.withScenario(c, 205 nil, 206 s.expectMachineTag, 207 s.expectMachines, 208 s.expectNoDeterminedSupportedContainers, 209 ) 210 c.Assert(err, gc.ErrorMatches, "no container types determined") 211 } 212 213 func (s *trackerSuite) TestNewTrackerWithKVMContainers(c *gc.C) { 214 defer s.setup(c).Finish() 215 216 _, err := s.withScenario(c, 217 nil, 218 s.expectMachineTag, 219 s.expectMachines, 220 s.expectKVMSupportedContainers, 221 ) 222 c.Assert(err, gc.ErrorMatches, "resource permanently unavailable") 223 } 224 225 func (s *trackerSuite) withScenario(c *gc.C, expected *broker.Config, behaviours ...func()) (*containerbroker.Tracker, error) { 226 for _, b := range behaviours { 227 b() 228 } 229 return containerbroker.NewTracker(containerbroker.Config{ 230 APICaller: s.apiCaller, 231 AgentConfig: s.agentConfig, 232 MachineLock: s.machineLock, 233 NewBrokerFunc: func(config broker.Config) (environs.InstanceBroker, error) { 234 if expected != nil { 235 c.Check(config.Name, gc.Equals, expected.Name) 236 c.Check(config.ContainerType, gc.Equals, expected.ContainerType) 237 c.Check(config.ManagerConfig, gc.DeepEquals, expected.ManagerConfig) 238 c.Check(config.MachineTag, gc.Equals, expected.MachineTag) 239 } 240 return s.broker, nil 241 }, 242 NewStateFunc: func(base.APICaller) containerbroker.State { 243 return s.state 244 }, 245 }) 246 } 247 248 func (s *trackerSuite) expectMachineTag() { 249 s.agentConfig.EXPECT().Tag().Return(s.machineTag) 250 } 251 252 func (s *trackerSuite) expectMachines() { 253 s.state.EXPECT().Machines(s.machineTag).Return([]provisioner.MachineResult{{ 254 Machine: s.machine, 255 }}, nil) 256 s.machine.EXPECT().Life().Return(life.Alive) 257 } 258 259 func (s *trackerSuite) expectNoMachines() { 260 s.state.EXPECT().Machines(s.machineTag).Return([]provisioner.MachineResult{}, nil) 261 } 262 263 func (s *trackerSuite) expectDeadMachines() { 264 s.state.EXPECT().Machines(s.machineTag).Return([]provisioner.MachineResult{{ 265 Machine: s.machine, 266 }}, nil) 267 s.machine.EXPECT().Life().Return(life.Dead) 268 } 269 270 func (s *trackerSuite) expectSupportedContainers() { 271 s.machine.EXPECT().SupportedContainers().Return([]instance.ContainerType{ 272 instance.LXD, 273 }, true, nil) 274 } 275 276 func (s *trackerSuite) expectNoSupportedContainers() { 277 s.machine.EXPECT().SupportedContainers().Return([]instance.ContainerType{}, true, nil) 278 } 279 280 func (s *trackerSuite) expectNoDeterminedSupportedContainers() { 281 s.machine.EXPECT().SupportedContainers().Return([]instance.ContainerType{ 282 instance.LXD, 283 }, false, nil) 284 } 285 286 func (s *trackerSuite) expectKVMSupportedContainers() { 287 s.machine.EXPECT().SupportedContainers().Return([]instance.ContainerType{ 288 instance.KVM, 289 }, true, nil) 290 } 291 292 func (s *trackerSuite) expectContainerConfig() { 293 s.state.EXPECT().ContainerManagerConfig(params.ContainerManagerConfigParams{ 294 Type: instance.LXD, 295 }).Return(params.ContainerManagerConfig{ 296 ManagerConfig: make(map[string]string), 297 }, nil) 298 s.machine.EXPECT().AvailabilityZone().Return("0", nil) 299 }