Harden BizTalk maintenance workflow and add installer
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.props" Condition="Exists('$(MSBuildToolsPath)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B2AD340B-859F-413B-8811-7FBA4BD2BC02}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>BizTalkPlatformManagementTool.Tests</RootNamespace>
|
||||
<AssemblyName>BizTalkPlatformManagementTool.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\BizTalkPlatformManagementTool\BizTalkPlatformManagementTool.csproj">
|
||||
<Project>{2C5B2C0A-F407-46C2-9E3B-1FA09FA8445A}</Project>
|
||||
<Name>BizTalkPlatformManagementTool</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BizTalkPlatformManagementTool.Models;
|
||||
using BizTalkPlatformManagementTool.Services;
|
||||
|
||||
namespace BizTalkPlatformManagementTool.Tests
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static int _failed;
|
||||
|
||||
private static int Main()
|
||||
{
|
||||
Run("RestoreStartsOnlyPreviouslyActiveArtifacts", RestoreStartsOnlyPreviouslyActiveArtifacts);
|
||||
Run("ShutdownStopsOnlyPreviouslyActiveArtifacts", ShutdownStopsOnlyPreviouslyActiveArtifacts);
|
||||
Run("SnapshotComparisonUsesCompositeIdentity", SnapshotComparisonUsesCompositeIdentity);
|
||||
Run("SnapshotServerValidationIsSafe", SnapshotServerValidationIsSafe);
|
||||
Run("JsonStoreReplacesAtomically", JsonStoreReplacesAtomically);
|
||||
Console.WriteLine(_failed == 0 ? "PASS: 5 tests" : "FAIL: " + _failed + " test(s)");
|
||||
return _failed == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
private static void RestoreStartsOnlyPreviouslyActiveArtifacts()
|
||||
{
|
||||
var snapshot = FullSnapshot();
|
||||
var plan = new BizTalkOperationService(null).CreateRestorePlan(snapshot, "BIZ01");
|
||||
AssertEqual(4, plan.Steps.Count(x => x.Execute), "restore executable step count");
|
||||
Assert(plan.Steps.Any(x => x.Kind == "HostInstance" && x.Name == "HostStarted"), "started host missing");
|
||||
Assert(plan.Steps.Any(x => x.Kind == "SendPort" && x.Name == "SendStarted"), "started send port missing");
|
||||
Assert(plan.Steps.Any(x => x.Kind == "Orchestration" && x.Name == "OrchStarted"), "started orchestration missing");
|
||||
AssertEqual("AssemblyName", plan.Steps.Single(x => x.Kind == "Orchestration").QualifierProperty, "orchestration qualifier property");
|
||||
var receive = plan.Steps.Single(x => x.Kind == "ReceiveLocation");
|
||||
AssertEqual("ReceivePortName", receive.QualifierProperty, "receive qualifier property");
|
||||
AssertEqual("RP1", receive.QualifierValue, "receive qualifier value");
|
||||
Assert(!plan.Steps.Any(x => x.Name == "SendStopped" || x.Name == "SendBound" || x.Name == "ReceiveDisabled"), "inactive artifacts must remain untouched");
|
||||
}
|
||||
|
||||
private static void ShutdownStopsOnlyPreviouslyActiveArtifacts()
|
||||
{
|
||||
var plan = new BizTalkOperationService(null).CreateShutdownPlan(FullSnapshot(), "BIZ01");
|
||||
AssertEqual(4, plan.Steps.Count(x => x.Execute), "shutdown executable step count");
|
||||
Assert(!plan.Steps.Any(x => x.Name == "SendStopped" || x.Name == "SendBound" || x.Name == "ReceiveDisabled"), "inactive artifacts must not be stopped");
|
||||
}
|
||||
|
||||
private static void SnapshotComparisonUsesCompositeIdentity()
|
||||
{
|
||||
var before = EmptySnapshot("BIZ01");
|
||||
var after = EmptySnapshot("BIZ01");
|
||||
before.Applications.Add(App("AppA", ArtifactStates.SendPortStarted));
|
||||
before.Applications.Add(App("AppB", ArtifactStates.SendPortStopped));
|
||||
after.Applications.Add(App("AppA", ArtifactStates.SendPortStopped));
|
||||
after.Applications.Add(App("AppB", ArtifactStates.SendPortStopped));
|
||||
var diff = SnapshotComparer.Compare(before, after);
|
||||
AssertEqual(1, diff.ArtifactDifferences.Count, "composite send port comparison");
|
||||
AssertEqual("AppA", diff.ArtifactDifferences[0].Application, "changed application");
|
||||
}
|
||||
|
||||
private static void SnapshotServerValidationIsSafe()
|
||||
{
|
||||
BizTalkOperationService.ValidateSnapshot(EmptySnapshot("biz01.domain.local"), "BIZ01");
|
||||
AssertThrows<InvalidDataException>(() => BizTalkOperationService.ValidateSnapshot(EmptySnapshot("BIZ02"), "BIZ01"), "foreign server must be rejected");
|
||||
}
|
||||
|
||||
private static void JsonStoreReplacesAtomically()
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "BizTalkPlatformManagementTool.Tests." + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(directory);
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(directory, "state.json");
|
||||
JsonFileStore.Save(path, EmptySnapshot("BIZ01"));
|
||||
JsonFileStore.Save(path, EmptySnapshot("BIZ02"));
|
||||
var loaded = JsonFileStore.Load<BizTalkSnapshot>(path);
|
||||
AssertEqual("BIZ02", loaded.Server, "atomic replacement payload");
|
||||
AssertEqual(0, Directory.GetFiles(directory, "*.tmp.*").Length, "temporary files");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static BizTalkSnapshot FullSnapshot()
|
||||
{
|
||||
var snapshot = EmptySnapshot("BIZ01");
|
||||
var app = new ApplicationSnapshot { Application = "Orders" };
|
||||
app.ReceiveLocations.Add(new ReceiveLocationState { Application = "Orders", Name = "ReceiveEnabled", ReceivePortName = "RP1", Enabled = true });
|
||||
app.ReceiveLocations.Add(new ReceiveLocationState { Application = "Orders", Name = "ReceiveDisabled", ReceivePortName = "RP1", Enabled = false });
|
||||
app.SendPorts.Add(new SendPortState { Application = "Orders", Name = "SendStarted", Status = ArtifactStates.SendPortStarted });
|
||||
app.SendPorts.Add(new SendPortState { Application = "Orders", Name = "SendStopped", Status = ArtifactStates.SendPortStopped });
|
||||
app.SendPorts.Add(new SendPortState { Application = "Orders", Name = "SendBound", Status = ArtifactStates.SendPortBound });
|
||||
app.Orchestrations.Add(new OrchestrationState { Application = "Orders", Name = "OrchStarted", OrchestrationStatus = ArtifactStates.OrchestrationStarted, AssemblyName = "Orders.Processes" });
|
||||
app.Orchestrations.Add(new OrchestrationState { Application = "Orders", Name = "OrchStopped", OrchestrationStatus = ArtifactStates.OrchestrationStopped });
|
||||
snapshot.Applications.Add(app);
|
||||
snapshot.HostInstances.Add(new HostInstanceState { InstanceName = "HostStarted", Server = "BIZ01", RawState = ArtifactStates.HostStarted });
|
||||
snapshot.HostInstances.Add(new HostInstanceState { InstanceName = "HostStopped", Server = "BIZ01", RawState = ArtifactStates.HostStopped });
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private static BizTalkSnapshot EmptySnapshot(string server)
|
||||
{
|
||||
return new BizTalkSnapshot { Server = server, CreatedAt = DateTime.Now.ToString("s"), ToolVersion = BizTalkOperationService.Version };
|
||||
}
|
||||
|
||||
private static ApplicationSnapshot App(string name, int sendStatus)
|
||||
{
|
||||
var app = new ApplicationSnapshot { Application = name };
|
||||
app.SendPorts.Add(new SendPortState { Application = name, Name = "SharedName", Status = sendStatus });
|
||||
return app;
|
||||
}
|
||||
|
||||
private static void Run(string name, Action test)
|
||||
{
|
||||
try { test(); Console.WriteLine("PASS: " + name); }
|
||||
catch (Exception ex) { _failed++; Console.WriteLine("FAIL: " + name + " - " + ex.Message); }
|
||||
}
|
||||
|
||||
private static void Assert(bool condition, string message)
|
||||
{
|
||||
if (!condition) throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
private static void AssertEqual<T>(T expected, T actual, string label)
|
||||
{
|
||||
if (!object.Equals(expected, actual)) throw new InvalidOperationException(label + ": expected=" + expected + ", actual=" + actual);
|
||||
}
|
||||
|
||||
private static void AssertThrows<T>(Action action, string label) where T : Exception
|
||||
{
|
||||
try { action(); }
|
||||
catch (T) { return; }
|
||||
throw new InvalidOperationException(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user