From a27899aae12ceaf39f662864c87e164af7e47ee2 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Mon, 28 Oct 2013 10:47:04 +0530 Subject: [PATCH] Hyperv unit tests for the agent. Unit tests are written using NSubstitute and XUnit and they test the create, stop and start commands in the agent. --- .../hyperv/DotNet/ServerResource/.gitignore | 1 + .../DotNet/ServerResource/.nuget/NuGet.Config | 6 + .../ServerResource/.nuget/NuGet.targets | 136 ++++++++ .../AgentShell/AgentSettings.Designer.cs | 2 +- .../AgentShell/AgentSettings.settings | 2 +- .../AgentShell/AgentShell.csproj | 9 + .../ServerResource/AgentShell/packages.config | 3 + .../HypervResource/HypervResource.csproj | 4 +- .../HypervResourceController.cs | 33 +- .../HypervResource/IWmiCalls.cs | 44 +++ .../HypervResource/IWmiCallsV2.cs | 22 ++ .../ServerResource/HypervResource/WmiCalls.cs | 103 +++--- .../HypervResource/WmiCallsV2.cs | 21 +- .../HypervResource/packages.config | 2 + .../ServerResource.Tests/App.config | 29 +- .../HypervResourceController1Test.cs | 298 ++++++++++++++++++ .../HypervResourceControllerTest.cs | 209 ++++++------ .../ServerResource.Tests.csproj | 15 + .../ServerResource.Tests/packages.config | 3 + .../WmiWrappers/WmiWrappers.csproj | 20 +- plugins/hypervisors/hyperv/buildagent.sh | 2 +- .../storagepool/TestCopiedLocalTemplate.vhdx | 1 + 22 files changed, 774 insertions(+), 191 deletions(-) create mode 100644 plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.Config create mode 100644 plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets create mode 100644 plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCalls.cs create mode 100644 plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs create mode 100644 plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceController1Test.cs mode change 100644 => 100755 plugins/hypervisors/hyperv/buildagent.sh create mode 100644 plugins/hypervisors/hyperv/var/test/storagepool/TestCopiedLocalTemplate.vhdx diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore b/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore index cf9cb855bd8..99afc0b89f2 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore @@ -5,4 +5,5 @@ WmiWrappers/bin/* AgentShell/bin/* ServerResource*/bin/* *.user +!.nuget/ diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.Config b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.Config new file mode 100644 index 00000000000..6a318ad9b75 --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets new file mode 100644 index 00000000000..d0ebc7535f3 --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/.nuget/NuGet.targets @@ -0,0 +1,136 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + false + + + false + + + true + + + false + + + + + + + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) + + + + + $(SolutionDir).nuget + packages.config + + + + + $(NuGetToolsPath)\NuGet.exe + @(PackageSource) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 $(NuGetExePath) + + $(TargetDir.Trim('\\')) + + -RequireConsent + -NonInteractive + + "$(SolutionDir) " + "$(SolutionDir)" + + + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) + $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + + + + RestorePackages; + $(BuildDependsOn); + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.Designer.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.Designer.cs index 281f1693649..ae2bbbcfe76 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.Designer.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.Designer.cs @@ -192,7 +192,7 @@ namespace CloudStack.Plugin.AgentShell { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("..\\..\\..\\..\\..\\")] + [global::System.Configuration.DefaultSettingValueAttribute("../../../../../")] public string hyperv_plugin_root { get { return ((string)(this["hyperv_plugin_root"])); diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.settings b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.settings index 435b8e0e35a..695ebe2ce99 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.settings +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentSettings.settings @@ -60,7 +60,7 @@ 4294967296 - ..\..\..\..\..\ + ../../../../../ e:\ diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj index 2a3c0db1c78..a813124b1ed 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj @@ -54,6 +54,9 @@ true + + ..\packages\AWSSDK.1.5.23.0\lib\AWSSDK.dll + ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll @@ -63,6 +66,9 @@ ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + + ..\packages\NSubstitute.1.6.1.0\lib\NET40\NSubstitute.dll + @@ -83,6 +89,9 @@ + + ..\packages\xunit.1.9.2\lib\net20\xunit.dll + diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config index f5f47e64a47..fb1c846ad3c 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config @@ -1,5 +1,6 @@  + @@ -7,4 +8,6 @@ + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj index dbd7b151341..ed22a7a4ef7 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj @@ -76,6 +76,8 @@ + + @@ -100,4 +102,4 @@ --> - + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs index 2d61a6c8e2d..bdb0eae62b0 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs @@ -118,6 +118,9 @@ namespace HypervResource { } + public IWmiCalls wmiCalls { get; set; } + public IWmiCallsV2 wmiCallsV2 { get; set;} + // GET api/HypervResource public string Get() { @@ -152,7 +155,7 @@ namespace HypervResource share.uri = new Uri(uriStr); string systemVmIso = (string)cmd.systemVmIso; - string defaultDataPath = WmiCallsV2.GetDefaultDataRoot(); + string defaultDataPath = wmiCallsV2.GetDefaultDataRoot(); string isoPath = Path.Combine(defaultDataPath, Path.GetFileName(systemVmIso)); if (!File.Exists(isoPath)) { @@ -195,7 +198,7 @@ namespace HypervResource { string vmName = (string)cmd.vmName; string isoPath = "\\\\10.102.192.150\\SMB-Share\\202-2-305ed1f7-1be8-345e-86c3-a976f7f57f10.iso"; - WmiCalls.AttachIso(vmName, isoPath); + wmiCalls.AttachIso(vmName, isoPath); result = true; } @@ -288,7 +291,7 @@ namespace HypervResource string vmName = (string)cmd.vmName; if (!string.IsNullOrEmpty(vmName) && File.Exists(path)) { - var imgmgr = WmiCalls.GetImageManagementService(); + var imgmgr = wmiCalls.GetImageManagementService(); var returncode = imgmgr.Unmount(path); if (returncode != ReturnCode.Completed) { @@ -367,7 +370,7 @@ namespace HypervResource newVolName = cmd.diskCharacteristics.name; newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower()); // TODO: how do you specify format as VHD or VHDX? - WmiCalls.CreateDynamicVirtualHardDisk(disksize, newVolPath); + wmiCalls.CreateDynamicVirtualHardDisk(disksize, newVolPath); if (File.Exists(newVolPath)) { result = true; @@ -632,7 +635,7 @@ namespace HypervResource string state = null; // TODO: Look up the VM, convert Hyper-V state to CloudStack version. - var sys = WmiCalls.GetComputerSystem(vmName); + var sys = wmiCalls.GetComputerSystem(vmName); if (sys == null) { details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName; @@ -831,7 +834,7 @@ namespace HypervResource try { - WmiCalls.DeployVirtualMachine(cmd, systemVmIso); + wmiCalls.DeployVirtualMachine(cmd, systemVmIso); result = true; } catch (Exception wmiEx) @@ -863,7 +866,7 @@ namespace HypervResource try { - WmiCalls.DestroyVm(cmd); + wmiCalls.DestroyVm(cmd); result = true; } catch (Exception wmiEx) @@ -962,13 +965,13 @@ namespace HypervResource var vmsToInspect = new List(); foreach (var vmName in vmNames) { - var sys = WmiCalls.GetComputerSystem(vmName); + var sys = wmiCalls.GetComputerSystem(vmName); if (sys == null) { logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames); continue; } - var sysInfo = WmiCalls.GetVmSettings(sys); + var sysInfo = wmiCalls.GetVmSettings(sys); vmsToInspect.Add(sysInfo.Path); } @@ -982,7 +985,7 @@ namespace HypervResource }; System.Management.ManagementBaseObject[] sysSummary; - var vmsvc = WmiCalls.GetVirtualisationSystemManagementService(); + var vmsvc = wmiCalls.GetVirtualisationSystemManagementService(); System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray(); vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary); @@ -1315,8 +1318,8 @@ namespace HypervResource try { long hostId = (long)cmd.hostId; - WmiCalls.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); - WmiCalls.GetProcessorUsageInfo(out cpuUtilization); + wmiCalls.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); + wmiCalls.GetProcessorUsageInfo(out cpuUtilization); // TODO: can we assume that the host has only one adaptor? string tmp; @@ -1379,12 +1382,12 @@ namespace HypervResource // Detect CPUs, speed, memory uint cores; uint mhz; - WmiCalls.GetProcessorResources(out cores, out mhz); + wmiCalls.GetProcessorResources(out cores, out mhz); strtRouteCmd.cpus = cores; strtRouteCmd.speed = mhz; ulong memoryKBs; ulong freeMemoryKBs; - WmiCalls.GetMemoryResources(out memoryKBs, out freeMemoryKBs); + wmiCalls.GetMemoryResources(out memoryKBs, out freeMemoryKBs); strtRouteCmd.memory = memoryKBs * 1024; // Convert to bytes // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx @@ -1395,7 +1398,7 @@ namespace HypervResource // Read the localStoragePath for virtual disks from the Hyper-V configuration // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx // for discussion of Hyper-V file locations paths. - string localStoragePath = WmiCalls.GetDefaultVirtualDiskFolder(); + string localStoragePath = wmiCalls.GetDefaultVirtualDiskFolder(); if (localStoragePath != null) { // GUID arbitrary. Host agents deals with storage pool in terms of localStoragePath. diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCalls.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCalls.cs new file mode 100644 index 00000000000..2f48f6a210f --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCalls.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION; +using System.Management; + +namespace HypervResource +{ + public interface IWmiCalls + { + ComputerSystem CreateVM(string name, long memory_mb, int vcpus); + void DestroyVm(string displayName); + void DestroyVm(dynamic jsonObj); + void patchSystemVmIso(String vmName, String systemVmIso); + void AttachIso(string displayName, string iso); + void GetProcessorResources(out uint cores, out uint mhz); + void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs); + string GetDefaultVirtualDiskFolder(); + ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso); + ComputerSystem GetComputerSystem(string displayName); + void GetProcessorUsageInfo(out double cpuUtilization); + SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac, string vlan); + ManagementPath AddDiskDriveToVm(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType); + void SetState(ComputerSystem vm, ushort requiredState); + bool DeleteSwitchPort(string elementName); + VLANEndpointSettingData GetVlanEndpointSettings(VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath); + VirtualSwitch GetExternalVirtSwitch(); + VirtualSwitchManagementService GetVirtualSwitchManagementService(); + void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path); + ImageManagementService GetImageManagementService(); + VirtualSystemManagementService GetVirtualisationSystemManagementService(); + List GetVmElementNames(); + ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings); + MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings); + ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr); + ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings); + SwitchPort[] GetSwitchPorts(ComputerSystem vm); + SwitchPort GetSwitchPort(SyntheticEthernetPort nic); + SyntheticEthernetPortSettingData[] GetEthernetPorts(ComputerSystem vm); + VirtualSystemSettingData GetVmSettings(ComputerSystem vm); + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs new file mode 100644 index 00000000000..b3695c71bdd --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; +using System.Management; + +namespace HypervResource +{ + public interface IWmiCallsV2 + { + ComputerSystem AddUserData(ComputerSystem vm, string userData); + void DeleteHostKvpItem(ComputerSystem vm, string key); + VirtualSystemManagementService GetVirtualisationSystemManagementService(); + ComputerSystem GetComputerSystem(string displayName); + List GetVmElementNames(); + VirtualSystemSettingData GetVmSettings(ComputerSystem vm); + KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings); + string GetDefaultDataRoot(); + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs index 65b726e9e5c..1d8d58a915c 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs @@ -30,8 +30,13 @@ using System.IO; namespace HypervResource { - public class WmiCalls + public class WmiCalls : IWmiCalls { + private IWmiCallsV2 wmiCallsV2; + public WmiCalls() + { + wmiCallsV2 = new WmiCallsV2(); + } public static void Initialize() { // Trigger assembly load into curren appdomain @@ -42,7 +47,7 @@ namespace HypervResource /// /// Returns ComputerSystem lacking any NICs and VOLUMEs /// - public static ComputerSystem CreateVM(string name, long memory_mb, int vcpus) + public ComputerSystem CreateVM(string name, long memory_mb, int vcpus) { // Obtain controller for Hyper-V virtualisation subsystem VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); @@ -84,7 +89,7 @@ namespace HypervResource /// /// /// - public static SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac, string vlan) + public SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac, string vlan) { logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name); @@ -158,7 +163,8 @@ namespace HypervResource /// /// Create new VM. By default we start it. /// - public static ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso) + + public ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso) { var vmInfo = jsonObj.vm; string vmName = vmInfo.name; @@ -209,7 +215,7 @@ namespace HypervResource // Create vm carcase logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize); - var newVm = WmiCalls.CreateVM(vmName, memSize, vcpus); + var newVm = CreateVM(vmName, memSize, vcpus); foreach (var diskDrive in diskDrives) { @@ -319,12 +325,11 @@ namespace HypervResource // pass the boot args for the VM using KVP component. // We need to pass the boot args to system vm's to get them configured with cloudstack configuration. // Add new user data - var vm = WmiCallsV2.GetComputerSystem(vmName); + var vm = wmiCallsV2.GetComputerSystem(vmName); if (bootArgs != null) { - String bootargs = bootArgs; - WmiCallsV2.AddUserData(vm, bootargs); + wmiCallsV2.AddUserData(vm, bootargs); } // call patch systemvm iso only for systemvms @@ -352,11 +357,13 @@ namespace HypervResource /// this method is to add a dvd drive and attach the systemvm iso. /// - public static void patchSystemVmIso(String vmName, String systemVmIso) + + public void patchSystemVmIso(String vmName, String systemVmIso) { - ComputerSystem vmObject = WmiCalls.GetComputerSystem(vmName); + ComputerSystem vmObject = GetComputerSystem(vmName); AddDiskDriveToVm(vmObject, "", "1", IDE_ISO_DRIVE); - WmiCalls.AttachIso(vmName, systemVmIso); + + AttachIso(vmName, systemVmIso); } /// @@ -365,7 +372,7 @@ namespace HypervResource /// /// /// IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE - public static ManagementPath AddDiskDriveToVm(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType) + public ManagementPath AddDiskDriveToVm(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType) { logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", vm.ElementName, @@ -406,7 +413,7 @@ namespace HypervResource return newDrivePath; } - private static ManagementPath AttachNewDriveToVm(ComputerSystem vm, string cntrllerAddr, string driveType) + private ManagementPath AttachNewDriveToVm(ComputerSystem vm, string cntrllerAddr, string driveType) { // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. VirtualSystemSettingData vmSettings = GetVmSettings(vm); @@ -453,7 +460,7 @@ namespace HypervResource /// /// /// - private static void AttachIsoToVm(ComputerSystem vm, string isoPath) + private void AttachIsoToVm(ComputerSystem vm, string isoPath) { // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. VirtualSystemSettingData vmSettings = GetVmSettings(vm); @@ -490,7 +497,7 @@ namespace HypervResource isoPath); } - private static void InsertDiskImage(ComputerSystem vm, string vhdfile, string diskResourceSubType, ManagementPath drivePath) + private void InsertDiskImage(ComputerSystem vm, string vhdfile, string diskResourceSubType, ManagementPath drivePath) { // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType); @@ -524,7 +531,7 @@ namespace HypervResource vhdfile); } - private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery) + private ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery) { var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery); @@ -541,7 +548,7 @@ namespace HypervResource return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); } - public static void AttachIso(string displayName, string iso) + public void AttachIso(string displayName, string iso) { logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName); @@ -557,7 +564,7 @@ namespace HypervResource } } - public static void DestroyVm(dynamic jsonObj) + public void DestroyVm(dynamic jsonObj) { string vmToDestroy = jsonObj.vmName; DestroyVm(vmToDestroy); @@ -567,7 +574,7 @@ namespace HypervResource /// Remove all VMs and all SwitchPorts with the displayName. VHD gets deleted elsewhere. /// /// - public static void DestroyVm(string displayName) + public void DestroyVm(string displayName) { logger.DebugFormat("Got request to destroy vm {0}", displayName); @@ -614,7 +621,7 @@ namespace HypervResource while (vm != null); } - public static void SetState(ComputerSystem vm, ushort requiredState) + public void SetState(ComputerSystem vm, ushort requiredState) { logger.InfoFormat( "Changing state of {0} (GUID {1}) to {2}", @@ -657,7 +664,7 @@ namespace HypervResource //TODO: Write method to delete SwitchPort based on Name - public static bool DeleteSwitchPort(string elementName) + public bool DeleteSwitchPort(string elementName) { var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); // Get NIC path @@ -683,7 +690,7 @@ namespace HypervResource } // Add new - private static ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm ) + private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm ) { var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); @@ -715,7 +722,7 @@ namespace HypervResource return resourcePaths; } - private static ManagementPath CreateSwitchPortForVm(ComputerSystem vm, VirtualSwitchManagementService vmNetMgmtSvc, VirtualSwitch vSwitch) + private ManagementPath CreateSwitchPortForVm(ComputerSystem vm, VirtualSwitchManagementService vmNetMgmtSvc, VirtualSwitch vSwitch) { ManagementPath newSwitchPath = null; var ret_val = vmNetMgmtSvc.CreateSwitchPort( @@ -740,7 +747,7 @@ namespace HypervResource } // add vlan support by setting AccessVLAN on VLANEndpointSettingData for port - private static void SetPortVlan(string vlan, VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath) + private void SetPortVlan(string vlan, VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath) { logger.DebugFormat("Setting VLAN to {0}", vlan); @@ -749,7 +756,7 @@ namespace HypervResource vlanEndpointSettings.CommitObject(); } - public static VLANEndpointSettingData GetVlanEndpointSettings(VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath) + public VLANEndpointSettingData GetVlanEndpointSettings(VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath) { // Get Msvm_VLANEndpoint through associated with new Port var vlanEndpointQuery = new RelatedObjectQuery(newSwitchPath.Path, VLANEndpoint.CreatedClassName); @@ -791,7 +798,7 @@ namespace HypervResource /// /// /// Throws if there is no vswitch - public static VirtualSwitch GetExternalVirtSwitch() + public VirtualSwitch GetExternalVirtSwitch() { // Work back from the first *bound* external NIC we find. var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE"); @@ -857,7 +864,7 @@ namespace HypervResource } - private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings) + private void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings) { // Resource settings are changed through the management service System.Management.ManagementPath jobPath; @@ -883,7 +890,7 @@ namespace HypervResource } } - private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name) + private ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name) { // Tweak default settings by basing new VM on default global setting object // with designed display name. @@ -936,7 +943,7 @@ namespace HypervResource return vm; } - public static VirtualSwitchManagementService GetVirtualSwitchManagementService() + public VirtualSwitchManagementService GetVirtualSwitchManagementService() { // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set // of local instances, which should be size 1. @@ -952,7 +959,7 @@ namespace HypervResource throw ex; } - public static void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path) + public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path) { // Resource settings are changed through the management service System.Management.ManagementPath jobPath; @@ -976,7 +983,7 @@ namespace HypervResource } } - public static ImageManagementService GetImageManagementService() + public ImageManagementService GetImageManagementService() { // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set // of local instances, which should be size 1. @@ -994,7 +1001,7 @@ namespace HypervResource } - public static VirtualSystemManagementService GetVirtualisationSystemManagementService() + public VirtualSystemManagementService GetVirtualisationSystemManagementService() { // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set // of local instances, which should be size 1. @@ -1016,7 +1023,7 @@ namespace HypervResource /// /// /// - private static void JobCompleted(ManagementPath jobPath) + private void JobCompleted(ManagementPath jobPath) { ConcreteJob jobObj = null; for(;;) @@ -1044,7 +1051,7 @@ namespace HypervResource logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime); } - public static void GetProcessorResources(out uint cores, out uint mhz) + public void GetProcessorResources(out uint cores, out uint mhz) { // Processor processors cores = 0; @@ -1057,7 +1064,7 @@ namespace HypervResource } } - public static void GetProcessorUsageInfo(out double cpuUtilization) + public void GetProcessorUsageInfo(out double cpuUtilization) { PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\""); @@ -1072,14 +1079,14 @@ namespace HypervResource } - public static void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs) + public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs) { OperatingSystem0 os = new OperatingSystem0(); physicalRamKBs = os.TotalVisibleMemorySize; freeMemoryKBs = os.FreePhysicalMemory; } - public static string GetDefaultVirtualDiskFolder() + public string GetDefaultVirtualDiskFolder() { VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances(); string defaultVirtualHardDiskPath = null; @@ -1099,7 +1106,7 @@ namespace HypervResource return defaultVirtualHardDiskPath; } - public static ComputerSystem GetComputerSystem(string displayName) + public ComputerSystem GetComputerSystem(string displayName) { var wmiQuery = String.Format("ElementName=\"{0}\"", displayName); ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery); @@ -1112,7 +1119,7 @@ namespace HypervResource return null; } - public static List GetVmElementNames() + public List GetVmElementNames() { List result = new List(); ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); @@ -1129,7 +1136,7 @@ namespace HypervResource return result; } - public static ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) + public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) { // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. @@ -1154,7 +1161,7 @@ namespace HypervResource throw ex; } - public static MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) + public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) { // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. @@ -1179,7 +1186,7 @@ namespace HypervResource throw ex; } - public static ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) + public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) { var wmiObjCollection = GetResourceAllocationSettings(vmSettings); @@ -1199,7 +1206,7 @@ namespace HypervResource throw ex; } - public static ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr) + public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr) { var wmiObjCollection = GetResourceAllocationSettings(vmSettings); @@ -1228,7 +1235,7 @@ namespace HypervResource /// /// /// - public static ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings) + public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings) { // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. @@ -1253,7 +1260,7 @@ namespace HypervResource throw ex; } - public static SwitchPort[] GetSwitchPorts(ComputerSystem vm) + public SwitchPort[] GetSwitchPorts(ComputerSystem vm) { var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); // Get NIC path @@ -1274,7 +1281,7 @@ namespace HypervResource /// /// /// - public static SwitchPort GetSwitchPort(SyntheticEthernetPort nic) + public SwitchPort GetSwitchPort(SyntheticEthernetPort nic) { // An ASSOCIATOR object provides the cross reference between WMI objects, // but generated wrappers do not expose a ASSOCIATOR OF query as a method. @@ -1316,7 +1323,7 @@ namespace HypervResource return switchPort; } - public static SyntheticEthernetPortSettingData[] GetEthernetPorts(ComputerSystem vm) + public SyntheticEthernetPortSettingData[] GetEthernetPorts(ComputerSystem vm) { // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData. @@ -1343,7 +1350,7 @@ namespace HypervResource return results.ToArray(); } - public static VirtualSystemSettingData GetVmSettings(ComputerSystem vm) + public VirtualSystemSettingData GetVmSettings(ComputerSystem vm) { // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs index f95c337fdd7..6afa7887694 100755 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs @@ -30,7 +30,7 @@ using System.IO; namespace HypervResource { - public class WmiCallsV2 + public class WmiCallsV2 : IWmiCallsV2 { public static String CloudStackUserDataKey = "cloudstack-vm-userdata"; @@ -54,7 +54,7 @@ namespace HypervResource /// /// Returns ComputerSystem lacking any NICs and VOLUMEs /// - public static ComputerSystem AddUserData(ComputerSystem vm, string userData) + public ComputerSystem AddUserData(ComputerSystem vm, string userData) { // Obtain controller for Hyper-V virtualisation subsystem VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); @@ -95,7 +95,7 @@ namespace HypervResource /// /// Returns ComputerSystem lacking any NICs and VOLUMEs /// - public static void DeleteHostKvpItem(ComputerSystem vm, string key) + public void DeleteHostKvpItem(ComputerSystem vm, string key) { // Obtain controller for Hyper-V virtualisation subsystem VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); @@ -132,7 +132,7 @@ namespace HypervResource } } - public static VirtualSystemManagementService GetVirtualisationSystemManagementService() + public VirtualSystemManagementService GetVirtualisationSystemManagementService() { // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set // of local instances, which should be size 1. @@ -182,7 +182,7 @@ namespace HypervResource logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime); } - public static ComputerSystem GetComputerSystem(string displayName) + public ComputerSystem GetComputerSystem(string displayName) { var wmiQuery = String.Format("ElementName=\"{0}\"", displayName); ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery); @@ -195,7 +195,7 @@ namespace HypervResource return null; } - public static List GetVmElementNames() + public List GetVmElementNames() { List result = new List(); ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); @@ -212,7 +212,7 @@ namespace HypervResource return result; } - public static string GetDefaultDataRoot() + public string GetDefaultDataRoot() { string defaultRootPath = null; VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance(); @@ -224,8 +224,9 @@ namespace HypervResource return defaultRootPath; } - - public static VirtualSystemSettingData GetVmSettings(ComputerSystem vm) + + public VirtualSystemSettingData GetVmSettings(ComputerSystem vm) + { // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. @@ -256,7 +257,7 @@ namespace HypervResource throw ex; } - public static KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings) + public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings) { // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config index b0f2ace9761..4c538e4872b 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config @@ -4,4 +4,6 @@ + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config index 1bf17d4791f..c959ccf1443 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config @@ -1,23 +1,22 @@ - + - +
- +
- - - - - + + + + @@ -125,4 +124,16 @@ - + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceController1Test.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceController1Test.cs new file mode 100644 index 00000000000..6f8aa4b7d06 --- /dev/null +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceController1Test.cs @@ -0,0 +1,298 @@ +// 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; +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 IWmiCalls wmiCalls; + + + 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() + { + wmiCalls = 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() + { + var counter = 0; + wmiCalls.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(); + rsrcServer.wmiCalls = wmiCalls; + + 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(); + } + + /// + /// Possible additional tests: place an ISO in the drive + /// + + [Fact] + public void TestStartCommand() + { + ComputerSystem system = new ComputerSystem(); + wmiCalls.DeployVirtualMachine(Arg.Any(), Arg.Any()).Returns(system); + + // Arrange + HypervResourceController rsrcServer = new HypervResourceController(); + rsrcServer.wmiCalls = wmiCalls; + String sample = getSampleStartCommand(); + + + dynamic jsonStartCmd = JsonConvert.DeserializeObject(sample); + + // Act + dynamic startAns = rsrcServer.StartCommand(jsonStartCmd); + + // Assert + Assert.NotNull(startAns[0][CloudStackTypes.StartAnswer]); + Assert.True((bool)startAns[0][CloudStackTypes.StartAnswer].result, "StartCommand did not succeed " + startAns[0][CloudStackTypes.StartAnswer].details); + + Assert.Null((string)startAns[0][CloudStackTypes.StartAnswer].details); + } + + [Fact] + public void TestStopCommand() + { + //string vmName = "Test VM"; + var counter = 0; + wmiCalls.When(x => x.DestroyVm(Arg.Any())).Do(x => counter++); + + // Arrange + HypervResourceController rsrcServer = new HypervResourceController(); + rsrcServer.wmiCalls = wmiCalls; + + String sampleStop = "{\"isProxy\":false,\"vmName\":\"i-2-17-VM\",\"contextMap\":{},\"wait\":0}"; + dynamic jsonStopCmd = JsonConvert.DeserializeObject(sampleStop); + + // Act + dynamic stopAns = rsrcServer.StopCommand(jsonStopCmd); + + // Assert VM is gone! + Assert.NotNull(stopAns[0][CloudStackTypes.StopAnswer]); + Assert.True((bool)stopAns[0][CloudStackTypes.StopAnswer].result, "StopCommand did not succeed " + stopAns[0][CloudStackTypes.StopAnswer].details); + + Assert.Null((string)stopAns[0][CloudStackTypes.StopAnswer].details); + Assert.Equal(counter, 1); + } + + public static String getSamplePrimaryDataStoreInfo() + { + String samplePrimaryDataStoreInfo = + "{\"org.apache.cloudstack.storage.to.PrimaryDataStoreTO\":" + + "{\"uuid\":\"" + testLocalStoreUUID + "\"," + + "\"id\":201," + + "\"host\":\"" + testPrimaryDataStoreHost + "\"," + + "\"type\":\"Filesystem\"," + // Not used in PrimaryDataStoreTO + "\"poolType\":\"Filesystem\"," + // Not used in PrimaryDataStoreTO + "\"path\":" + testLocalStorePathJSON + "," + + "\"port\":0}" + + "}"; + return samplePrimaryDataStoreInfo; + } + + public static String getSampleVolumeObjectTO() + { + String sampleVolumeObjectTO = + "{\"org.apache.cloudstack.storage.to.VolumeObjectTO\":" + + "{\"uuid\":\"19ae8e67-cb2c-4ab4-901e-e0b864272b59\"," + + "\"volumeType\":\"ROOT\"," + + "\"format\":\"VHDX\"," + + "\"dataStore\":" + getSamplePrimaryDataStoreInfo() + "," + + "\"name\":\"" + testSampleVolumeTempUUIDNoExt + "\"," + + "\"size\":52428800," + + "\"volumeId\":10," + + // "\"vmName\":\"i-3-5-VM\"," + // TODO: do we have to fill in the vmName? + "\"accountId\":3,\"id\":10}" + + "}"; // end of destTO + return sampleVolumeObjectTO; + } + + public static String getSampleStartCommand() + { + String sample = "{\"vm\":{\"id\":17,\"name\":\"i-2-17-VM\",\"type\":\"User\",\"cpus\":1,\"speed\":500," + + "\"minRam\":536870912,\"maxRam\":536870912,\"arch\":\"x86_64\"," + + "\"os\":\"CentOS 6.0 (64-bit)\",\"bootArgs\":\"\",\"rebootOnCrash\":false," + + "\"enableHA\":false,\"limitCpuUse\":false,\"vncPassword\":\"31f82f29aff646eb\"," + + "\"params\":{},\"uuid\":\"8b030b6a-0243-440a-8cc5-45d08815ca11\"" + + ",\"disks\":[" + + "{\"data\":" + getSampleVolumeObjectTO() + ",\"diskSeq\":0,\"type\":\"ROOT\"}," + + "{\"diskSeq\":1,\"type\":\"ISO\"}" + + "]," + + "\"nics\":[" + + "{\"deviceId\":0,\"networkRateMbps\":100,\"defaultNic\":true,\"uuid\":\"99cb4813-23af-428c-a87a-2d1899be4f4b\"," + + "\"ip\":\"10.1.1.67\",\"netmask\":\"255.255.255.0\",\"gateway\":\"10.1.1.1\"," + + "\"mac\":\"02:00:51:2c:00:0e\",\"dns1\":\"4.4.4.4\",\"broadcastType\":\"Vlan\",\"type\":\"Guest\"," + + "\"broadcastUri\":\"vlan://261\",\"isolationUri\":\"vlan://261\",\"isSecurityGroupEnabled\":false}" + + "]},\"contextMap\":{},\"wait\":0}"; + return sample; + } + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceControllerTest.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceControllerTest.cs index 8a867272671..c66c6162017 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceControllerTest.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/HypervResourceControllerTest.cs @@ -15,7 +15,6 @@ // specific language governing permissions and limitations // under the License. using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION; using System.Management; using Newtonsoft.Json.Linq; @@ -26,10 +25,10 @@ using HypervResource; using CloudStack.Plugin.AgentShell; using System.Collections.Generic; using System.Xml; +using Xunit; namespace ServerResource.Tests { - [TestClass] public class HypervResourceControllerTest { protected static string testCifsUrl = AgentSettings.Default.testCifsUrl; @@ -59,6 +58,9 @@ namespace ServerResource.Tests protected static String testSampleTemplateURLJSON; protected static String testLocalStorePathJSON; + protected static WmiCalls wmiCalls = new WmiCalls(); + protected static WmiCallsV2 wmiCallsV2 = new WmiCallsV2(); + private static ILog s_logger = LogManager.GetLogger(typeof(HypervResourceControllerTest)); /// @@ -69,8 +71,7 @@ namespace ServerResource.Tests /// A second approximation would use the AgentShell settings files directly. /// A third approximation would look to invoke ServerResource methods via an HTTP request /// - [TestInitializeAttribute] - public void setUp() + public HypervResourceControllerTest() { AgentService.ConfigServerResource(); HypervResourceController.config.PrivateMacAddress = AgentSettings.Default.private_mac_address; @@ -95,7 +96,7 @@ namespace ServerResource.Tests } catch (System.IO.IOException ex) { - Assert.Fail("Need to be able to create the folder " + testSecondarStoreDir.FullName + " failed due to " + ex.Message); + throw new NotImplementedException("Need to be able to create the folder " + testSecondarStoreDir.FullName + " failed due to " + ex.Message); } } @@ -105,7 +106,7 @@ namespace ServerResource.Tests // Make sure local primary storage is available DirectoryInfo testPoolDir = new DirectoryInfo(testLocalStorePath); - Assert.IsTrue(testPoolDir.Exists, "To simulate local file system Storage Pool, you need folder at " + testPoolDir.FullName); + 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; @@ -113,7 +114,7 @@ namespace ServerResource.Tests // Clean up old test files in local storage folder FileInfo testVolWorks = new FileInfo(Path.Combine(testLocalStorePath, testSampleVolumeWorkingUUID)); - Assert.IsTrue(testVolWorks.Exists, "Create a working virtual disk at " + testVolWorks.FullName); + Assert.True(testVolWorks.Exists, "Create a working virtual disk at " + testVolWorks.FullName); // Delete all temporary files in local folder save the testVolWorks @@ -125,7 +126,7 @@ namespace ServerResource.Tests } file.Delete(); file.Refresh(); - Assert.IsFalse(file.Exists, "removed file from previous test called " + file.FullName); + Assert.False(file.Exists, "removed file from previous test called " + file.FullName); } // Recreate starting point files for test, and record JSON encoded paths for each ... @@ -165,12 +166,12 @@ namespace ServerResource.Tests newFileInfo = srcFile.CopyTo(newFullname); } newFileInfo.Refresh(); - Assert.IsTrue(newFileInfo.Exists, "Attempted to create " + newFullname + " from " + newFileInfo.FullName); + Assert.True(newFileInfo.Exists, "Attempted to create " + newFullname + " from " + newFileInfo.FullName); return JsonConvert.SerializeObject(newFileInfo.FullName); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestPrimaryStorageDownloadCommandHTTP() { string downloadURI = "https://s3-eu-west-1.amazonaws.com/cshv3eu/SmallDisk.vhdx"; @@ -190,7 +191,7 @@ namespace ServerResource.Tests // Assert JObject ansAsProperty = jsonResult[0]; dynamic ans = ansAsProperty.GetValue(CloudStackTypes.PrimaryStorageDownloadAnswer); - Assert.IsTrue((bool)ans.result, "PrimaryStorageDownloadCommand did not succeed " + ans.details); + Assert.True((bool)ans.result, "PrimaryStorageDownloadCommand did not succeed " + ans.details); // Test that URL of downloaded template works for file creation. dynamic jsonCreateCmd = JsonConvert.DeserializeObject(CreateCommandSample()); @@ -199,10 +200,10 @@ namespace ServerResource.Tests JObject ansAsProperty2 = jsonAns2[0]; dynamic ans2 = ansAsProperty2.GetValue(CloudStackTypes.CreateAnswer); - Assert.IsTrue((bool)ans2.result, (string)ans2.details); + Assert.True((bool)ans2.result, (string)ans2.details); FileInfo newFile = new FileInfo((string)ans2.volume.path); - Assert.IsTrue(newFile.Length > 0, "The new file should have a size greater than zero"); + Assert.True(newFile.Length > 0, "The new file should have a size greater than zero"); newFile.Delete(); } @@ -227,7 +228,7 @@ namespace ServerResource.Tests return sample; } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestDestroyCommand() { // Arrange @@ -252,11 +253,11 @@ namespace ServerResource.Tests JObject ansAsProperty2 = destoryAns[0]; dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.Answer); String path = jsonDestoryCmd.volume.path; - Assert.IsTrue((bool)ans.result, "DestroyCommand did not succeed " + ans.details); - Assert.IsTrue(!File.Exists(path), "Failed to delete file " + path); + Assert.True((bool)ans.result, "DestroyCommand did not succeed " + ans.details); + Assert.True(!File.Exists(path), "Failed to delete file " + path); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestCreateCommand() { // TODO: Need sample to update the test. @@ -268,9 +269,9 @@ namespace ServerResource.Tests dynamic jsonCreateCmd = JsonConvert.DeserializeObject(createCmd); HypervResourceController rsrcServer = new HypervResourceController(); - Assert.IsTrue(Directory.Exists(testLocalStorePath)); + Assert.True(Directory.Exists(testLocalStorePath)); string filePath = Path.Combine(testLocalStorePath, (string)JsonConvert.DeserializeObject(testSampleTemplateURLJSON)); - Assert.IsTrue(File.Exists(filePath), "The template we make volumes from is missing from path " + filePath); + 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"); @@ -280,18 +281,18 @@ namespace ServerResource.Tests JObject ansAsProperty2 = jsonResult[0]; dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.CreateAnswer); - Assert.IsNotNull(ans, "Should be an answer object of type CreateAnswer"); - Assert.IsTrue((bool)ans.result, "Failed to CreateCommand due to " + (string)ans.result); - Assert.AreEqual(Directory.GetFiles(testLocalStorePath).Length, fileCount + 1); + 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.IsTrue(newFile.Length > 0, "The new file should have a size greater than zero"); + Assert.True(newFile.Length > 0, "The new file should have a size greater than zero"); newFile.Delete(); } /// /// Possible additional tests: place an ISO in the drive /// - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestStartStopCommand() { string vmName = TestStartCommand(); @@ -351,7 +352,7 @@ namespace ServerResource.Tests } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestCopyCommandFromCifs() { // Arrange @@ -411,7 +412,7 @@ namespace ServerResource.Tests File.Delete(dwnldDest); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestCopyCommand() { // Arrange @@ -515,9 +516,9 @@ namespace ServerResource.Tests dynamic copyResult = rsrcServer.CopyCommand(jsonCloneCopyCmd); // Assert - Assert.IsNotNull(copyResult[0][CloudStackTypes.CopyCmdAnswer], "CopyCommand should return a StartAnswer in all cases"); - Assert.IsTrue((bool)copyResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + copyResult[0][CloudStackTypes.CopyCmdAnswer].details); - Assert.IsTrue(File.Exists(newVolName), "CopyCommand failed to generate " + newVolName); + Assert.NotNull(copyResult[0][CloudStackTypes.CopyCmdAnswer]); + Assert.True((bool)copyResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + copyResult[0][CloudStackTypes.CopyCmdAnswer].details); + Assert.True(File.Exists(newVolName), "CopyCommand failed to generate " + newVolName); } private static void DownloadTemplateToPrimaryStorage(HypervResourceController rsrcServer, dynamic jsonDownloadCopyCmd, string dwnldDest) @@ -525,12 +526,12 @@ namespace ServerResource.Tests dynamic dwnldResult = rsrcServer.CopyCommand(jsonDownloadCopyCmd); // Assert - Assert.IsNotNull(dwnldResult[0][CloudStackTypes.CopyCmdAnswer], "CopyCommand should return a StartAnswer in all cases"); - Assert.IsTrue((bool)dwnldResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + dwnldResult[0][CloudStackTypes.CopyCmdAnswer].details); - Assert.IsTrue(File.Exists(dwnldDest), "CopyCommand failed to generate " + dwnldDest); + Assert.NotNull(dwnldResult[0][CloudStackTypes.CopyCmdAnswer]); + Assert.True((bool)dwnldResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + dwnldResult[0][CloudStackTypes.CopyCmdAnswer].details); + Assert.True(File.Exists(dwnldDest), "CopyCommand failed to generate " + dwnldDest); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestCopyCommandBz2Img() { // Arrange @@ -662,7 +663,7 @@ namespace ServerResource.Tests jsonCloneCopyCmd = null; } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestModifyStoragePoolCommand() { // Create dummy folder @@ -696,7 +697,7 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.ModifyStoragePoolAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); // always succeeds + Assert.True((bool)ans.result, (string)ans.details); // always succeeds // Clean up var cmd2 = new @@ -711,10 +712,10 @@ namespace ServerResource.Tests // Assert dynamic ans2 = jsonResult2[0][CloudStackTypes.Answer]; - Assert.IsTrue((bool)ans2.result, (string)ans2.details); // always succeeds + Assert.True((bool)ans2.result, (string)ans2.details); // always succeeds } - [TestMethod] + [Fact(Skip="these are functional tests")] public void CreateStoragePoolCommand() { var cmd = new { localPath = "NULL" }; @@ -726,10 +727,10 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.Answer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); // always succeeds + Assert.True((bool)ans.result, (string)ans.details); // always succeeds } - [TestMethod] + [Fact(Skip="these are functional tests")] public void MaintainCommand() { // Omit HostEnvironment object, as this is a series of settings currently not used. @@ -742,10 +743,10 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.MaintainAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); // always succeeds + Assert.True((bool)ans.result, (string)ans.details); // always succeeds } - [TestMethod] + [Fact(Skip="these are functional tests")] public void SetupCommand() { // Omit HostEnvironment object, as this is a series of settings currently not used. @@ -758,10 +759,10 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.SetupAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); // always succeeds + Assert.True((bool)ans.result, (string)ans.details); // always succeeds } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestPassingUserdataToVm() { // Sample data @@ -769,14 +770,14 @@ namespace ServerResource.Tests String value = "username=root;password=1pass@word1"; // Find the VM - List vmNames = WmiCallsV2.GetVmElementNames(); + List vmNames = wmiCallsV2.GetVmElementNames(); // Get associated WMI object - var vm = WmiCallsV2.GetComputerSystem(AgentSettings.Default.testKvpVmName); + var vm = wmiCallsV2.GetComputerSystem(AgentSettings.Default.testKvpVmName); // Get existing KVP - var vmSettings = WmiCallsV2.GetVmSettings(vm); - var kvpInfo = WmiCallsV2.GetKvpSettings(vmSettings); + var vmSettings = wmiCallsV2.GetVmSettings(vm); + var kvpInfo = wmiCallsV2.GetKvpSettings(vmSettings); // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object. string[] kvpProps = kvpInfo.HostExchangeItems; @@ -791,16 +792,16 @@ namespace ServerResource.Tests if (existingKey == key) { - WmiCallsV2.DeleteHostKvpItem(vm, existingKey); + wmiCallsV2.DeleteHostKvpItem(vm, existingKey); break; } } // Add new user data - WmiCallsV2.AddUserData(vm, value); + wmiCallsV2.AddUserData(vm, value); // Verify key added to subsystem - kvpInfo = WmiCallsV2.GetKvpSettings(vmSettings); + kvpInfo = wmiCallsV2.GetKvpSettings(vmSettings); // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object. kvpProps = kvpInfo.HostExchangeItems; @@ -816,13 +817,13 @@ namespace ServerResource.Tests if (existingKey == key && existingValue == value) { -// WmiCallsV2.DeleteHostKvpItem(vm, existingKey); +// wmiCallsV2.DeleteHostKvpItem(vm, existingKey); userDataInPlace = true; break; } } - Assert.IsTrue(userDataInPlace, "User data key / value did no save properly"); + Assert.True(userDataInPlace, "User data key / value did no save properly"); } private static void ParseKVP(String wmiObjectXml, out String existingKey, out String existingValue) @@ -844,7 +845,7 @@ namespace ServerResource.Tests existingValue = dataNode.InnerText; } - [TestMethod] + [Fact(Skip="these are functional tests")] public void GetVmStatsCommandFail() { // Use WMI to find existing VMs @@ -865,14 +866,14 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.GetVmStatsAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); // always succeeds, fake VM means no answer for the named VM + Assert.True((bool)ans.result, (string)ans.details); // always succeeds, fake VM means no answer for the named VM } - [TestMethod] + [Fact(Skip="these are functional tests")] public void GetVmStatsCommand() { // Use WMI to find existing VMs - List vmNames = WmiCalls.GetVmElementNames(); + List vmNames = wmiCalls.GetVmElementNames(); var cmd = new { @@ -888,10 +889,10 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.GetVmStatsAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); + Assert.True((bool)ans.result, (string)ans.details); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void GetStorageStatsCommand() { // TODO: Update sample data to unsure it is using correct info. @@ -916,12 +917,12 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.GetStorageStatsAnswer]; - Assert.IsTrue((bool)ans.result, (string)ans.details); - Assert.IsTrue((long)ans.used <= (long)ans.capacity); // TODO: verify that capacity is indeed capacity and not used. + Assert.True((bool)ans.result, (string)ans.details); + Assert.True((long)ans.used <= (long)ans.capacity); // TODO: verify that capacity is indeed capacity and not used. } // TODO: can we speed up this command? The logic takes over a second. - [TestMethod] + [Fact(Skip="these are functional tests")] public void GetHostStatsCommand() { // Arrange @@ -945,19 +946,19 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.GetHostStatsAnswer]; - Assert.IsTrue((bool)ans.result); - Assert.IsTrue(hostIdVal == (long)ans.hostStats.hostId); - Assert.IsTrue(0.0 < (double)ans.hostStats.totalMemoryKBs); - Assert.IsTrue(0.0 < (double)ans.hostStats.freeMemoryKBs); - Assert.IsTrue(0.0 <= (double)ans.hostStats.networkReadKBs); - Assert.IsTrue(0.0 <= (double)ans.hostStats.networkWriteKBs); - Assert.IsTrue(0.0 <= (double)ans.hostStats.cpuUtilization); - Assert.IsTrue(100.0 >= (double)ans.hostStats.cpuUtilization); - Assert.IsTrue("host".Equals((string)ans.hostStats.entityType)); - Assert.IsTrue(String.IsNullOrEmpty((string)ans.details)); + Assert.True((bool)ans.result); + Assert.True(hostIdVal == (long)ans.hostStats.hostId); + Assert.True(0.0 < (double)ans.hostStats.totalMemoryKBs); + Assert.True(0.0 < (double)ans.hostStats.freeMemoryKBs); + Assert.True(0.0 <= (double)ans.hostStats.networkReadKBs); + Assert.True(0.0 <= (double)ans.hostStats.networkWriteKBs); + Assert.True(0.0 <= (double)ans.hostStats.cpuUtilization); + Assert.True(100.0 >= (double)ans.hostStats.cpuUtilization); + Assert.True("host".Equals((string)ans.hostStats.entityType)); + Assert.True(String.IsNullOrEmpty((string)ans.details)); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void GetHostStatsCommandFail() { // Arrange @@ -970,12 +971,12 @@ namespace ServerResource.Tests // Assert dynamic ans = jsonResult[0][CloudStackTypes.GetHostStatsAnswer]; - Assert.IsFalse((bool)ans.result); - Assert.IsNull((string)ans.hostStats); - Assert.IsNotNull(ans.details); + Assert.False((bool)ans.result); + Assert.Null((string)ans.hostStats); + Assert.NotNull(ans.details); } - [TestMethod] + [Fact(Skip="these are functional tests")] public void TestStartupCommand() { // Arrange @@ -1008,16 +1009,16 @@ namespace ServerResource.Tests uint cores; uint mhz; - WmiCalls.GetProcessorResources(out cores, out mhz); + wmiCalls.GetProcessorResources(out cores, out mhz); ulong memory_mb; ulong freememory; - WmiCalls.GetMemoryResources(out memory_mb, out freememory); + wmiCalls.GetMemoryResources(out memory_mb, out freememory); memory_mb *= 1024; long capacityBytes; long availableBytes; - HypervResourceController.GetCapacityForLocalPath(WmiCalls.GetDefaultVirtualDiskFolder(), + HypervResourceController.GetCapacityForLocalPath(wmiCalls.GetDefaultVirtualDiskFolder(), out capacityBytes, out availableBytes); - var DefaultVirtualDiskFolder = JsonConvert.SerializeObject(WmiCalls.GetDefaultVirtualDiskFolder()); + var DefaultVirtualDiskFolder = JsonConvert.SerializeObject(wmiCalls.GetDefaultVirtualDiskFolder()); string expected = #region string_literal "[{\"" + CloudStackTypes.StartupRoutingCommand + "\":{" + @@ -1073,7 +1074,7 @@ namespace ServerResource.Tests // Assert string actual = JsonConvert.SerializeObject(jsonResult); - Assert.AreEqual(expected, actual, "StartupRoutingCommand not populated properly"); + Assert.Equal(expected, actual); } @@ -1090,40 +1091,40 @@ namespace ServerResource.Tests dynamic startAns = rsrcServer.StartCommand(jsonStartCmd); // Assert - Assert.IsNotNull(startAns[0][CloudStackTypes.StartAnswer], "StartCommand should return a StartAnswer in all cases"); - Assert.IsTrue((bool)startAns[0][CloudStackTypes.StartAnswer].result, "StartCommand did not succeed " + startAns[0][CloudStackTypes.StartAnswer].details); + Assert.NotNull(startAns[0][CloudStackTypes.StartAnswer]); + Assert.True((bool)startAns[0][CloudStackTypes.StartAnswer].result, "StartCommand did not succeed " + startAns[0][CloudStackTypes.StartAnswer].details); string vmCmdName = jsonStartCmd.vm.name.Value; - var vm = WmiCalls.GetComputerSystem(vmCmdName); - VirtualSystemSettingData vmSettings = WmiCalls.GetVmSettings(vm); - MemorySettingData memSettings = WmiCalls.GetMemSettings(vmSettings); - ProcessorSettingData procSettings = WmiCalls.GetProcSettings(vmSettings); + var vm = wmiCalls.GetComputerSystem(vmCmdName); + VirtualSystemSettingData vmSettings = wmiCalls.GetVmSettings(vm); + MemorySettingData memSettings = wmiCalls.GetMemSettings(vmSettings); + ProcessorSettingData procSettings = wmiCalls.GetProcSettings(vmSettings); dynamic jsonObj = JsonConvert.DeserializeObject(sample); var vmInfo = jsonObj.vm; string vmName = vmInfo.name; var nicInfo = vmInfo.nics; int vcpus = vmInfo.cpus; int memSize = vmInfo.maxRam / 1048576; - Assert.IsTrue((long)memSettings.VirtualQuantity == memSize); - Assert.IsTrue((long)memSettings.Reservation == memSize); - Assert.IsTrue((long)memSettings.Limit == memSize); - Assert.IsTrue((int)procSettings.VirtualQuantity == vcpus); - Assert.IsTrue((int)procSettings.Reservation == vcpus); - Assert.IsTrue((int)procSettings.Limit == 100000); + Assert.True((long)memSettings.VirtualQuantity == memSize); + Assert.True((long)memSettings.Reservation == memSize); + Assert.True((long)memSettings.Limit == memSize); + Assert.True((int)procSettings.VirtualQuantity == vcpus); + Assert.True((int)procSettings.Reservation == vcpus); + Assert.True((int)procSettings.Limit == 100000); // examine NIC - SyntheticEthernetPortSettingData[] nicSettingsViaVm = WmiCalls.GetEthernetPorts(vm); - Assert.IsTrue(nicSettingsViaVm.Length > 0, "Should be at least one ethernet port on VM"); + SyntheticEthernetPortSettingData[] nicSettingsViaVm = wmiCalls.GetEthernetPorts(vm); + Assert.True(nicSettingsViaVm.Length > 0, "Should be at least one ethernet port on VM"); string expectedMac = (string)jsonStartCmd.vm.nics[0].mac; string strippedExpectedMac = expectedMac.Replace(":", string.Empty); - Assert.AreEqual(nicSettingsViaVm[0].Address.ToLower(), strippedExpectedMac.ToLower()); + Assert.Equal(nicSettingsViaVm[0].Address.ToLower(), strippedExpectedMac.ToLower()); // Assert switchport has correct VLAN - SwitchPort[] switchPorts = WmiCalls.GetSwitchPorts(vm); - VirtualSwitchManagementService vmNetMgmtSvc = WmiCalls.GetVirtualSwitchManagementService(); - VLANEndpointSettingData vlanSettings = WmiCalls.GetVlanEndpointSettings(vmNetMgmtSvc, switchPorts[0].Path); + SwitchPort[] switchPorts = wmiCalls.GetSwitchPorts(vm); + VirtualSwitchManagementService vmNetMgmtSvc = wmiCalls.GetVirtualSwitchManagementService(); + VLANEndpointSettingData vlanSettings = wmiCalls.GetVlanEndpointSettings(vmNetMgmtSvc, switchPorts[0].Path); string isolationUri = (string)jsonStartCmd.vm.nics[0].isolationUri; string vlan = isolationUri.Replace("vlan://", string.Empty); - Assert.AreEqual(vlanSettings.AccessVLAN.ToString(), vlan); + Assert.Equal(vlanSettings.AccessVLAN.ToString(), vlan); return vmName; } @@ -1139,10 +1140,10 @@ namespace ServerResource.Tests dynamic stopAns = rsrcServer.StopCommand(jsonStopCmd); // Assert VM is gone! - Assert.IsNotNull(stopAns[0][CloudStackTypes.StopAnswer], "StopCommand should return a StopAnswer in all cases"); - Assert.IsTrue((bool)stopAns[0][CloudStackTypes.StopAnswer].result, "StopCommand did not succeed " + stopAns[0][CloudStackTypes.StopAnswer].details); - var finalVm = WmiCalls.GetComputerSystem(vmName); - Assert.IsTrue(WmiCalls.GetComputerSystem(vmName) == null); + Assert.NotNull(stopAns[0][CloudStackTypes.StopAnswer]); + Assert.True((bool)stopAns[0][CloudStackTypes.StopAnswer].result, "StopCommand did not succeed " + stopAns[0][CloudStackTypes.StopAnswer].details); + var finalVm = wmiCalls.GetComputerSystem(vmName); + Assert.True(wmiCalls.GetComputerSystem(vmName) == null); } } } diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/ServerResource.Tests.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/ServerResource.Tests.csproj index 381245ed93e..96b411cc86a 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/ServerResource.Tests.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/ServerResource.Tests.csproj @@ -53,6 +53,9 @@ MinimumRecommendedRules.ruleset + + ..\packages\AWSSDK.1.5.23.0\lib\AWSSDK.dll + ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll @@ -64,6 +67,9 @@ ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + + ..\packages\NSubstitute.1.6.1.0\lib\NET40\NSubstitute.dll + @@ -83,8 +89,12 @@ + + ..\packages\xunit.1.9.2\lib\net20\xunit.dll + + @@ -121,4 +131,9 @@ --> + + + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config index 08ef691fa29..4c538e4872b 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config @@ -1,6 +1,9 @@  + + + \ No newline at end of file diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj index 8de9b57f197..ad6245e6d74 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj @@ -50,6 +50,21 @@ MinimumRecommendedRules.ruleset + + ..\packages\AWSSDK.1.5.23.0\lib\AWSSDK.dll + + + ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll + + + ..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + + + ..\packages\NSubstitute.1.6.1.0\lib\NET40\NSubstitute.dll + @@ -58,6 +73,9 @@ + + ..\packages\xunit.1.9.2\lib\net20\xunit.dll + @@ -172,4 +190,4 @@ --> - \ No newline at end of file + diff --git a/plugins/hypervisors/hyperv/buildagent.sh b/plugins/hypervisors/hyperv/buildagent.sh old mode 100644 new mode 100755 index f2a492127d6..93aec16ca99 --- a/plugins/hypervisors/hyperv/buildagent.sh +++ b/plugins/hypervisors/hyperv/buildagent.sh @@ -19,4 +19,4 @@ export EnableNuGetPackageRestore=true wget http://nuget.org/nuget.exe mv nuget.exe ./DotNet/ServerResource/.nuget/NuGet.exe chmod a+x ./DotNet/ServerResource/.nuget/NuGet.exe -xbuild /p:Configuration="NoUnitTests" /p:BuildWithMono="true" ./DotNet/ServerResource/ServerResource.sln +xbuild /p:BuildWithMono="true" ./DotNet/ServerResource/ServerResource.sln diff --git a/plugins/hypervisors/hyperv/var/test/storagepool/TestCopiedLocalTemplate.vhdx b/plugins/hypervisors/hyperv/var/test/storagepool/TestCopiedLocalTemplate.vhdx new file mode 100644 index 00000000000..bea65f361fa --- /dev/null +++ b/plugins/hypervisors/hyperv/var/test/storagepool/TestCopiedLocalTemplate.vhdx @@ -0,0 +1 @@ +fake template file \ No newline at end of file