Skip to content

Commit

Permalink
Added an option of creating a service message writer that doesn't set…
Browse files Browse the repository at this point in the history
… a top-level flowId attribute on messages
  • Loading branch information
boris-yakhno authored and qodana-bot committed Aug 24, 2023
1 parent c2db442 commit 71032ce
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace JetBrains.TeamCity.ServiceMessages.Tests.Read
using ServiceMessages.Read;

[TestFixture]
[Explicit]
public class ServiceMessageParserPerformanceTest
{
private static string GenerateTestData(int sz)
Expand Down Expand Up @@ -77,4 +78,4 @@ public void Parse10000()
Console.Out.WriteLine(trash);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.6;net45;netcoreapp1.0;netcoreapp2.0;netcoreapp3.0</TargetFrameworks>
<AssemblyName>TeamCity.ServiceMessages.Tests</AssemblyName>
Expand All @@ -14,16 +14,17 @@
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>TeamCity.ServiceMessages.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
</PropertyGroup>

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Moq" Version="4.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="NUnit"><Version>3.12.0</Version></PackageReference>
</ItemGroup>

</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TeamCity.ServiceMessages\TeamCity.ServiceMessages.csproj" />
</ItemGroup>

</Project>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace JetBrains.TeamCity.ServiceMessages.Tests.Write.Specials
{
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using ServiceMessages.Write;
using ServiceMessages.Write.Special;
using ServiceMessages.Write.Special.Impl;

[TestFixture]
public class FlowAwareServiceMessageWriterTest
{
[Test]
public void ShouldNotAddFlowIdAttributeToServiceMessageWhenFlowIdIsNotSet()
{
var processorMock = new Mock<IServiceMessageProcessor>();
var flowAwareWriter = new FlowAwareServiceMessageWriter(
null,
processorMock.Object,
Mock.Of<IFlowIdGenerator>(),
new List<IServiceMessageUpdater>());

var serviceMessage = new ServiceMessage("foo");
flowAwareWriter.AddServiceMessage(serviceMessage);

processorMock.Verify(x => x.AddServiceMessage(
It.Is<IServiceMessage>(m => m.Keys.All(k => k != "flowId"))));
}

[Test]
public void ShouldAddFlowIdAttributeToServiceMessageWhenFlowIdIsSet()
{
string flowId = "123";
var processorMock = new Mock<IServiceMessageProcessor>();
var flowAwareWriter = new FlowAwareServiceMessageWriter(
flowId,
processorMock.Object,
Mock.Of<IFlowIdGenerator>(),
new List<IServiceMessageUpdater>());

var serviceMessage = new ServiceMessage("foo");
flowAwareWriter.AddServiceMessage(serviceMessage);

processorMock.Verify(x => x.AddServiceMessage(
It.Is<IServiceMessage>(m => m.GetValue("flowId") == flowId)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ namespace JetBrains.TeamCity.ServiceMessages.Tests.Write.Specials

public abstract class TeamCityFlowWriterBaseTest<T> : TeamCityWriterBaseTest<T>
{
protected abstract T Create(IFlowServiceMessageProcessor proc);
protected abstract T Create(IFlowAwareServiceMessageProcessor proc);

protected sealed override T Create(IServiceMessageProcessor proc)
{
return Create(new FlowServiceMessageWriter(proc, new DefaultFlowIdGenerator(), Enumerable.Empty<IServiceMessageUpdater>()));
var flowIdGenerator = new DefaultFlowIdGenerator();
return Create(new FlowAwareServiceMessageWriter(flowIdGenerator.NewFlowId(), proc, flowIdGenerator, Enumerable.Empty<IServiceMessageUpdater>()));
}

protected override ToStringProcessor CreateProcessor()
Expand Down Expand Up @@ -70,4 +71,4 @@ private string FlowToString(string flowId)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
namespace JetBrains.TeamCity.ServiceMessages.Tests.Write.Specials
{
using System;
using System.Linq;
using Moq;
using NUnit.Framework;
using ServiceMessages.Write.Special;
using ServiceMessages.Write.Special.Impl;
Expand All @@ -25,7 +27,7 @@ namespace JetBrains.TeamCity.ServiceMessages.Tests.Write.Specials
[TestFixture]
public class TeamCityFlowWriterTest : TeamCityFlowWriterBaseTest<TeamCityFlowWriter<IDisposable>>
{
protected override TeamCityFlowWriter<IDisposable> Create(IFlowServiceMessageProcessor proc)
protected override TeamCityFlowWriter<IDisposable> Create(IFlowAwareServiceMessageProcessor proc)
{
return new TeamCityFlowWriter<IDisposable>(proc, (x, _) => x, DisposableDelegate.Empty);
}
Expand All @@ -43,5 +45,24 @@ public void TestOpenCloseBlock()
"##teamcity[flowStarted parent='1' flowId='2']",
"##teamcity[flowFinished flowId='2']");
}

[Test]
public void ShouldNotAddParentFlowAttributeToMessageAfterOpeningNewFlowIfThereIsNoParentFlow()
{
var parentFlowAwareProcessorMock = new Mock<IFlowAwareServiceMessageProcessor>();
var childFlowAwareProcessorMock = new Mock<IFlowAwareServiceMessageProcessor>();
parentFlowAwareProcessorMock.SetupGet(x => x.FlowId).Returns((string)null);
parentFlowAwareProcessorMock.Setup(x => x.ForNewFlow()).Returns(childFlowAwareProcessorMock.Object);
var teamCityFlowWriter = new TeamCityFlowWriter<IDisposable>(
parentFlowAwareProcessorMock.Object,
(handler, processor) => Mock.Of<IDisposable>(),
Mock.Of<IDisposable>());

teamCityFlowWriter.OpenFlow();

childFlowAwareProcessorMock.Verify(
x => x.AddServiceMessage(
It.Is<IServiceMessage>(m => m.Keys.All(k => k != "parent"))));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace JetBrains.TeamCity.ServiceMessages.Tests.Write.Specials
[TestFixture]
public class TeamCityTestsWriterTest : TeamCityFlowWriterBaseTest<ITeamCityTestsWriter>
{
protected override ITeamCityTestsWriter Create(IFlowServiceMessageProcessor proc)
protected override ITeamCityTestsWriter Create(IFlowAwareServiceMessageProcessor proc)
{
return new TeamCityTestSuiteBlock(proc, DisposableDelegate.Empty);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public virtual void AddServiceMessage(IServiceMessage serviceMessage)

public abstract class TeamCityWriterBaseTest : TeamCityFlowWriterBaseTest<ITeamCityWriter>
{
protected override ITeamCityWriter Create(IFlowServiceMessageProcessor proc)
protected override ITeamCityWriter Create(IFlowAwareServiceMessageProcessor proc)
{
return new TeamCityWriterImpl(proc, DisposableDelegate.Empty);
}
Expand Down
3 changes: 2 additions & 1 deletion TeamCity.ServiceMessages/TeamCity.ServiceMessages.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
<DelaySign>False</DelaySign>
<Authors>JetBrains</Authors>
<Title>TeamCity Service Messages read/write access</Title>
<Description>This library provides read/write access to TeamCity Service messages. Take a look at the description of service messages at http://confluence.jetbrains.net/display/TCDL/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ServiceMessages</Description>
<Description>This library provides read/write access to TeamCity Service messages. The documentation on service messages can be found at https://www.jetbrains.com/help/teamcity/service-messages.html</Description>
<PackageLicenseUrl>https://github.com/JetBrains/TeamCity.ServiceMessages/raw/master/LICENSE.txt</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/JetBrains/TeamCity.ServiceMessages</PackageProjectUrl>
<PackageIconUrl>https://github.com/JetBrains/TeamCity.ServiceMessages/raw/master/icon.png</PackageIconUrl>
<PackageReleaseNotes>Release descriptions are available at https://github.com/JetBrains/TeamCity.ServiceMessages/releases</PackageReleaseNotes>
<RepositoryUrl>https://github.com/JetBrains/TeamCity.ServiceMessages.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>TeamCity ServiceMessage ServiceMessages</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace JetBrains.TeamCity.ServiceMessages.Write.Special
/// <summary>
/// FlowId aware implementation of ServiceMessagesProcessor
/// </summary>
public interface IFlowServiceMessageProcessor : IServiceMessageProcessor
public interface IFlowAwareServiceMessageProcessor : IServiceMessageProcessor
{
/// <summary>
/// Current flow Id
Expand All @@ -31,6 +31,6 @@ public interface IFlowServiceMessageProcessor : IServiceMessageProcessor
/// </summary>
/// <returns></returns>
[NotNull]
IFlowServiceMessageProcessor ForNewFlow();
IFlowAwareServiceMessageProcessor ForNewFlow();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,25 @@ namespace JetBrains.TeamCity.ServiceMessages.Write.Special
public interface ITeamCityServiceMessages
{
/// <summary>
/// Created writer that generates service messages to a Console.Out
/// Creates a writer that outputs service messages to Console.Out
/// </summary>
/// <remarks>
/// Implementation does not support multiple-threads.
/// If you need to log more me
/// </remarks>
/// <returns></returns>
[NotNull]
ITeamCityWriter CreateWriter();

/// <summary>
/// Creates writer that translates service messages to the given
/// delegate.
/// Creates a writer that uses the provided delegate to output service messages
/// </summary>
/// <param name="destination">generated service messages processor</param>
/// <param name="addFlowIdsOnTopLevelMessages">specifies whether messages written without explicitly opening a flow should be marked with a common flow id</param>
/// <returns></returns>
[NotNull]
ITeamCityWriter CreateWriter(Action<string> destination);
ITeamCityWriter CreateWriter(Action<string> destination, bool addFlowIdsOnTopLevelMessages = true);

/// <summary>
/// Adds user-specific service message updater to the list of service message updaters.
/// </summary>
/// <param name="updater">updater instance</param>
void AddServiceMessageUpdater([NotNull] IServiceMessageUpdater updater);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,35 @@ namespace JetBrains.TeamCity.ServiceMessages.Write.Special.Impl
using Updater;

/// <summary>
/// Servivce message acceptor implementation with support of IServiceMessageUpdater chains
/// Service message acceptor implementation that is aware of service message flows and supports IServiceMessageUpdater chains
/// </summary>
public class FlowServiceMessageWriter : IFlowServiceMessageProcessor
public class FlowAwareServiceMessageWriter : IFlowAwareServiceMessageProcessor
{
private readonly IFlowIdGenerator _generator;
private readonly IServiceMessageProcessor _processor;
private readonly List<IServiceMessageUpdater> _updaters;

/// <summary>
/// Creates generic processor that calls messages updaters and sends output to provided deledate.
/// Creates generic processor that calls messages updaters and sends output to provided delegate.
/// </summary>
/// <param name="serviceMessageFlowId">id of the flow assigned to messages written through this processor, can be null</param>
/// <param name="processor">writer of service messages objects</param>
/// <param name="generator">flow id generator that is called to create next flowId</param>
/// <param name="updaters">service message updaters, i.e. timestamp updater</param>
public FlowServiceMessageWriter([NotNull] IServiceMessageProcessor processor,
public FlowAwareServiceMessageWriter(
string serviceMessageFlowId,
[NotNull] IServiceMessageProcessor processor,
[NotNull] IFlowIdGenerator generator,
[NotNull] IEnumerable<IServiceMessageUpdater> updaters)
{
if (processor == null) throw new ArgumentNullException(nameof(processor));
if (generator == null) throw new ArgumentNullException(nameof(generator));
if (updaters == null) throw new ArgumentNullException(nameof(updaters));

FlowId = serviceMessageFlowId;
_processor = processor;
_generator = generator;
_updaters = IncludeFlowId(updaters);
_updaters = AddFlowIdUpdater(updaters.ToList());
}

public void AddServiceMessage(IServiceMessage serviceMessage)
Expand All @@ -54,26 +59,32 @@ public void AddServiceMessage(IServiceMessage serviceMessage)
_processor.AddServiceMessage(_updaters.Aggregate(serviceMessage, (current, updater) => updater.UpdateServiceMessage(current)));
}

public string FlowId => _updaters.OfType<FlowMessageUpdater>().First().FlowId;
public string FlowId { get; }

/// <summary>
/// Creates new ServiceMessage updater that uses specified FlowId
/// </summary>
public IFlowServiceMessageProcessor ForNewFlow()
public IFlowAwareServiceMessageProcessor ForNewFlow()
{
return new FlowServiceMessageWriter(
return new FlowAwareServiceMessageWriter(
_generator.NewFlowId(),
_processor,
_generator,
IncludeFlowId(_updaters)
_updaters
);
}

[NotNull]
private List<IServiceMessageUpdater> IncludeFlowId([NotNull] IEnumerable<IServiceMessageUpdater> updaters)
private List<IServiceMessageUpdater> AddFlowIdUpdater([NotNull] List<IServiceMessageUpdater> updaters)
{
if (FlowId == null)
{
return updaters;
}

return updaters.Where(x => !(x is FlowMessageUpdater))
.Union(new[] {new FlowMessageUpdater(_generator)})
.Union(new[] {new FlowMessageUpdater(FlowId)})
.ToList();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class TeamCityWriterImpl : TeamCityWriterFacade, ISubWriter
private readonly IEnumerable<ISubWriter> _writeCheck;

public TeamCityWriterImpl(
[NotNull] IFlowServiceMessageProcessor processor,
[NotNull] IFlowAwareServiceMessageProcessor processor,
[NotNull] IDisposable dispose)
: this(processor,
new TeamCityFlowWriter<ITeamCityWriter>(processor, (handler, writer) => new TeamCityWriterImpl(writer, handler), DisposableDelegate.Empty),
Expand Down Expand Up @@ -89,4 +89,4 @@ protected override void CheckConsistency()
AssertNoChildOpened();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,20 @@ namespace JetBrains.TeamCity.ServiceMessages.Write.Special.Impl.Updater
/// </summary>
public class FlowMessageUpdater : IServiceMessageUpdater
{
[NotNull] private readonly string _flowId;

/// <summary>
/// Constructs updater
/// </summary>
/// <param name="flowId">flowId set to all messages</param>
public FlowMessageUpdater([NotNull] string flowId)
{
FlowId = flowId ?? throw new ArgumentNullException(nameof(flowId));
_flowId = flowId ?? throw new ArgumentNullException(nameof(flowId));
}

/// <summary>
/// Creates flow id from given generator instance
/// </summary>
/// <param name="flowId"></param>
public FlowMessageUpdater([NotNull] IFlowIdGenerator flowId) : this(flowId.NewFlowId())
{
}

public string FlowId { [NotNull] get; }

public IServiceMessage UpdateServiceMessage(IServiceMessage message)
{
return message.DefaultValue != null || message.GetValue("flowId") != null ? message : new PatchedServiceMessage(message) { { "flowId", FlowId } };
return message.DefaultValue != null || message.GetValue("flowId") != null ? message : new PatchedServiceMessage(message) { { "flowId", _flowId } };
}
}
}
}
Loading

0 comments on commit 71032ce

Please sign in to comment.