From 9337663adba06a0eb74ec6ba097169b8ffa098c5 Mon Sep 17 00:00:00 2001 From: Gabor Apati-Nagy Date: Wed, 29 Jun 2016 12:49:53 +0100 Subject: [PATCH 1/2] CP-17282: Unit tests to validate the Update Sequence logic Unit tests to test GetUpdateSequence Signed-off-by: Gabor Apati-Nagy --- XenAdmin/Core/Updates.cs | 2 +- .../BatchUpdatesTests/BatchUpdatesTests.cs | 335 ++++++++++++++++++ 2 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs diff --git a/XenAdmin/Core/Updates.cs b/XenAdmin/Core/Updates.cs index a9699b182..312d999e4 100644 --- a/XenAdmin/Core/Updates.cs +++ b/XenAdmin/Core/Updates.cs @@ -52,7 +52,7 @@ namespace XenAdmin.Core private static List XenServerVersionsForAutoCheck = new List(); private static List XenServerPatches = new List(); private static List XenCenterVersions = new List(); - private static List XenServerVersions = new List(); + public static List XenServerVersions = new List(); private static readonly object updateAlertsLock = new object(); private static readonly ChangeableList updateAlerts = new ChangeableList(); diff --git a/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs new file mode 100644 index 000000000..c6d80f8b5 --- /dev/null +++ b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs @@ -0,0 +1,335 @@ +/* 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 NUnit.Framework; +using XenAdmin.Actions; +using Moq; +using XenAdmin.Core; +using XenAPI; +using System.Linq; + +namespace XenAdminTests.UnitTests +{ + [TestFixture, Category(TestCategories.Unit)] + public class BatchUpdatesTests + { + + private static Mock GetAMockHost(string productVersion, string buildNumber) + { + var id = System.Guid.NewGuid().ToString(); + + MockObjectManager mom = new MockObjectManager(); + + mom.CreateNewConnection(id); + + Mock master = mom.NewXenObject(id); + Mock pool = mom.NewXenObject(id); + XenRef masterRef = new XenRef("master-ref"); + pool.Setup(p => p.master).Returns(masterRef); + + mom.MockCacheFor(id).Setup(c => c.Resolve(It.IsAny>())).Returns(pool.Object); + + mom.MockConnectionFor(id).Setup(c => c.Resolve(masterRef)).Returns(master.Object); + mom.MockConnectionFor(id).Setup(c => c.Cache.Hosts).Returns(new Host[] { master.Object }); + mom.MockConnectionFor(id).Setup(c => c.Cache.Pools).Returns(new Pool[] { pool.Object }); + + master.Setup(h => h.software_version).Returns(new Dictionary()); + master.Setup(h => h.ProductVersion).Returns(productVersion); + master.Setup(h => h.AppliedPatches()).Returns(new List()); + master.Setup(h => h.BuildNumberRaw).Returns(buildNumber); + master.Setup(h => h.uuid).Returns(id); + return master; + } + + + private static List GetAVersionWithGivenNumberOfPatches(int numberOfPatches) + { + var serverVersions = new List(); + + var version = new XenServerVersion("7.0.0", "XenServer Test 7", true, "", new List(), new List(), DateTime.MinValue.ToString(), "buildNo"); + for (int ii = 0; ii < numberOfPatches; ii++) + { + var patch = new XenServerPatch("patch_uuid_" + ii, "patch name " + ii, "patch description" + ii, "", "", "1.0", "", "", "1970-01-01T00:00:00Z", "", "1000"); + version.Patches.Add(patch); + version.MinimalPatches.Add(patch); + } + serverVersions.Add(version); + + return serverVersions; + } + + + private static void RemoveANumberOfPatchesPseudoRandomly(List patches, int numberOfPatchesToRemove) + { + int expectedCount = patches.Count - numberOfPatchesToRemove; + var rnd = new Random(777); //pseudo random to be able to repeat this test... + + while (patches.Count > expectedCount) + { + patches.RemoveAt(rnd.Next(patches.Count)); + } + } + + + [Test] + public void GetUpgradeSequenceForNullConnection() + { + Assert.AreEqual(XenAdmin.Core.Updates.GetUpgradeSequence(null), null); + } + + /// + /// Version exist + /// No patches in updates + /// Nothing installed on host + /// Result: update sequence has the host, but empty sequence + /// + [Test] + public void NoPatchesForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(0); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + Assert.NotNull(upgradeSequence.First().Key); + Assert.AreEqual(upgradeSequence.First().Key.uuid, master.Object.uuid); + Assert.NotNull(upgradeSequence.First().Value); + Assert.AreEqual(upgradeSequence.First().Value.Count, 0); + } + + /// + /// Version exist + /// 1 patch in updates. 1 in minimal list. + /// 1 has to be installed on host + /// Result: update sequence has the host, with the one single patch in it + /// + [Test] + public void OnePatchToBeInstalledForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(1); + var patch = serverVersions.First().Patches[0]; + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + Assert.NotNull(upgradeSequence.First().Key); + Assert.AreEqual(upgradeSequence.First().Key.uuid, master.Object.uuid); + Assert.NotNull(upgradeSequence.First().Value); + Assert.AreEqual(upgradeSequence.First().Value.Count, 1); + Assert.AreEqual(upgradeSequence.First().Value[0], patch); + } + + /// + /// Version exist + /// 100 patch in updates. 100 in minimal list. + /// 100 has to be installed on host + /// Result: update sequence has all the 100 patches in it + /// + [Test] + public void HundredPatchToBeInstalledForCurrentVersion() + { + // Arrange + var serverVersions = GetAVersionWithGivenNumberOfPatches(100); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + var seqToCheck = upgradeSequence.First(); + Assert.NotNull(seqToCheck.Key); + Assert.AreEqual(seqToCheck.Key.uuid, master.Object.uuid); + Assert.NotNull(seqToCheck.Value); + Assert.AreEqual(seqToCheck.Value.Count, 100); + + for (int ii = 100; ii < 0; --ii) + Assert.AreEqual(seqToCheck.Value[ii], serverVersions.First().Patches[ii]); + } + + /// + /// Version exist + /// 100 patch in updates. 51 in minimal list. + /// 51 has to be installed on host + /// Result: update sequence has all the 100 patches in it + /// + [Test] + public void FiftyOnePatchToBeInstalledForCurrentVersion() + { + // Arrange + var serverVersions = GetAVersionWithGivenNumberOfPatches(100); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + RemoveANumberOfPatchesPseudoRandomly(serverVersions.First().MinimalPatches, 49); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + var seqToCheck = upgradeSequence.First(); + Assert.NotNull(seqToCheck.Key); + Assert.AreEqual(seqToCheck.Key.uuid, master.Object.uuid); + Assert.NotNull(seqToCheck.Value); + Assert.AreEqual(seqToCheck.Value.Count, 51); + + foreach (var patch in seqToCheck.Value) + Assert.IsTrue(serverVersions.First().MinimalPatches.Contains(patch)); + + Assert.False(seqToCheck.Value.Exists(seqpatch => !serverVersions.First().MinimalPatches.Contains(seqpatch))); + } + + + /// + /// Version exist + /// 2 patch in updates. 1 in minimal list. + /// 1 has to be installed on host + /// Result: update sequence has the host, with the one single patch in it + /// + [Test] + public void OnePatchOutOfTwoToBeInstalledForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(2); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + RemoveANumberOfPatchesPseudoRandomly(serverVersions.First().MinimalPatches, 1); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + Assert.NotNull(upgradeSequence.First().Key); + Assert.AreEqual(upgradeSequence.First().Key.uuid, master.Object.uuid); + Assert.NotNull(upgradeSequence.First().Value); + Assert.AreEqual(upgradeSequence.First().Value.Count, 1); + Assert.AreEqual(upgradeSequence.First().Value[0], serverVersions.First().MinimalPatches[0]); + } + + + /// + /// Version exist + /// 2 patch in updates. 2 in minimal list. + /// 2 has to be installed on host + /// Result: update sequence has the host, with the one single patch in it + /// + [Test] + public void TwoPatchToBeInstalleOutOfTwodForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(2); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + Assert.NotNull(upgradeSequence.First().Key); + Assert.AreEqual(upgradeSequence.First().Key.uuid, master.Object.uuid); + Assert.NotNull(upgradeSequence.First().Value); + Assert.AreEqual(upgradeSequence.First().Value.Count, 2); + Assert.AreEqual(upgradeSequence.First().Value[0], serverVersions.First().MinimalPatches[0]); + Assert.AreEqual(upgradeSequence.First().Value[1], serverVersions.First().MinimalPatches[1]); + } + + + /// + /// Version does not exist + /// Result: update sequence does not have the host + /// + [Test] + public void NoInfoForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(200); + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber + "to_make_it_not_match"); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(0, upgradeSequence.Count); + } + + + /// + /// Updates is static class, can't be mocked without refactoring - using this method instead + /// + /// + private void SetXenServerVersionsInUpdates(List serverVersions) + { + Updates.XenServerVersions = serverVersions; + } + } +} From eb5b01bc8302b29c23a2b3bfabbb81f9f036e387 Mon Sep 17 00:00:00 2001 From: Gabor Apati-Nagy Date: Wed, 29 Jun 2016 13:45:36 +0100 Subject: [PATCH 2/2] CP-17282: Unit tests to validate the Update Sequence logic More tests following the code review Signed-off-by: Gabor Apati-Nagy --- .../BatchUpdatesTests/BatchUpdatesTests.cs | 92 ++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs index c6d80f8b5..442245d9d 100644 --- a/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs +++ b/XenAdminTests/UnitTests/BatchUpdatesTests/BatchUpdatesTests.cs @@ -44,7 +44,7 @@ namespace XenAdminTests.UnitTests public class BatchUpdatesTests { - private static Mock GetAMockHost(string productVersion, string buildNumber) + private static Mock GetAMockHost(string productVersion, string buildNumber, List applied_patches = null) { var id = System.Guid.NewGuid().ToString(); @@ -65,7 +65,7 @@ namespace XenAdminTests.UnitTests master.Setup(h => h.software_version).Returns(new Dictionary()); master.Setup(h => h.ProductVersion).Returns(productVersion); - master.Setup(h => h.AppliedPatches()).Returns(new List()); + master.Setup(h => h.AppliedPatches()).Returns(applied_patches ?? new List()); master.Setup(h => h.BuildNumberRaw).Returns(buildNumber); master.Setup(h => h.uuid).Returns(id); return master; @@ -167,6 +167,41 @@ namespace XenAdminTests.UnitTests Assert.AreEqual(upgradeSequence.First().Value[0], patch); } + + /// + /// Version exist + /// 1 patch in updates. 1 in minimal list. But it is applied already on master. + /// 0 has to be installed on host + /// + [Test] + public void AlreadyInstalledOneFromMinimalForCurrentVersion() + { + // Arrange + + var serverVersions = GetAVersionWithGivenNumberOfPatches(1); + var patch = serverVersions.First().Patches[0]; + + Pool_patch pool_patch = new Pool_patch(); + pool_patch.uuid = patch.Uuid; + + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber, new List() { pool_patch }); + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + Assert.NotNull(upgradeSequence.First().Key); + Assert.AreEqual(upgradeSequence.First().Key.uuid, master.Object.uuid); + Assert.NotNull(upgradeSequence.First().Value); + Assert.AreEqual(upgradeSequence.First().Value.Count, 0); + } + + /// /// Version exist /// 100 patch in updates. 100 in minimal list. @@ -203,7 +238,7 @@ namespace XenAdminTests.UnitTests /// Version exist /// 100 patch in updates. 51 in minimal list. /// 51 has to be installed on host - /// Result: update sequence has all the 100 patches in it + /// Result: update sequence has all the 51 patches in it /// [Test] public void FiftyOnePatchToBeInstalledForCurrentVersion() @@ -235,6 +270,57 @@ namespace XenAdminTests.UnitTests } + /// + /// Version exist + /// 100 patch in updates. 51 in minimal list. + /// 41 has to be installed on host (only 41 of 51, because 10 is already installed from the Minimal list (as well as 5 other)) + /// Result: update sequence has all the 41 patches in it and all are from Minimal List and also not installed on the host + /// + [Test] + public void FourtyOnePatchToBeInstalledForCurrentVersion() + { + // Arrange + var serverVersions = GetAVersionWithGivenNumberOfPatches(100); + RemoveANumberOfPatchesPseudoRandomly(serverVersions.First().MinimalPatches, 49); + + var pool_patches = new List(); + for (int ii = 0; ii < 10; ii++) + { + pool_patches.Add(new Pool_patch() { uuid = serverVersions.First().MinimalPatches[ii].Uuid }); + } + + var notMinimalPatchesInVersion = serverVersions.First().Patches.Where(p => !serverVersions.First().MinimalPatches.Exists(mp => mp.Uuid == p.Uuid)).ToList(); + for (int ii = 0; ii < 5; ii++) + { + pool_patches.Add(new Pool_patch() { uuid = notMinimalPatchesInVersion[ii].Uuid }); + } + + var master = GetAMockHost(serverVersions.First().Oem, serverVersions.First().BuildNumber, pool_patches); + + SetXenServerVersionsInUpdates(serverVersions); + + // Act + + var upgradeSequence = XenAdmin.Core.Updates.GetUpgradeSequence(master.Object.Connection); + + // Assert + + Assert.NotNull(upgradeSequence); + Assert.AreEqual(1, upgradeSequence.Count); + var seqToCheck = upgradeSequence.First(); + Assert.NotNull(seqToCheck.Key); + Assert.AreEqual(seqToCheck.Key.uuid, master.Object.uuid); + Assert.NotNull(seqToCheck.Value); + Assert.AreEqual(seqToCheck.Value.Count, 41); + + foreach (var patch in seqToCheck.Value) + Assert.IsTrue(serverVersions.First().MinimalPatches.Contains(patch) && !pool_patches.Exists(p => p.uuid == patch.Uuid)); + + Assert.False(seqToCheck.Value.Exists(seqpatch => !serverVersions.First().MinimalPatches.Contains(seqpatch))); + Assert.True(seqToCheck.Value.Exists(seqpatch => !pool_patches.Exists(pp => pp.uuid == seqpatch.Uuid))); + } + + /// /// Version exist /// 2 patch in updates. 1 in minimal list.