mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-25 11:49:52 +01:00
231 lines
10 KiB
C#
231 lines
10 KiB
C#
|
/* 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.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Reflection;
|
|||
|
using Moq;
|
|||
|
using NUnit.Framework;
|
|||
|
using XenAdmin.Actions;
|
|||
|
using XenAdmin.Core;
|
|||
|
using XenAPI;
|
|||
|
|
|||
|
namespace XenAdminTests.XenModelTests
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// This unit test relies on a list of call versions. For ease, they are included
|
|||
|
/// as a csv file
|
|||
|
///
|
|||
|
/// To update the csv call list:
|
|||
|
/// 1. Build your own version on the api bindings.
|
|||
|
/// 2. Look in the generated code output directory (not the code that's been packaged) eg. build.hg/output/api-bindings
|
|||
|
/// 3. Copy out the "callVersions.csv" and replace the one in TestResources
|
|||
|
///
|
|||
|
/// To Add New Actions:
|
|||
|
/// 1. Go down to the container of actions called "Actions"
|
|||
|
/// 2. Add enough unit test code to get your action to run - this is failrly minimal
|
|||
|
///
|
|||
|
/// To Add a new version:
|
|||
|
/// 1. Add a const string containing the correct name as extracted into the csv file
|
|||
|
/// 2. Add this to the test ctor
|
|||
|
/// 3. Add a DatabaseInfo member
|
|||
|
/// 4. Check the unsupportedVersions are up to date
|
|||
|
/// </summary>
|
|||
|
[TestFixture]
|
|||
|
internal class TestAPICallVersions : UnitTester_TestFixture
|
|||
|
{
|
|||
|
public TestAPICallVersions()
|
|||
|
: base(rio, miami, symc, orlando, george, midnight, cowley,
|
|||
|
boston, sanibel, tampa, tallahassee, clearwater, sarasota, thefuture)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
private void SetupConnection(DatabaseInfo id)
|
|||
|
{
|
|||
|
Mock<Host> host = ObjectManager.NewXenObject<Host>(id.name);
|
|||
|
host.Setup(h => h.ProductVersion).Returns(id.version);
|
|||
|
ObjectManager.MockConnectionFor(id.name).Setup(c => c.Resolve(It.IsAny<XenRef<Host>>())).Returns(host.Object);
|
|||
|
}
|
|||
|
|
|||
|
[Test]
|
|||
|
public void CompareCalls()
|
|||
|
{
|
|||
|
ReadCallList();
|
|||
|
foreach (DatabaseInfo info in versionData.Where( v=> !unsupportedVersions.Contains(v.name)))
|
|||
|
{
|
|||
|
SetupConnection(info);
|
|||
|
foreach (AsyncAction myAction in Actions(info.name))
|
|||
|
{
|
|||
|
List<string> calls = ExtractApiCallList(myAction);
|
|||
|
VerifyCalls(calls, info);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#region Data
|
|||
|
|
|||
|
private const string tampa = "tampa";
|
|||
|
private const string boston = "boston";
|
|||
|
private const string rio = "rio";
|
|||
|
private const string sanibel = "sanibel";
|
|||
|
private const string cowley = "cowley";
|
|||
|
private const string george = "george";
|
|||
|
private const string miami = "miami";
|
|||
|
private const string midnight = "midnight-ride";
|
|||
|
private const string orlando = "orlando";
|
|||
|
private const string symc = "symc";
|
|||
|
private const string tallahassee = "tallahassee";
|
|||
|
private const string clearwater = "clearwater";
|
|||
|
private const string sarasota = "sarasota";
|
|||
|
private const string thefuture = "Oct 21, 2015";
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Complete lookup of version numbers
|
|||
|
/// </summary>
|
|||
|
private readonly List<DatabaseInfo> versionData = new List<DatabaseInfo>
|
|||
|
{
|
|||
|
new DatabaseInfo {name = rio, version = "4.0.0"},
|
|||
|
new DatabaseInfo {name = miami, version = "4.1.0"},
|
|||
|
new DatabaseInfo {name = symc, version = "4.1.0"},
|
|||
|
new DatabaseInfo {name = orlando, version = "5.0.0"},
|
|||
|
new DatabaseInfo {name = george, version = "5.5.0"},
|
|||
|
new DatabaseInfo {name = midnight, version = "5.6.0"},
|
|||
|
new DatabaseInfo {name = cowley, version = "5.6.100"},
|
|||
|
new DatabaseInfo {name = boston, version = "6.0.0"},
|
|||
|
new DatabaseInfo {name = sanibel, version = "6.0.2"},
|
|||
|
new DatabaseInfo {name = tampa, version = "6.1.0"},
|
|||
|
new DatabaseInfo {name = tallahassee, version = "6.1.1"},
|
|||
|
new DatabaseInfo {name = clearwater, version = "6.1.2"},
|
|||
|
new DatabaseInfo {name = sarasota, version = "6.5.0"},
|
|||
|
new DatabaseInfo {name = thefuture, version = "9999.9999.9999"},
|
|||
|
};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// These versions are not checked for compatability
|
|||
|
/// </summary>
|
|||
|
private readonly List<string> unsupportedVersions = new List<string>
|
|||
|
{
|
|||
|
rio, miami, symc, orlando, george
|
|||
|
};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Additional calls that are added to the call list or overloads for the list
|
|||
|
/// </summary>
|
|||
|
private readonly Dictionary<string, string> additionalCalls = new Dictionary<string, string>
|
|||
|
{
|
|||
|
{"vif_destroy", "rio"}
|
|||
|
};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// List of actions to test - you need to add one per test of interest
|
|||
|
/// TODO: Probably best to add this to a factory at some point
|
|||
|
/// TODO: Add more actions
|
|||
|
/// </summary>
|
|||
|
/// <param name="id"></param>
|
|||
|
/// <returns></returns>
|
|||
|
private IEnumerable<AsyncAction> Actions(string id)
|
|||
|
{
|
|||
|
yield return ActionFactory.MockActionFor(id, typeof (DeleteVIFAction));
|
|||
|
yield return ActionFactory.MockActionFor(id, typeof(AddRemoveRolesAction));
|
|||
|
}
|
|||
|
|
|||
|
private Dictionary<string, string> CallsInProductSince { get; set; }
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Helper Classes And Methods
|
|||
|
private class DatabaseInfo
|
|||
|
{
|
|||
|
public string name;
|
|||
|
public string version;
|
|||
|
}
|
|||
|
|
|||
|
private void ReadCallList()
|
|||
|
{
|
|||
|
CallsInProductSince = additionalCalls;
|
|||
|
using (StreamReader sr = new StreamReader(TestResource("callVersions.csv")))
|
|||
|
{
|
|||
|
while (!sr.EndOfStream)
|
|||
|
{
|
|||
|
string line = sr.ReadLine();
|
|||
|
if (String.IsNullOrEmpty(line))
|
|||
|
continue;
|
|||
|
|
|||
|
string[] words = line.Split(',');
|
|||
|
if (!CallsInProductSince.ContainsKey(words[0]))
|
|||
|
CallsInProductSince.Add(words[0], words[1]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void VerifyCalls(List<string> callsMade, DatabaseInfo dbInfo)
|
|||
|
{
|
|||
|
Assert.That(callsMade.Count, Is.GreaterThan(0), "The action made no api calls");
|
|||
|
|
|||
|
foreach (string call in callsMade)
|
|||
|
{
|
|||
|
|
|||
|
if(call.Contains("_get_allowed_operations"))
|
|||
|
continue;
|
|||
|
|
|||
|
if(!CallsInProductSince.ContainsKey(call))
|
|||
|
{
|
|||
|
string msg = String.Format("Call missing '{0}'- suggest an update of the call list", call);
|
|||
|
Assert.Fail(msg);
|
|||
|
}
|
|||
|
|
|||
|
string closureCall = call;
|
|||
|
string callVersionNumber = versionData.Find(d => d.name == CallsInProductSince[closureCall]).version;
|
|||
|
|
|||
|
Assert.IsTrue(Helpers.productVersionCompare(callVersionNumber, dbInfo.version) <= 0,
|
|||
|
String.Format("Call '{0}' made out of version. It was added in version '{1}' but called in version '{2}'", call, callVersionNumber, dbInfo.version));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private List<string> ExtractApiCallList(AsyncAction myAction)
|
|||
|
{
|
|||
|
RbacMethodList rbacMethods = new RbacMethodList();
|
|||
|
RbacCollectorProxy.GetProxy(rbacMethods);
|
|||
|
Session session = new Session(RbacCollectorProxy.GetProxy(rbacMethods), myAction.Connection);
|
|||
|
myAction.RunExternal(session);
|
|||
|
return rbacMethods.ConvertAll(c => c.Method.ToLower().Replace('.', '_').Replace("async_", ""));
|
|||
|
}
|
|||
|
|
|||
|
private string TestResource(string name)
|
|||
|
{
|
|||
|
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\TestResources\" + name;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|