// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
using System.Management;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO;
using log4net;
using HypervResource;
using CloudStack.Plugin.AgentShell;
using System.Collections.Generic;
using NSubstitute;
using System.Web.Http;
using Xunit;
namespace ServerResource.Tests
{
public class HypervResourceController1Test
{
protected static string testCifsUrl = AgentSettings.Default.testCifsUrl;
protected static string testCifsPath = AgentSettings.Default.testCifsPath;
protected static String testPrimaryDataStoreHost = HypervResourceController.config.StorageIpAddress;
protected static String testS3TemplateName = AgentSettings.Default.testS3TemplateName;
protected static String testCifsTemplateName = AgentSettings.Default.testS3TemplateName;
protected static String testSystemVMTemplateName = AgentSettings.Default.testSystemVMTemplateName;
protected static String testSystemVMTemplateNameNoExt = AgentSettings.Default.testSystemVMTemplateNameNoExt;
protected static String testLocalStoreUUID = "5fe2bad3-d785-394e-9949-89786b8a63d2";
protected static String testLocalStorePath = Path.Combine(AgentSettings.Default.hyperv_plugin_root, "var", "test", "storagepool");
protected static String testSecondaryStoreLocalPath = Path.Combine(AgentSettings.Default.hyperv_plugin_root, "var", "test", "secondary");
// TODO: differentiate between NFS and HTTP template URLs.
protected static String testSampleTemplateUUID = "TestCopiedLocalTemplate.vhdx";
protected static String testSampleTemplateURL = testSampleTemplateUUID;
// test volumes are both a minimal size vhdx. Changing the extension to .vhd makes on corrupt.
protected static String testSampleVolumeWorkingUUID = "TestVolumeLegit.vhdx";
protected static String testSampleVolumeCorruptUUID = "TestVolumeCorrupt.vhd";
protected static String testSampleVolumeTempUUID = "TestVolumeTemp.vhdx";
protected static String testSampleVolumeTempUUIDNoExt = "TestVolumeTemp";
protected static String testSampleVolumeWorkingURIJSON;
protected static String testSampleVolumeCorruptURIJSON;
protected static String testSampleVolumeTempURIJSON;
protected static String testSampleTemplateURLJSON;
protected static String testLocalStorePathJSON;
protected static IWmiCallsV2 wmiCallsV2;
private static ILog s_logger = LogManager.GetLogger(typeof(HypervResourceController1Test));
///
/// Test WmiCalls to which incoming HTTP POST requests are dispatched.
///
/// TODO: revise beyond first approximation
/// First approximation is a quick port of the existing Java tests for Hyper-V server resource.
/// A second approximation would use the AgentShell settings files directly.
/// A third approximation would look to invoke ServerResource methods via an HTTP request
///
public HypervResourceController1Test()
{
wmiCallsV2 = Substitute.For();
//AgentService.ConfigServerResource();
HypervResourceController.config.PrivateMacAddress = AgentSettings.Default.private_mac_address;
HypervResourceController.config.PrivateNetmask = AgentSettings.Default.private_ip_netmask;
HypervResourceController.config.StorageIpAddress = HypervResourceController.config.PrivateIpAddress;
HypervResourceController.config.StorageMacAddress = HypervResourceController.config.PrivateMacAddress;
HypervResourceController.config.StorageNetmask = HypervResourceController.config.PrivateNetmask;
// Used to create existing StoragePool in preparation for the ModifyStoragePool
testLocalStoreUUID = AgentSettings.Default.local_storage_uuid.ToString();
// Make sure secondary store is available.
string fullPath = Path.GetFullPath(testSecondaryStoreLocalPath);
s_logger.Info("Test secondary storage in " + fullPath);
DirectoryInfo testSecondarStoreDir = new DirectoryInfo(fullPath);
if (!testSecondarStoreDir.Exists)
{
try
{
testSecondarStoreDir.Create();
}
catch (System.IO.IOException ex)
{
throw new NotImplementedException("Need to be able to create the folder " + testSecondarStoreDir.FullName + " failed due to " + ex.Message);
}
}
// Convert to secondary storage string to canonical path
testSecondaryStoreLocalPath = testSecondarStoreDir.FullName;
AgentSettings.Default.local_secondary_storage_path = testSecondaryStoreLocalPath;
// Make sure local primary storage is available
DirectoryInfo testPoolDir = new DirectoryInfo(testLocalStorePath);
//Assert.True(testPoolDir.Exists, "To simulate local file system Storage Pool, you need folder at " + testPoolDir.FullName);
// Convert to local primary storage string to canonical path
testLocalStorePath = testPoolDir.FullName;
AgentSettings.Default.local_storage_path = testLocalStorePath;
// Clean up old test files in local storage folder
FileInfo testVolWorks = new FileInfo(Path.Combine(testLocalStorePath, testSampleVolumeWorkingUUID));
// Assert.True(testVolWorks.Exists, "Create a working virtual disk at " + testVolWorks.FullName);
testSampleTemplateURLJSON = JsonConvert.SerializeObject(testSampleTemplateUUID);
s_logger.Info("Created " + testSampleTemplateURLJSON + " in local storage.");
// Capture other JSON encoded paths
testSampleVolumeWorkingURIJSON = Newtonsoft.Json.JsonConvert.SerializeObject(testVolWorks.FullName);
testLocalStorePathJSON = JsonConvert.SerializeObject(testLocalStorePath);
// TODO: may need to initialise the server resource in future.
// s_hypervresource.initialize();
// Verify sample template is in place storage pool
s_logger.Info("setUp complete, sample StoragePool at " + testLocalStorePathJSON
+ " sample template at " + testSampleTemplateURLJSON);
}
private String CreateTestDiskImageFromExistingImage(FileInfo srcFile,
String dstPath,
String dstFileName)
{
var newFullname = Path.Combine(dstPath, dstFileName);
var newFileInfo = new FileInfo(newFullname);
if (!newFileInfo.Exists)
{
newFileInfo = srcFile.CopyTo(newFullname);
}
newFileInfo.Refresh();
Assert.True(newFileInfo.Exists, "Attempted to create " + newFullname + " from " + newFileInfo.FullName);
return JsonConvert.SerializeObject(newFileInfo.FullName);
}
[Fact]
public void TestCreateCommand()
{
DirectoryInfo localStorePath = new DirectoryInfo(testLocalStorePath);
if (!localStorePath.Exists)
{
try
{
localStorePath.Create();
}
catch (System.IO.IOException ex)
{
throw new NotImplementedException("Need to be able to create the folder " + localStorePath.FullName + " failed due to " + ex.Message);
}
}
FileInfo sampleTemplateFile = new FileInfo(Path.Combine(testLocalStorePath, testSampleTemplateUUID));
if (!sampleTemplateFile.Exists)
{
//Create a file to write to.
using (StreamWriter sw = sampleTemplateFile.CreateText())
{
sw.WriteLine("This is fake template file for test");
}
}
var counter = 0;
wmiCallsV2.When(x => x.CreateDynamicVirtualHardDisk(Arg.Any(), Arg.Any())).Do(x => counter++);
// TODO: Need sample to update the test.
// Arrange
String createCmd = "{\"volId\":10,\"pool\":{\"id\":201,\"uuid\":\"" + testLocalStoreUUID + "\",\"host\":\"" + HypervResourceController.config.StorageIpAddress + "\"" +
",\"path\":" + testLocalStorePathJSON + ",\"port\":0,\"type\":\"Filesystem\"},\"diskCharacteristics\":{\"size\":0," +
"\"tags\":[],\"type\":\"ROOT\",\"name\":\"ROOT-9\",\"useLocalStorage\":true,\"recreatable\":true,\"diskOfferingId\":11," +
"\"volumeId\":10,\"hyperType\":\"Hyperv\"},\"templateUrl\":" + testSampleTemplateURLJSON + ",\"contextMap\":{},\"wait\":0}";
dynamic jsonCreateCmd = JsonConvert.DeserializeObject(createCmd);
HypervResourceController rsrcServer = new HypervResourceController();
HypervResourceController.wmiCallsV2 = wmiCallsV2;
Assert.True(Directory.Exists(testLocalStorePath), testLocalStorePath + " does not exist ");
string filePath = Path.Combine(testLocalStorePath, (string)JsonConvert.DeserializeObject(testSampleTemplateURLJSON));
Assert.True(File.Exists(filePath), "The template we make volumes from is missing from path " + filePath);
int fileCount = Directory.GetFiles(testLocalStorePath).Length;
s_logger.Debug(" test local store has " + fileCount + "files");
// Act
// Test requires there to be a template at the tempalteUrl, which is its location in the local file system.
dynamic jsonResult = rsrcServer.CreateCommand(jsonCreateCmd);
s_logger.Debug("CreateDynamicVirtualHardDisk method is called " + counter + " times");
//Assert.Equal(counter, 1);
JObject ansAsProperty2 = jsonResult[0];
dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.CreateAnswer);
Assert.NotNull(ans);
Assert.True((bool)ans.result, "Failed to CreateCommand due to " + (string)ans.result);
Assert.Equal(Directory.GetFiles(testLocalStorePath).Length, fileCount + 1);
FileInfo newFile = new FileInfo((string)ans.volume.path);
Assert.True(newFile.Length > 0, "The new file should have a size greater than zero");
newFile.Delete();
sampleTemplateFile.Delete();
}
[Fact]
public void TestDestroyCommand()
{
testSampleVolumeTempURIJSON = "\"storagepool\"";
// Arrange
String destoryCmd = //"{\"volume\":" + getSampleVolumeObjectTO() + "}";
"{\"volume\":{\"name\":\"" + testSampleVolumeTempUUIDNoExt
+ "\",\"storagePoolType\":\"Filesystem\","
+ "\"mountPoint\":"
+ testLocalStorePathJSON
+ ",\"path\":" + testSampleVolumeTempURIJSON
+ ",\"storagePoolUuid\":\"" + testLocalStoreUUID
+ "\","
+ "\"type\":\"ROOT\",\"id\":9,\"size\":0}}";
ImageManagementService imgmgr = new ImageManagementService();
wmiCallsV2.GetImageManagementService().Returns(imgmgr);
HypervResourceController rsrcServer = new HypervResourceController();
HypervResourceController.wmiCallsV2 = wmiCallsV2;
dynamic jsonDestoryCmd = JsonConvert.DeserializeObject(destoryCmd);
// Act
dynamic destoryAns = rsrcServer.DestroyCommand(jsonDestoryCmd);
// Assert
JObject ansAsProperty2 = destoryAns[0];
dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.Answer);
String path = jsonDestoryCmd.volume.path;
Assert.True((bool)ans.result, "DestroyCommand did not succeed " + ans.details);
Assert.True(!File.Exists(path), "Failed to delete file " + path);
}
[Fact]
public void TestStartCommand()
{
ComputerSystem system = new ComputerSystem();
wmiCallsV2.DeployVirtualMachine(Arg.Any