gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/clh_test.go (about) 1 // Copyright (c) 2019 Ericsson Eurolab Deutschland G.m.b.H. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "fmt" 11 "net/http" 12 "os" 13 "path/filepath" 14 "reflect" 15 "testing" 16 17 "github.com/kata-containers/runtime/virtcontainers/device/config" 18 "github.com/kata-containers/runtime/virtcontainers/persist" 19 chclient "github.com/kata-containers/runtime/virtcontainers/pkg/cloud-hypervisor/client" 20 "github.com/kata-containers/runtime/virtcontainers/utils" 21 "github.com/pkg/errors" 22 "github.com/stretchr/testify/assert" 23 ) 24 25 const ( 26 FAIL = true 27 PASS = !FAIL 28 ) 29 30 func newClhConfig() (HypervisorConfig, error) { 31 32 setupClh() 33 34 if testClhPath == "" { 35 return HypervisorConfig{}, errors.New("hypervisor fake path is empty") 36 } 37 38 if testVirtiofsdPath == "" { 39 return HypervisorConfig{}, errors.New("hypervisor fake path is empty") 40 } 41 42 if _, err := os.Stat(testClhPath); os.IsNotExist(err) { 43 return HypervisorConfig{}, err 44 } 45 46 if _, err := os.Stat(testVirtiofsdPath); os.IsNotExist(err) { 47 return HypervisorConfig{}, err 48 } 49 50 return HypervisorConfig{ 51 KernelPath: testClhKernelPath, 52 ImagePath: testClhImagePath, 53 HypervisorPath: testClhPath, 54 NumVCPUs: defaultVCPUs, 55 BlockDeviceDriver: config.VirtioBlock, 56 MemorySize: defaultMemSzMiB, 57 DefaultBridges: defaultBridges, 58 DefaultMaxVCPUs: uint32(64), 59 SharedFS: config.VirtioFS, 60 VirtioFSCache: virtioFsCacheAlways, 61 VirtioFSDaemon: testVirtiofsdPath, 62 }, nil 63 } 64 65 type clhClientMock struct { 66 vmInfo chclient.VmInfo 67 } 68 69 func (c *clhClientMock) VmmPingGet(ctx context.Context) (chclient.VmmPingResponse, *http.Response, error) { 70 return chclient.VmmPingResponse{}, nil, nil 71 } 72 73 func (c *clhClientMock) ShutdownVMM(ctx context.Context) (*http.Response, error) { 74 return nil, nil 75 } 76 77 func (c *clhClientMock) CreateVM(ctx context.Context, vmConfig chclient.VmConfig) (*http.Response, error) { 78 c.vmInfo.State = clhStateCreated 79 return nil, nil 80 } 81 82 //nolint:golint 83 func (c *clhClientMock) VmInfoGet(ctx context.Context) (chclient.VmInfo, *http.Response, error) { 84 return c.vmInfo, nil, nil 85 } 86 87 func (c *clhClientMock) BootVM(ctx context.Context) (*http.Response, error) { 88 c.vmInfo.State = clhStateRunning 89 return nil, nil 90 } 91 92 //nolint:golint 93 func (c *clhClientMock) VmResizePut(ctx context.Context, vmResize chclient.VmResize) (*http.Response, error) { 94 return nil, nil 95 } 96 97 //nolint:golint 98 func (c *clhClientMock) VmAddDevicePut(ctx context.Context, vmAddDevice chclient.VmAddDevice) (*http.Response, error) { 99 return nil, nil 100 } 101 102 //nolint:golint 103 func (c *clhClientMock) VmAddDiskPut(ctx context.Context, diskConfig chclient.DiskConfig) (*http.Response, error) { 104 return nil, nil 105 } 106 107 func TestCloudHypervisorAddVSock(t *testing.T) { 108 assert := assert.New(t) 109 clh := cloudHypervisor{} 110 111 clh.addVSock(1, "path") 112 assert.Equal(clh.vmconfig.Vsock.Cid, int64(1)) 113 assert.Equal(clh.vmconfig.Vsock.Sock, "path") 114 } 115 116 // Check addNet appends to the network config list new configurations. 117 // Check that the elements in the list has the correct values 118 func TestCloudHypervisorAddNetCheckNetConfigListValues(t *testing.T) { 119 macTest := "00:00:00:00:00" 120 tapPath := "/path/to/tap" 121 122 assert := assert.New(t) 123 124 clh := cloudHypervisor{} 125 126 e := &VethEndpoint{} 127 e.NetPair.TAPIface.HardAddr = macTest 128 e.NetPair.TapInterface.TAPIface.Name = tapPath 129 130 err := clh.addNet(e) 131 assert.Nil(err) 132 133 assert.Equal(len(clh.vmconfig.Net), 1) 134 if err == nil { 135 assert.Equal(clh.vmconfig.Net[0].Mac, macTest) 136 assert.Equal(clh.vmconfig.Net[0].Tap, tapPath) 137 } 138 139 err = clh.addNet(e) 140 assert.Nil(err) 141 142 assert.Equal(len(clh.vmconfig.Net), 2) 143 if err == nil { 144 assert.Equal(clh.vmconfig.Net[1].Mac, macTest) 145 assert.Equal(clh.vmconfig.Net[1].Tap, tapPath) 146 } 147 } 148 149 // Check addNet with valid values, and fail with invalid values 150 // For Cloud Hypervisor only tap is be required 151 func TestCloudHypervisorAddNetCheckEnpointTypes(t *testing.T) { 152 assert := assert.New(t) 153 154 tapPath := "/path/to/tap" 155 156 validVeth := &VethEndpoint{} 157 validVeth.NetPair.TapInterface.TAPIface.Name = tapPath 158 159 type args struct { 160 e Endpoint 161 } 162 tests := []struct { 163 name string 164 args args 165 wantErr bool 166 }{ 167 {"TapEndpoint", args{e: &TapEndpoint{}}, true}, 168 {"Empty VethEndpoint", args{e: &VethEndpoint{}}, true}, 169 {"Valid VethEndpoint", args{e: validVeth}, false}, 170 } 171 for _, tt := range tests { 172 t.Run(tt.name, func(t *testing.T) { 173 clh := &cloudHypervisor{} 174 if err := clh.addNet(tt.args.e); (err != nil) != tt.wantErr { 175 t.Errorf("cloudHypervisor.addNet() error = %v, wantErr %v", err, tt.wantErr) 176 177 } else if err == nil { 178 assert.Equal(clh.vmconfig.Net[0].Tap, tapPath) 179 } 180 }) 181 } 182 } 183 184 func TestCloudHypervisorBootVM(t *testing.T) { 185 clh := &cloudHypervisor{} 186 clh.APIClient = &clhClientMock{} 187 var ctx context.Context 188 if err := clh.bootVM(ctx); err != nil { 189 t.Errorf("cloudHypervisor.bootVM() error = %v", err) 190 } 191 } 192 193 func TestCloudHypervisorCleanupVM(t *testing.T) { 194 assert := assert.New(t) 195 store, err := persist.GetDriver() 196 assert.NoError(err, "persist.GetDriver() unexpected error") 197 198 clh := &cloudHypervisor{ 199 store: store, 200 } 201 202 err = clh.cleanupVM(true) 203 assert.Error(err, "persist.GetDriver() expected error") 204 205 clh.id = "cleanVMID" 206 207 err = clh.cleanupVM(true) 208 assert.NoError(err, "persist.GetDriver() unexpected error") 209 210 dir := filepath.Join(clh.store.RunVMStoragePath(), clh.id) 211 os.MkdirAll(dir, os.ModePerm) 212 213 err = clh.cleanupVM(false) 214 assert.NoError(err, "persist.GetDriver() unexpected error") 215 216 _, err = os.Stat(dir) 217 assert.Error(err, "dir should not exist %s", dir) 218 219 assert.True(os.IsNotExist(err), "persist.GetDriver() unexpected error") 220 } 221 222 func TestClhCreateSandbox(t *testing.T) { 223 assert := assert.New(t) 224 225 clhConfig, err := newClhConfig() 226 assert.NoError(err) 227 228 store, err := persist.GetDriver() 229 assert.NoError(err) 230 231 clh := &cloudHypervisor{ 232 config: clhConfig, 233 store: store, 234 } 235 236 sandbox := &Sandbox{ 237 ctx: context.Background(), 238 id: "testSandbox", 239 config: &SandboxConfig{ 240 HypervisorConfig: clhConfig, 241 }, 242 } 243 244 err = clh.createSandbox(context.Background(), sandbox.id, NetworkNamespace{}, &sandbox.config.HypervisorConfig, false) 245 assert.NoError(err) 246 assert.Exactly(clhConfig, clh.config) 247 } 248 249 func TestClooudHypervisorStartSandbox(t *testing.T) { 250 assert := assert.New(t) 251 clhConfig, err := newClhConfig() 252 assert.NoError(err) 253 254 store, err := persist.GetDriver() 255 assert.NoError(err) 256 257 clh := &cloudHypervisor{ 258 config: clhConfig, 259 APIClient: &clhClientMock{}, 260 virtiofsd: &virtiofsdMock{}, 261 store: store, 262 } 263 264 err = clh.startSandbox(10) 265 assert.NoError(err) 266 } 267 268 func TestCloudHypervisorResizeMemory(t *testing.T) { 269 assert := assert.New(t) 270 clhConfig, err := newClhConfig() 271 type args struct { 272 reqMemMB uint32 273 memoryBlockSizeMB uint32 274 } 275 tests := []struct { 276 name string 277 args args 278 expectedMemDev memoryDevice 279 wantErr bool 280 }{ 281 {"Resize to zero", args{0, 128}, memoryDevice{probe: false, sizeMB: 0}, FAIL}, 282 {"Resize to aligned size", args{clhConfig.MemorySize + 128, 128}, memoryDevice{probe: false, sizeMB: 128}, PASS}, 283 {"Resize to aligned size", args{clhConfig.MemorySize + 129, 128}, memoryDevice{probe: false, sizeMB: 256}, PASS}, 284 {"Resize to NOT aligned size", args{clhConfig.MemorySize + 125, 128}, memoryDevice{probe: false, sizeMB: 128}, PASS}, 285 } 286 for _, tt := range tests { 287 t.Run(tt.name, func(t *testing.T) { 288 assert.NoError(err) 289 clh := cloudHypervisor{} 290 291 mockClient := &clhClientMock{} 292 mockClient.vmInfo.Config.Memory.Size = int64(utils.MemUnit(clhConfig.MemorySize) * utils.MiB) 293 mockClient.vmInfo.Config.Memory.HotplugSize = int64(40 * utils.GiB.ToBytes()) 294 295 clh.APIClient = mockClient 296 clh.config = clhConfig 297 298 newMem, memDev, err := clh.resizeMemory(tt.args.reqMemMB, tt.args.memoryBlockSizeMB, false) 299 300 if (err != nil) != tt.wantErr { 301 t.Errorf("cloudHypervisor.resizeMemory() error = %v, expected to fail = %v", err, tt.wantErr) 302 return 303 } 304 305 if err != nil { 306 return 307 } 308 309 expectedMem := clhConfig.MemorySize + uint32(tt.expectedMemDev.sizeMB) 310 311 if newMem != expectedMem { 312 t.Errorf("cloudHypervisor.resizeMemory() got = %+v, want %+v", newMem, expectedMem) 313 } 314 315 if !reflect.DeepEqual(memDev, tt.expectedMemDev) { 316 t.Errorf("cloudHypervisor.resizeMemory() got = %+v, want %+v", memDev, tt.expectedMemDev) 317 } 318 }) 319 } 320 } 321 322 func TestCheckVersion(t *testing.T) { 323 clh := &cloudHypervisor{} 324 assert := assert.New(t) 325 testcases := []struct { 326 name string 327 major int 328 minor int 329 pass bool 330 }{ 331 { 332 name: "minor lower than supported version", 333 major: supportedMajorVersion, 334 minor: 2, 335 pass: false, 336 }, 337 { 338 name: "minor equal to supported version", 339 major: supportedMajorVersion, 340 minor: supportedMinorVersion, 341 pass: true, 342 }, 343 { 344 name: "major exceeding supported version", 345 major: 1, 346 minor: supportedMinorVersion, 347 pass: true, 348 }, 349 } 350 for _, tc := range testcases { 351 clh.version = CloudHypervisorVersion{ 352 Major: tc.major, 353 Minor: tc.minor, 354 Revision: 0, 355 } 356 err := clh.checkVersion() 357 msg := fmt.Sprintf("test: %+v, clh.version: %v, result: %v", tc, clh.version, err) 358 if tc.pass { 359 assert.NoError(err, msg) 360 } else { 361 assert.Error(err, msg) 362 } 363 } 364 } 365 366 func TestCloudHypervisorHotplugBlockDevice(t *testing.T) { 367 assert := assert.New(t) 368 369 clhConfig, err := newClhConfig() 370 assert.NoError(err) 371 372 clh := &cloudHypervisor{} 373 clh.config = clhConfig 374 clh.APIClient = &clhClientMock{} 375 376 clh.config.BlockDeviceDriver = config.VirtioBlock 377 err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: false}) 378 assert.NoError(err, "Hotplug disk block device expected no error") 379 380 err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: true}) 381 assert.Error(err, "Hotplug pmem block device expected error") 382 383 clh.config.BlockDeviceDriver = config.VirtioSCSI 384 err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: false}) 385 assert.Error(err, "Hotplug block device not using 'virtio-blk' expected error") 386 }