Skip to content
This repository has been archived by the owner on Oct 30, 2024. It is now read-only.

chore: Expect event sink to match predicate. #223

Merged
merged 5 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions pkgs/sdk/server/test/AssertHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using LaunchDarkly.Logging;
using System;
using LaunchDarkly.Logging;
using LaunchDarkly.TestHelpers;
using Xunit;
using Xunit.Sdk;

using static LaunchDarkly.Sdk.Server.Subsystems.DataStoreTypes;
using static LaunchDarkly.TestHelpers.JsonAssertions;

Expand Down Expand Up @@ -34,13 +35,48 @@ public static void LogMessageText(LogCapture logCapture, bool shouldHave, LogLev
}
}

private static void ThrowLogMatchException(LogCapture logCapture, bool shouldHave, LogLevel level, string text, bool isRegex) =>
private static void ThrowLogMatchException(LogCapture logCapture, bool shouldHave, LogLevel level, string text,
bool isRegex) =>
throw new AssertActualExpectedException(shouldHave, !shouldHave,
string.Format("Expected log {0} the {1} \"{2}\" at level {3}\n\nActual log output follows:\n{4}",
shouldHave ? "to have" : "not to have",
isRegex ? "pattern" : "exact message",
text,
level,
logCapture.ToString()));

/// <summary>
/// Expect that the given sink will receive an event that passes the provided predicate within the specified
/// timeout.
///
/// The total time for the execution of this method may be greater than the timeout, because its implementation
/// depends on a function which itself has a timeout.
/// </summary>
/// <param name="sink">the sink to check events from</param>
/// <param name="predicate">the predicate to run against events</param>
/// <param name="message">the message to show if the test fails</param>
/// <param name="timeout">the overall timeout</param>
/// <typeparam name="T">the type of the sink and predicate</typeparam>
public static void ExpectPredicate<T>(EventSink<T> sink, Predicate<T> predicate, string message,
TimeSpan timeout)
{
while (true)
{
var startTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();

var value = sink.ExpectValue(timeout);

if (predicate(value))
{
break;
}

if (!(DateTimeOffset.Now.ToUnixTimeMilliseconds() - startTime > timeout.TotalMilliseconds)) continue;

// XUnit 2.5+ adds Assert.Fail.
Assert.True(false, message);
return;
}
}
}
}
56 changes: 51 additions & 5 deletions pkgs/sdk/server/test/Internal/DataSources/FileDataSourceTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Linq;
using System.Threading;
using Castle.Core.Internal;
using LaunchDarkly.Sdk.Server.Integrations;
using LaunchDarkly.Sdk.Server.Interfaces;
using LaunchDarkly.Sdk.Server.Internal.Model;
Expand All @@ -8,7 +10,6 @@
using YamlDotNet.Serialization;
using Xunit;
using Xunit.Abstractions;

using static LaunchDarkly.Sdk.Server.Subsystems.DataStoreTypes;
using static LaunchDarkly.Sdk.Server.TestUtils;
using static LaunchDarkly.TestHelpers.JsonAssertions;
Expand All @@ -24,7 +25,9 @@ public class FileDataSourceTest : BaseTest
private readonly FileDataSourceBuilder factory = FileData.DataSource();
private readonly Context user = Context.New("key");

public FileDataSourceTest(ITestOutputHelper testOutput) : base(testOutput) { }
public FileDataSourceTest(ITestOutputHelper testOutput) : base(testOutput)
{
}

private IDataSource MakeDataSource() =>
factory.Build(BasicContext.WithDataSourceUpdates(_updateSink));
Expand Down Expand Up @@ -148,9 +151,52 @@ public void ModifiedFileIsReloadedIfAutoUpdateIsOn()

file.SetContentFromPath(TestUtils.TestFilePath("segment-only.json"));

var newData = _updateSink.Inits.ExpectValue(TimeSpan.FromSeconds(5));

AssertJsonEqual(DataSetAsJson(ExpectedDataSetForSegmentOnlyFile(2)), DataSetAsJson(newData));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot just do a JSON comparison if the version number is going to be incremented every time a change is detected.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't pretty, but I want the test to stop failing.

AssertHelpers.ExpectPredicate(_updateSink.Inits, actual =>
{
var segments = actual.Data.First(item => item.Key == DataModel.Segments);
var features = actual.Data.First(item => item.Key == DataModel.Features);
if (!features.Value.Items.IsNullOrEmpty())
{
return false;
}

var segmentItems = segments.Value.Items.ToList();

if (segmentItems.Count != 1)
{
return false;
}

var segmentDescriptor = segmentItems[0];
if (segmentDescriptor.Key != "seg1")
{
return false;
}

if (segmentDescriptor.Value.Version == 1)
{
return false;
}

if (!(segmentDescriptor.Value.Item is Segment segment))
{
return false;
}

if (segment.Deleted)
{
return false;
}

if (segment.Included.Count != 1)
{
return false;
}

return segment.Included[0] == "user1";
},
"Did not receive expected update from the file data source.",
TimeSpan.FromSeconds(30));
}
}
}
Expand Down