/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; using XenAdmin; using XenAdmin.Commands; using XenAPI; namespace XenAdminTests.CommandTests { [TestFixture, Category(TestCategories.UICategoryA)] public class MigrateVirtualDiskCommandTest : DatabaseTester_TestFixture { private readonly IMainWindow mw = new MockMainWindow(); private const string dbName = "tampa_livevdimove_xapi-db.xml"; public MigrateVirtualDiskCommandTest() : base(dbName){} [Test] public void CheckContextMenuText() { var selectedVdi1 = new SelectedItem(new VDI()); var selectedVdi2 = new SelectedItem(new VDI()); var cmd = new MigrateVirtualDiskCommand(mw, new[] { selectedVdi1 }); Assert.AreEqual(Messages.MOVE_VDI_CONTEXT_MENU, cmd.ContextMenuText); cmd = new MigrateVirtualDiskCommand(mw, new[] { selectedVdi1, selectedVdi2 }); Assert.AreEqual(Messages.MAINWINDOW_MOVE_OBJECTS, cmd.ContextMenuText); } [Test] public void CommandCanExecuteWithSelectionOfSrAndVdiOnRunningVms() { foreach (SrTuple srTuple in runningVmCanMigrateVdiData) { SR sr; VDI vdi; ResolveSrAndVdiNames(srTuple.SrName, srTuple.VdiName, out sr, out vdi); var cmd = new MigrateVirtualDiskCommand(mw, new[] {new SelectedItem(vdi)}); Assert.AreEqual(srTuple.ExpectedCanMigrate, cmd.CanExecute(), String.Format("VDI '{0}' on SR '{1}' can migrate", srTuple.VdiName, srTuple.SrName)); } } [Test] public void CommandCannotExecuteNullVdi() { Assert.Throws(() => new MigrateVirtualDiskCommand(mw, null), "Null vdi selection"); } [Test] public void CommandCanExecuteWithSelectionOfSrAndVdiOnShutdownVms() { ShutdownAllVMs(); foreach (SrTuple srTuple in runningVmCanMigrateVdiData) { SR sr; VDI vdi; ResolveSrAndVdiNames(srTuple.SrName, srTuple.VdiName, out sr, out vdi); var cmd = new MigrateVirtualDiskCommand(mw, new[] { new SelectedItem(vdi) }); Assert.IsFalse(cmd.CanExecute(), String.Format("VDI '{0}' on SR '{1}' can migrate", srTuple.VdiName, srTuple.SrName)); } StartAllVMs(); } [Test] public void TestMultipleSelectionsAllValid() { List selection = CreateVdiSelection(runningVmCanMigrateVdiData, t=>t.ExpectedCanMigrate); Assert.IsNotEmpty(selection); MigrateVirtualDiskCommand cmd = new MigrateVirtualDiskCommand(mw, selection); Assert.IsTrue(cmd.CanExecute(), "All valid selection can migrate"); } [Test] public void TestMultipleSelectionsMixed() { List selection = CreateVdiSelection(runningVmCanMigrateVdiData, t=>true); Assert.IsNotEmpty(selection); MigrateVirtualDiskCommand cmd = new MigrateVirtualDiskCommand(mw, selection); Assert.IsFalse(cmd.CanExecute(), "Mixture in/valid selection can migrate"); } [Test] public void CommandCannotExecuteAndReasonMessage() { //Note: Order of logic implicitly checked here SR sr; VDI vdi; ResolveSrAndVdiNames("iSCSIa", "vdi1", out sr, out vdi); ExecuteCommandCheckingReason("Unknown", vdi); vdi.type = vdi_type.metadata; ExecuteCommandCheckingReason(Messages.CANNOT_MOVE_DR_VD, vdi); vdi.type = vdi_type.ha_statefile; ExecuteCommandCheckingReason(Messages.CANNOT_MOVE_HA_VD, vdi); vdi.Locked = true; ExecuteCommandCheckingReason(Messages.CANNOT_MOVE_VDI_IN_USE, vdi); vdi.is_a_snapshot = true; ExecuteCommandCheckingReason(Messages.CANNOT_MOVE_VDI_IS_SNAPSHOT, vdi); } #region Private Helper Methods private void StartAllVMs() { DatabaseManager.ConnectionFor(dbName).Cache.VMs.ToList().ForEach(vm => VM.start(DatabaseManager.ConnectionFor(dbName).Session, vm.opaque_ref, false, false)); DatabaseManager.ConnectionFor(dbName).LoadCache(DatabaseManager.ConnectionFor(dbName).Session); Assert.IsTrue(DatabaseManager.ConnectionFor(dbName).Cache.VMs.All(vm => vm.IsRunning), "VMs are in a running state"); } private void ShutdownAllVMs() { DatabaseManager.ConnectionFor(dbName).Cache.VMs.ToList().ForEach(vm => VM.hard_shutdown(DatabaseManager.ConnectionFor(dbName).Session, vm.opaque_ref)); DatabaseManager.ConnectionFor(dbName).LoadCache(DatabaseManager.ConnectionFor(dbName).Session); Assert.IsFalse(DatabaseManager.ConnectionFor(dbName).Cache.VMs.ToList().All(vm => vm.IsRunning), "VMs are in a shutdown state"); } private void ExecuteCommandCheckingReason(string expectedReason, VDI vdi) { MigrateVirtualDiskCommand cmd = new MigrateVirtualDiskCommand(mw, new List { new SelectedItem(vdi) }); Dictionary reasons = cmd.GetCantExecuteReasons(); Assert.IsNotEmpty(reasons, "Reasons found for " + vdi.name_label); Assert.IsFalse(cmd.CanExecute(), "Command can execute for " + vdi.name_label); Assert.AreEqual(expectedReason, reasons.First().Value, "Reason as expected for " + vdi.name_label); } private void ResolveSrAndVdiNames(string srName, string vdiName, out SR sr, out VDI vdi) { sr = DatabaseManager.ConnectionFor(dbName).Cache.SRs.First(s => s.name_label == srName); Assert.NotNull(sr, "Couldn't resolve SR: " + srName); List vdis = DatabaseManager.ConnectionFor(dbName).ResolveAll(sr.VDIs); vdi = vdis.First(v => v.name_label == vdiName); Assert.NotNull(vdi, "Couldn't resolve VDI: " + vdiName); } private List CreateVdiSelection(List sourceList, Predicate condition) { List selection = new List(); foreach (SrTuple srTuple in sourceList) { if(condition(srTuple)) { SR sr; VDI vdi; ResolveSrAndVdiNames(srTuple.SrName, srTuple.VdiName, out sr, out vdi); selection.Add(new SelectedItem(vdi)); } } return selection; } #endregion #region Test Data private struct SrTuple { public SrTuple(string SrName, string VdiName, bool ExpectedCanMigrate) { this.SrName = SrName; this.VdiName = VdiName; this.ExpectedCanMigrate = ExpectedCanMigrate; } public readonly string SrName; public readonly string VdiName; public readonly bool ExpectedCanMigrate; } private readonly List runningVmCanMigrateVdiData = new List { new SrTuple("iSCSIa", "shared 1", true), new SrTuple("iSCSIa", "shared 0", true), new SrTuple("iSCSIa", "vdi1", false), //Not connected to a VM new SrTuple("Local storage", "local 0", true), new SrTuple("Local storage", "local 1", true) }; #endregion } }