diff --git a/.editorconfig b/.editorconfig index 0eb3db006..2e6b25597 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,13 +8,19 @@ root = true indent_style = space indent_size = 4 trim_trailing_whitespace = true -insert_final_newline = false +insert_final_newline = true # SA1200: Using directives should be placed correctly dotnet_diagnostic.SA1200.severity = none +[*.cake] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true + [*.{xaml,xml,config,manifest}] indent_style = space indent_size = 2 trim_trailing_whitespace = true -insert_final_newline = false \ No newline at end of file +insert_final_newline = false diff --git a/.gitignore b/.gitignore index c7c40f2de..6769f2c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,4 @@ cake-build/addins/ cake-build/modules/ build-output/ unity-packager/ +test-results/ diff --git a/cake-build/helpers/test-retry.cake b/cake-build/helpers/test-retry.cake index fe95cb341..5c82875f0 100644 --- a/cake-build/helpers/test-retry.cake +++ b/cake-build/helpers/test-retry.cake @@ -18,25 +18,41 @@ public class TestRetryHelper var failedTests = new List(); if (!_context.FileExists(resultsPath)) + { + _context.Warning($"Results file not found: {resultsPath}"); return failedTests; + } try { var doc = System.Xml.Linq.XDocument.Load(resultsPath.FullPath); - var nodes = doc.XPathSelectElements("//test-case[@success='False']"); - foreach (var node in nodes) + // XUnit v2 XML format uses @result='Fail' attribute + // Try both formats for compatibility + var failedNodes = doc.XPathSelectElements("//test[@result='Fail']") + .Concat(doc.XPathSelectElements("//test-case[@result='Fail']")) + .Concat(doc.XPathSelectElements("//test-case[@success='False']")); + + foreach (var node in failedNodes) { var testName = node.Attribute("name")?.Value; if (!string.IsNullOrEmpty(testName)) { - failedTests.Add(TrimTestMethod(testName)); + var trimmedName = TrimTestMethod(testName); + if (!failedTests.Contains(trimmedName)) + { + _context.Information($"Found failed test: {trimmedName}"); + failedTests.Add(trimmedName); + } } } + + _context.Information($"Total failed tests found: {failedTests.Count}"); } catch (Exception ex) { _context.Warning($"Error parsing XUnit results: {ex.Message}"); + _context.Warning($"Stack trace: {ex.StackTrace}"); } return failedTests; @@ -97,6 +113,78 @@ public class TestRetryHelper } return basePath; } + + /// + /// Displays a formatted summary table of test retry results + /// + /// The type of tests (e.g., ".NET Framework Unit", ".NET Standard Integration") + /// List of tests that failed initially + /// List of tests that still failed after retry + public void DisplayRetryResultsSummary(string testType, List initialFailedTests, List stillFailedTests) + { + var passedTests = initialFailedTests.Except(stillFailedTests).ToList(); + + if (passedTests.Any()) + { + _context.Information(""); + _context.Information("✓ Tests that PASSED on retry:"); + foreach (var test in passedTests) + { + _context.Information($" • {test}"); + } + } + + if (stillFailedTests.Any()) + { + _context.Information(""); + _context.Warning("✗ Tests that FAILED after retry:"); + foreach (var test in stillFailedTests) + { + _context.Warning($" • {test}"); + } + } + else + { + _context.Information(""); + _context.Information("✓ All retried tests passed!"); + } + + _context.Information(""); + } + + /// + /// Validates failed tests and throws an exception if any non-flaky tests failed. + /// Tests ending with "_Flaky" are ignored. + /// + /// List of tests that still failed after retry + public void ValidateFlakyTests(List stillFailedTests) + { + if (!stillFailedTests.Any()) + { + return; + } + + var nonFlakyFailedTests = stillFailedTests.Where(test => !test.EndsWith("_Flaky")).ToList(); + + if (nonFlakyFailedTests.Any()) + { + _context.Error(""); + _context.Error($"✗ {nonFlakyFailedTests.Count} non-flaky test(s) failed after retry:"); + foreach (var test in nonFlakyFailedTests) + { + _context.Error($" • {test}"); + } + _context.Error(""); + + throw new Exception($"{nonFlakyFailedTests.Count} test(s) failed after retry"); + } + else + { + _context.Information(""); + _context.Information($"ℹ All {stillFailedTests.Count} failed test(s) are marked as flaky (ending with '_Flaky')"); + _context.Information(""); + } + } } var testRetryHelper = new TestRetryHelper(Context); diff --git a/cake-build/tasks/build.cake b/cake-build/tasks/build.cake index 8eec9a8a7..d3049bd80 100644 --- a/cake-build/tasks/build.cake +++ b/cake-build/tasks/build.cake @@ -6,12 +6,12 @@ Task("_Clean") .Does(() => { Information("Cleaning build directories..."); - + // Clean the main solution which includes all core projects (NetFramework, NetStandard, iOS, Android, Tests, etc.) CleanSolution(); - + // Clean custom output directories that are not part of standard project outputs - CleanDirectory(paths.TestResults); + CleanDirectory(paths.TestResults); }); Task("_Restore_Main") @@ -25,9 +25,9 @@ Task("_Version") .Does(() => { Information($"Setting version to {version}"); - + var assemblyInfoPath = paths.Src.CombineWithFilePath("CommonAssemblyInfo.cs"); - + CreateAssemblyInfo(assemblyInfoPath, new AssemblyInfoSettings { Company = "Ably", @@ -43,14 +43,14 @@ Task("_NetFramework_Build") .Does(() => { Information("Building .NET Framework solution..."); - + var settings = buildConfig.ApplyStandardSettings( new MSBuildSettings(), configuration ); - + settings = settings.WithTarget("Build"); - + MSBuild(paths.NetFrameworkSolution, settings); }); @@ -58,22 +58,22 @@ Task("_NetStandard_Build") .Does(() => { Information("Building .NET Standard solution..."); - + var settings = new DotNetBuildSettings { Configuration = configuration, NoRestore = true }; var msbuildSettings = new DotNetMSBuildSettings(); - - + + if (!string.IsNullOrEmpty(defineConstants)) { msbuildSettings = msbuildSettings.WithProperty("DefineConstants", defineConstants); } - + settings.MSBuildSettings = msbuildSettings; - + DotNetBuild(paths.NetStandardSolution.FullPath, settings); }); @@ -87,20 +87,20 @@ Task("_Xamarin_Build") .Does(() => { Information("Building Xamarin solution..."); - + if (!FileExists(paths.XamarinSolution)) { Warning("Xamarin solution not found, skipping build"); return; } - + var settings = buildConfig.ApplyStandardSettings( new MSBuildSettings(), configuration ); - + settings = settings.WithTarget("Build"); - + MSBuild(paths.XamarinSolution, settings); }); @@ -109,32 +109,32 @@ Task("_Build_Ably_Unity_Dll") .Does(() => { Information("Merging Unity dependencies into IO.Ably.dll..."); - + var netStandard20BinPath = paths.Src .Combine("IO.Ably.NETStandard20") .Combine("bin/Release/netstandard2.0"); - + if (!DirectoryExists(netStandard20BinPath)) { throw new Exception($"NETStandard2.0 bin directory not found: {netStandard20BinPath}. Please build the project first."); } - + var primaryDll = netStandard20BinPath.CombineWithFilePath("IO.Ably.dll"); - + if (!FileExists(primaryDll)) { throw new Exception($"Primary DLL not found: {primaryDll}. Please build the IO.Ably.NETStandard20 project first."); } - + var newtonsoftDll = paths.Root .Combine("lib/unity/AOT") .CombineWithFilePath("Newtonsoft.Json.dll"); - + if (!FileExists(newtonsoftDll)) { throw new Exception($"Newtonsoft.Json.dll not found at: {newtonsoftDll}"); } - + var dllsToMerge = new[] { netStandard20BinPath.CombineWithFilePath("IO.Ably.DeltaCodec.dll"), @@ -143,23 +143,47 @@ Task("_Build_Ably_Unity_Dll") netStandard20BinPath.CombineWithFilePath("System.Threading.Tasks.Extensions.dll"), newtonsoftDll }; - + var unityOutputPath = paths.Root.Combine("unity/Assets/Ably/Plugins"); var outputDll = unityOutputPath.CombineWithFilePath("IO.Ably.dll"); - + // Delete existing output DLL if it exists if (FileExists(outputDll)) { DeleteFile(outputDll); Information($"Deleted existing DLL: {outputDll}"); } - + // Merge all dependencies into primary DLL in one go ilRepackHelper.MergeDLLs(primaryDll, dllsToMerge, outputDll); - + Information($"✓ Unity DLL created at: {outputDll}"); }); +Task("_Format_Code") + .Description("Format C#, XML and other files") + .Does(() => +{ + Information("Formatting code with dotnet-format..."); + + // Using 'whitespace' mode for fast formatting without building the project + // This applies .editorconfig rules for whitespace, indentation, etc. without semantic analysis + // Much faster than default mode which requires compilation + var exitCode = StartProcess("dotnet", new ProcessSettings + { + Arguments = $"format {paths.MainSolution.FullPath} whitespace --no-restore" + }); + + if (exitCode == 0) + { + Information("✓ Code formatted successfully"); + } + else + { + throw new Exception($"dotnet format failed with exit code {exitCode}"); + } +}); + /////////////////////////////////////////////////////////////////////////////// // PUBLIC TARGETS /////////////////////////////////////////////////////////////////////////////// @@ -190,3 +214,8 @@ Task("Build.Xamarin") Task("Update.AblyUnity") .Description("Update Ably DLLs inside unity project") .IsDependentOn("_Build_Ably_Unity_Dll"); + +// Public task: Format code using dotnet-format +Task("Format.Code") + .Description("Format code using dotnet-format") + .IsDependentOn("_Format_Code"); diff --git a/cake-build/tasks/test.cake b/cake-build/tasks/test.cake index fc423418c..fcb26e654 100644 --- a/cake-build/tasks/test.cake +++ b/cake-build/tasks/test.cake @@ -24,24 +24,53 @@ Task("_NetFramework_Unit_Tests_WithRetry") var testAssemblies = testExecutionHelper.FindTestAssemblies("IO.Ably.Tests.NETFramework"); if (!testAssemblies.Any()) return; - var resultsPath = paths.TestResults.CombineWithFilePath("xunit-netframework-unit.xml"); + var baseReportName = "xunit-netframework-unit"; + var resultsPath = paths.TestResults.CombineWithFilePath($"{baseReportName}.xml"); + var initialFailedTests = new List(); try { - var settings = testExecutionHelper.CreateXUnitSettings("xunit-netframework-unit", isIntegration: false); + var settings = testExecutionHelper.CreateXUnitSettings(baseReportName, isIntegration: false); testExecutionHelper.RunXUnitTests(testAssemblies, settings); } catch { Warning("Some tests failed. Retrying failed tests..."); + initialFailedTests = testRetryHelper.FindFailedXUnitTests(resultsPath); } - testExecutionHelper.RetryFailedXUnitTests( - testAssemblies, - resultsPath, - testRetryHelper, - (test) => testExecutionHelper.CreateXUnitSettings("retry", isIntegration: false, isRetry: true) - ); + if (initialFailedTests.Any()) + { + Information($"Retrying {initialFailedTests.Count} failed test(s)..."); + + testExecutionHelper.RetryFailedXUnitTests( + testAssemblies, + resultsPath, + testRetryHelper, + (test) => testExecutionHelper.CreateXUnitSettings(baseReportName, isIntegration: false, isRetry: true) + ); + + // After retries complete, find all retry result files that were created + var retryPattern = $"{baseReportName}-*.xml"; + var retryResultFiles = GetFiles(paths.TestResults.Combine(retryPattern).FullPath); + + // Analyze retry results + var stillFailedTests = new List(); + foreach (var retryResultPath in retryResultFiles) + { + var retryFailed = testRetryHelper.FindFailedXUnitTests(retryResultPath); + if (retryFailed.Any()) + { + stillFailedTests.AddRange(retryFailed); + } + } + + // Display summary + testRetryHelper.DisplayRetryResultsSummary(".NET Framework Unit", initialFailedTests, stillFailedTests); + + // Validate and throw if non-flaky tests failed + testRetryHelper.ValidateFlakyTests(stillFailedTests); + } }); Task("_NetFramework_Integration_Tests") @@ -66,24 +95,53 @@ Task("_NetFramework_Integration_Tests_WithRetry") var testAssemblies = testExecutionHelper.FindTestAssemblies("IO.Ably.Tests.NETFramework"); if (!testAssemblies.Any()) return; - var resultsPath = paths.TestResults.CombineWithFilePath("xunit-netframework-integration.xml"); + var baseReportName = "xunit-netframework-integration"; + var resultsPath = paths.TestResults.CombineWithFilePath($"{baseReportName}.xml"); + var initialFailedTests = new List(); try { - var settings = testExecutionHelper.CreateXUnitSettings("xunit-netframework-integration", isIntegration: true); + var settings = testExecutionHelper.CreateXUnitSettings(baseReportName, isIntegration: true); testExecutionHelper.RunXUnitTests(testAssemblies, settings); } catch { Warning("Some tests failed. Retrying failed tests..."); + initialFailedTests = testRetryHelper.FindFailedXUnitTests(resultsPath); } - testExecutionHelper.RetryFailedXUnitTests( - testAssemblies, - resultsPath, - testRetryHelper, - (test) => testExecutionHelper.CreateXUnitSettings("retry", isIntegration: true, isRetry: true) - ); + if (initialFailedTests.Any()) + { + Information($"Retrying {initialFailedTests.Count} failed test(s)..."); + + testExecutionHelper.RetryFailedXUnitTests( + testAssemblies, + resultsPath, + testRetryHelper, + (test) => testExecutionHelper.CreateXUnitSettings(baseReportName, isIntegration: true, isRetry: true) + ); + + // After retries complete, find all retry result files that were created + var retryPattern = $"{baseReportName}-*.xml"; + var retryResultFiles = GetFiles(paths.TestResults.Combine(retryPattern).FullPath); + + // Analyze retry results + var stillFailedTests = new List(); + foreach (var retryResultPath in retryResultFiles) + { + var retryFailed = testRetryHelper.FindFailedXUnitTests(retryResultPath); + if (retryFailed.Any()) + { + stillFailedTests.AddRange(retryFailed); + } + } + + // Display summary + testRetryHelper.DisplayRetryResultsSummary(".NET Framework Integration", initialFailedTests, stillFailedTests); + + // Validate and throw if non-flaky tests failed + testRetryHelper.ValidateFlakyTests(stillFailedTests); + } }); /////////////////////////////////////////////////////////////////////////////// @@ -112,11 +170,13 @@ Task("_NetStandard_Unit_Tests_WithRetry") Information("Running .NET Standard unit tests with retry..."); var project = paths.Src.CombineWithFilePath("IO.Ably.Tests.DotNET/IO.Ably.Tests.DotNET.csproj"); - var resultsPath = paths.TestResults.CombineWithFilePath("tests-netstandard-unit.trx"); + var baseResultsName = "tests-netstandard-unit"; + var resultsPath = paths.TestResults.CombineWithFilePath($"{baseResultsName}.trx"); var filter = testExecutionHelper.CreateUnitTestFilter(IsRunningOnUnix()); var settings = testExecutionHelper.CreateDotNetTestSettings(resultsPath, filter, framework, configuration); + var initialFailedTests = new List(); try { testExecutionHelper.RunDotNetTests(project, settings); @@ -124,9 +184,36 @@ Task("_NetStandard_Unit_Tests_WithRetry") catch { Warning("Some tests failed. Retrying failed tests..."); + initialFailedTests = testRetryHelper.FindFailedDotNetTests(resultsPath); } - testExecutionHelper.RetryFailedDotNetTests(project, resultsPath, testRetryHelper, framework, configuration); + if (initialFailedTests.Any()) + { + Information($"Retrying {initialFailedTests.Count} failed test(s)..."); + + testExecutionHelper.RetryFailedDotNetTests(project, resultsPath, testRetryHelper, framework, configuration); + + // After retries complete, find all retry result files that were created + var retryPattern = $"{baseResultsName}-*.trx"; + var retryResultFiles = GetFiles(paths.TestResults.Combine(retryPattern).FullPath); + + // Analyze retry results + var stillFailedTests = new List(); + foreach (var retryResultPath in retryResultFiles) + { + var retryFailed = testRetryHelper.FindFailedDotNetTests(retryResultPath); + if (retryFailed.Any()) + { + stillFailedTests.AddRange(retryFailed); + } + } + + // Display summary + testRetryHelper.DisplayRetryResultsSummary(".NET Standard Unit", initialFailedTests, stillFailedTests); + + // Validate and throw if non-flaky tests failed + testRetryHelper.ValidateFlakyTests(stillFailedTests); + } }); Task("_NetStandard_Integration_Tests") @@ -151,11 +238,13 @@ Task("_NetStandard_Integration_Tests_WithRetry") Information("Running .NET Standard integration tests with retry..."); var project = paths.Src.CombineWithFilePath("IO.Ably.Tests.DotNET/IO.Ably.Tests.DotNET.csproj"); - var resultsPath = paths.TestResults.CombineWithFilePath("tests-netstandard-integration.trx"); + var baseResultsName = "tests-netstandard-integration"; + var resultsPath = paths.TestResults.CombineWithFilePath($"{baseResultsName}.trx"); var filter = testExecutionHelper.CreateIntegrationTestFilter(); var settings = testExecutionHelper.CreateDotNetTestSettings(resultsPath, filter, framework, configuration); + var initialFailedTests = new List(); try { testExecutionHelper.RunDotNetTests(project, settings); @@ -163,9 +252,36 @@ Task("_NetStandard_Integration_Tests_WithRetry") catch { Warning("Some tests failed. Retrying failed tests..."); + initialFailedTests = testRetryHelper.FindFailedDotNetTests(resultsPath); } - testExecutionHelper.RetryFailedDotNetTests(project, resultsPath, testRetryHelper, framework, configuration); + if (initialFailedTests.Any()) + { + Information($"Retrying {initialFailedTests.Count} failed test(s)..."); + + testExecutionHelper.RetryFailedDotNetTests(project, resultsPath, testRetryHelper, framework, configuration); + + // After retries complete, find all retry result files that were created + var retryPattern = $"{baseResultsName}-*.trx"; + var retryResultFiles = GetFiles(paths.TestResults.Combine(retryPattern).FullPath); + + // Analyze retry results + var stillFailedTests = new List(); + foreach (var retryResultPath in retryResultFiles) + { + var retryFailed = testRetryHelper.FindFailedDotNetTests(retryResultPath); + if (retryFailed.Any()) + { + stillFailedTests.AddRange(retryFailed); + } + } + + // Display summary + testRetryHelper.DisplayRetryResultsSummary(".NET Standard Integration", initialFailedTests, stillFailedTests); + + // Validate and throw if non-flaky tests failed + testRetryHelper.ValidateFlakyTests(stillFailedTests); + } }); /////////////////////////////////////////////////////////////////////////////// diff --git a/examples/AndroidSample/AblyService.cs b/examples/AndroidSample/AblyService.cs index 75f3116e8..6ffdc2813 100644 --- a/examples/AndroidSample/AblyService.cs +++ b/examples/AndroidSample/AblyService.cs @@ -18,14 +18,14 @@ public void Init() _ably = new AblyRealtime(new ClientOptions("lNj80Q.iGyVcQ:2QKX7FFASfX-7H9H") { LogHandler = this, - LogLevel = LogLevel.Debug, + LogLevel = LogLevel.Debug, AutoConnect = false, UseBinaryProtocol = false }); _ably.Connection.On(change => { - if(change.Current == ConnectionState.Connected) - foreach(var channel in _ably.Channels) + if (change.Current == ConnectionState.Connected) + foreach (var channel in _ably.Channels) channel.Attach(); _connectionSubject.OnNext(change.Current.ToString()); @@ -48,7 +48,7 @@ public IObservable SubsrcibeToChannel(string channelName) _ably.Channels.Get(channelName).Subscribe(subject.OnNext); return subject; } - + public void LogEvent(LogLevel level, string message) { Android.Util.Log.Debug("ably", $"[{level}] {message}"); @@ -66,6 +66,6 @@ public IDisposable Subscribe(IObserver observer) } } - + } \ No newline at end of file diff --git a/examples/AndroidSample/App.xaml.cs b/examples/AndroidSample/App.xaml.cs index 6b6c3f802..7d98ad0df 100644 --- a/examples/AndroidSample/App.xaml.cs +++ b/examples/AndroidSample/App.xaml.cs @@ -34,7 +34,7 @@ public App(AblyService ably) protected override void OnStart() { - + // Handle when your app starts } diff --git a/format-code.cmd b/format-code.cmd new file mode 100644 index 000000000..3fdbeea2a --- /dev/null +++ b/format-code.cmd @@ -0,0 +1 @@ +dotnet cake cake-build/build.cake -- --target=Format.Code diff --git a/format-code.sh b/format-code.sh new file mode 100644 index 000000000..c2714cc8c --- /dev/null +++ b/format-code.sh @@ -0,0 +1 @@ +format-code.sh diff --git a/src/IO.Ably.Shared/Realtime/ChannelMessageProcessor.cs b/src/IO.Ably.Shared/Realtime/ChannelMessageProcessor.cs index d07185bd6..f782f9a12 100644 --- a/src/IO.Ably.Shared/Realtime/ChannelMessageProcessor.cs +++ b/src/IO.Ably.Shared/Realtime/ChannelMessageProcessor.cs @@ -177,8 +177,8 @@ private bool ValidateIfDeltaItHasCorrectPreviousMessageId(ProtocolMessage protoc var deltaFrom = firstMessage.Extras?.Delta?.From; if (deltaFrom != null && deltaFrom.EqualsTo(channelSuccessfulMessageIds.LastMessageId) == false) { - Logger.Warning($"Delta message decode failure. Previous message id does not equal expected message id. PreviousMessageId: {channelSuccessfulMessageIds.LastMessageId}. ExpectedMessageId: {deltaFrom}"); - return false; + Logger.Warning($"Delta message decode failure. Previous message id does not equal expected message id. PreviousMessageId: {channelSuccessfulMessageIds.LastMessageId}. ExpectedMessageId: {deltaFrom}"); + return false; } return true; diff --git a/src/IO.Ably.Shared/Realtime/Connection.cs b/src/IO.Ably.Shared/Realtime/Connection.cs index 5eae16db9..ddb33a0eb 100644 --- a/src/IO.Ably.Shared/Realtime/Connection.cs +++ b/src/IO.Ably.Shared/Realtime/Connection.cs @@ -305,15 +305,15 @@ internal void NotifyUpdate(ConnectionStateChange stateChange) RealtimeClient.NotifyExternalClients( () => { - Emit(stateChange.Event, stateChange); - try - { - externalHandlers?.Invoke(this, stateChange); - } - catch (Exception ex) - { - Logger.Error("Error notifying Connection state changed handlers", ex); - } + Emit(stateChange.Event, stateChange); + try + { + externalHandlers?.Invoke(this, stateChange); + } + catch (Exception ex) + { + Logger.Error("Error notifying Connection state changed handlers", ex); + } }); } diff --git a/src/IO.Ably.Shared/Result.cs b/src/IO.Ably.Shared/Result.cs index fd31adf98..5254ce6b9 100644 --- a/src/IO.Ably.Shared/Result.cs +++ b/src/IO.Ably.Shared/Result.cs @@ -160,12 +160,12 @@ public static Result Ok() return new Result(true, null); } - /// - /// Factory method to create a successful Result of T with value. - /// - /// Type of value. - /// successful value held in the result. - /// Result. + /// + /// Factory method to create a successful Result of T with value. + /// + /// Type of value. + /// successful value held in the result. + /// Result. public static Result Ok(T value) { return new Result(value, true, null); diff --git a/src/IO.Ably.Shared/Transport/States/Connection/ConnectionDisconnectedState.cs b/src/IO.Ably.Shared/Transport/States/Connection/ConnectionDisconnectedState.cs index a8d4bd624..d511be7b0 100644 --- a/src/IO.Ably.Shared/Transport/States/Connection/ConnectionDisconnectedState.cs +++ b/src/IO.Ably.Shared/Transport/States/Connection/ConnectionDisconnectedState.cs @@ -32,7 +32,7 @@ public ConnectionDisconnectedState(IConnectionContext context, ErrorInfo error, public override RealtimeCommand Connect() { - return SetConnectingStateCommand.Create().TriggeredBy("DisconnectedState.Connect()"); + return SetConnectingStateCommand.Create().TriggeredBy("DisconnectedState.Connect()"); } public override void Close() diff --git a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs index d4e9219f5..f8d566eb4 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs @@ -794,12 +794,12 @@ public async Task TokenAuthUrlWithJsonTokenReturned_ShouldBeAbleToConnect(Protoc var authUrl = "http://echo.ably.io/?type=json&body=" + Uri.EscapeDataString(tokenJson); var client = new AblyRealtime(new ClientOptions - { - AuthUrl = new Uri(authUrl), - Environment = settings.Environment, - UseBinaryProtocol = protocol == Defaults.Protocol, - HttpRequestTimeout = new TimeSpan(0, 0, 20) - }); + { + AuthUrl = new Uri(authUrl), + Environment = settings.Environment, + UseBinaryProtocol = protocol == Defaults.Protocol, + HttpRequestTimeout = new TimeSpan(0, 0, 20) + }); await client.WaitForState(); client.Connection.State.Should().Be(ConnectionState.Connected); @@ -816,12 +816,12 @@ public async Task TokenAuthUrlWithIncorrectJsonTokenReturned_ShouldNotBeAbleToCo var authUrl = "http://echo.ably.io/?type=json&body=" + Uri.EscapeDataString(incorrectJson); var client = new AblyRealtime(new ClientOptions - { - AuthUrl = new Uri(authUrl), - Environment = settings.Environment, - UseBinaryProtocol = protocol == Defaults.Protocol, - HttpRequestTimeout = new TimeSpan(0, 0, 20) - }); + { + AuthUrl = new Uri(authUrl), + Environment = settings.Environment, + UseBinaryProtocol = protocol == Defaults.Protocol, + HttpRequestTimeout = new TimeSpan(0, 0, 20) + }); var tsc = new TaskCompletionAwaiter(); ErrorInfo err = null; diff --git a/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs b/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs index 427173ac9..32207886d 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs @@ -17,7 +17,8 @@ public class AuthorizationTests : MockHttpRestSpecs { internal readonly AblyResponse DummyTokenResponse = new AblyResponse { - Type = ResponseType.Json, TextResponse = "{ \"access_token\": {}}" + Type = ResponseType.Json, + TextResponse = "{ \"access_token\": {}}" }; internal override AblyResponse DefaultResponse => DummyTokenResponse; diff --git a/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs b/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs index 08cce6cfd..eeef7f873 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs @@ -50,20 +50,21 @@ public async Task WithDefaultTokenParamsAndTokenParamsSpecified_ShouldUseOnlyPar var client = GetRestClient( null, options => options.DefaultTokenParams = new TokenParams - { - ClientId = "123", Ttl = TimeSpan.FromHours(2) - }); + { + ClientId = "123", + Ttl = TimeSpan.FromHours(2) + }); var capability = new Capability(); capability.AddResource("a").AllowAll(); var methodParams = new TokenParams - { - Capability = capability, - ClientId = "999", - Ttl = TimeSpan.FromMinutes(1), - Nonce = "123", - Timestamp = Now.AddHours(1) - }; + { + Capability = capability, + ClientId = "999", + Ttl = TimeSpan.FromMinutes(1), + Nonce = "123", + Timestamp = Now.AddHours(1) + }; await client.Auth.RequestTokenAsync(methodParams); @@ -162,11 +163,11 @@ public async Task RequestToken_WithQueryTime_SendsTimeRequestAndUsesReturnedTime return DummyTokenResponse.ToTask(); }; var tokenParams = new TokenParams - { - Capability = new Capability(), - ClientId = "ClientId", - Ttl = TimeSpan.FromMinutes(10) - }; + { + Capability = new Capability(), + ClientId = "ClientId", + Ttl = TimeSpan.FromMinutes(10) + }; // Act await rest.Auth.RequestTokenAsync( @@ -185,11 +186,11 @@ public async Task RequestToken_WithoutQueryTime_SendsTimeRequestAndUsesReturnedT }; var tokenParams = new TokenParams - { - Capability = new Capability(), - ClientId = "ClientId", - Ttl = TimeSpan.FromMinutes(10) - }; + { + Capability = new Capability(), + ClientId = "ClientId", + Ttl = TimeSpan.FromMinutes(10) + }; // Act await rest.Auth.RequestTokenAsync( @@ -207,13 +208,13 @@ public async Task RequestToken_WithAuthCallback_RetrievesTokenFromCallback() var authCallbackCalled = false; var token = new TokenDetails(); var options = new AuthOptions - { - AuthCallback = (x) => - { - authCallbackCalled = true; - return Task.FromResult(token); - } - }; + { + AuthCallback = (x) => + { + authCallbackCalled = true; + return Task.FromResult(token); + } + }; var result = await rest.Auth.RequestTokenAsync(tokenRequest, options); authCallbackCalled.Should().BeTrue(); @@ -349,11 +350,11 @@ public async Task WithDefaultAuthParamsAndHeadersAndSpecifiedOnce_ShouldIgnoreTh }); var options = new AuthOptions - { - AuthUrl = new Uri("http://authUrl"), - AuthHeaders = new Dictionary { { "Test", "Test" } }, - AuthParams = new Dictionary { { "Test", "Test" } }, - }; + { + AuthUrl = new Uri("http://authUrl"), + AuthHeaders = new Dictionary { { "Test", "Test" } }, + AuthParams = new Dictionary { { "Test", "Test" } }, + }; // Act await rest.Auth.RequestTokenAsync(null, options); @@ -507,11 +508,11 @@ private async Task SendRequestTokenWithValidOptions() { var rest = GetRestClient(); var tokenParams = new TokenParams - { - Capability = new Capability(), - ClientId = "ClientId", - Ttl = TimeSpan.FromMinutes(10) - }; + { + Capability = new Capability(), + ClientId = "ClientId", + Ttl = TimeSpan.FromMinutes(10) + }; // Act await rest.Auth.RequestTokenAsync(tokenParams); diff --git a/src/IO.Ably.Tests.Shared/MessageEncodes/CipherEncoderTests.cs b/src/IO.Ably.Tests.Shared/MessageEncodes/CipherEncoderTests.cs index c27746be3..ccd66b3e7 100644 --- a/src/IO.Ably.Tests.Shared/MessageEncodes/CipherEncoderTests.cs +++ b/src/IO.Ably.Tests.Shared/MessageEncodes/CipherEncoderTests.cs @@ -209,15 +209,15 @@ public void WithOtherTypeOfPayload_LeavesDataAndEncodingIntact() [Fact] public void WithCipherEncodingThatDoesNotMatchTheCurrentCipher_LeavesMessageUnencrypted() { - const string initialEncoding = "utf-8/cipher+aes-128-cbc"; - const string encryptedValue = "test"; - IPayload payload = new Message { Data = encryptedValue, Encoding = initialEncoding }; + const string initialEncoding = "utf-8/cipher+aes-128-cbc"; + const string encryptedValue = "test"; + IPayload payload = new Message { Data = encryptedValue, Encoding = initialEncoding }; - var result = _encoder.Decode(payload, _channelOptions.ToDecodingContext()); + var result = _encoder.Decode(payload, _channelOptions.ToDecodingContext()); - result.IsFailure.Should().BeTrue(); - payload.Encoding.Should().Be(initialEncoding); - payload.Data.Should().Be(encryptedValue); + result.IsFailure.Should().BeTrue(); + payload.Encoding.Should().Be(initialEncoding); + payload.Data.Should().Be(encryptedValue); } } diff --git a/src/IO.Ably.Tests.Shared/Push/ActivationStateMachineTests.cs b/src/IO.Ably.Tests.Shared/Push/ActivationStateMachineTests.cs index 46bfde29c..e47cbc775 100644 --- a/src/IO.Ably.Tests.Shared/Push/ActivationStateMachineTests.cs +++ b/src/IO.Ably.Tests.Shared/Push/ActivationStateMachineTests.cs @@ -636,7 +636,7 @@ public async Task GotPushDeviceDetails_ShouldSetStateToWaitingForDeviceRegistrat var response = localDevice.ToString(); return Task.FromResult(new AblyResponse() - { StatusCode = HttpStatusCode.OK, TextResponse = response }); + { StatusCode = HttpStatusCode.OK, TextResponse = response }); }; var (nextState, nextStateFunction) = await state.Transition(new ActivationStateMachine.GotPushDeviceDetails()); diff --git a/src/IO.Ably.Tests.Shared/Push/LocalDeviceTests.cs b/src/IO.Ably.Tests.Shared/Push/LocalDeviceTests.cs index eecb7af3f..246aba63c 100644 --- a/src/IO.Ably.Tests.Shared/Push/LocalDeviceTests.cs +++ b/src/IO.Ably.Tests.Shared/Push/LocalDeviceTests.cs @@ -311,7 +311,7 @@ internal async Task WhenStateMachineIsInitialised_And_LocalDeviceIdIsEmpty_But_S // Arrange const string initialClientId = "123"; var options = new ClientOptions(ValidKey) - { TransportFactory = new FakeTransportFactory(), SkipInternetCheck = true, ClientId = initialClientId }; + { TransportFactory = new FakeTransportFactory(), SkipInternetCheck = true, ClientId = initialClientId }; var mobileDevice = new FakeMobileDevice(); var setupRealtime = new AblyRealtime(options, mobileDevice: mobileDevice); diff --git a/src/IO.Ably.Tests.Shared/Push/PushChannelTests.cs b/src/IO.Ably.Tests.Shared/Push/PushChannelTests.cs index 3bb736410..db6a9bcd7 100644 --- a/src/IO.Ably.Tests.Shared/Push/PushChannelTests.cs +++ b/src/IO.Ably.Tests.Shared/Push/PushChannelTests.cs @@ -146,7 +146,7 @@ async Task RequestHandler(AblyRequest request) taskAwaiter.SetCompleted(); return new AblyResponse() - { TextResponse = JsonConvert.SerializeObject(new PushChannelSubscription()) }; + { TextResponse = JsonConvert.SerializeObject(new PushChannelSubscription()) }; } var client = GetRestClient(RequestHandler, mobileDevice: new FakeMobileDevice()); diff --git a/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandBoxSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandBoxSpecs.cs index e7e303bca..a674653d1 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandBoxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandBoxSpecs.cs @@ -488,7 +488,7 @@ public async Task ResumeRequest_ShouldReceivePendingMessagesOnceConnectionResume [Theory] [ProtocolData] [Trait("spec", "RTN16d")] - public async Task RecoverRequest_ShouldInitializeRecoveryContextAndReceiveSameConnectionIdOnRecoverSuccess(Protocol protocol) + public async Task RecoverRequest_ShouldInitializeRecoveryContextAndReceiveSameConnectionIdOnRecoverSuccess_Flaky(Protocol protocol) { var client1 = await GetRealtimeClient(protocol); await client1.WaitForState(ConnectionState.Connected); diff --git a/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandboxTransportSideEffectsSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandboxTransportSideEffectsSpecs.cs index f370b82ec..90312ff04 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandboxTransportSideEffectsSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/ConnectionSandboxTransportSideEffectsSpecs.cs @@ -18,7 +18,7 @@ public class ConnectionSandboxTransportSideEffectsSpecs : SandboxSpecs [Theory] [ProtocolData] [Trait("spec", "RTN19b")] - public async Task WithChannelInAttachingState_WhenTransportIsDisconnected_ShouldResendAttachMessageOnConnectionResumed(Protocol protocol) + public async Task WithChannelInAttachingState_WhenTransportIsDisconnected_ShouldResendAttachMessageOnConnectionResumed_Flaky(Protocol protocol) { var client = await GetRealtimeClient(protocol); await client.WaitForState(ConnectionState.Connected); @@ -78,7 +78,7 @@ public async Task WithChannelInDetachingState_WhenTransportIsDisconnected_Should [ProtocolData] [Trait("spec", "RTN19")] [Trait("spec", "RTN19a1")] - public async Task OnConnected_ShouldResendAckWithConnectionMessageSerialIfResumeFailed(Protocol protocol) + public async Task OnConnected_ShouldResendAckWithConnectionMessageSerialIfResumeFailed_Flaky(Protocol protocol) { var client = await GetRealtimeClient(protocol); await client.WaitForState(ConnectionState.Connected); diff --git a/src/IO.Ably.Tests.Shared/Realtime/CountDownTimerSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/CountDownTimerSpecs.cs index 7af2b0acf..3e2277759 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/CountDownTimerSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/CountDownTimerSpecs.cs @@ -114,7 +114,7 @@ public CallCounter() Count = 0; } - public int Count { get; private set; } + public int Count { get; private set; } public void Invoke() { diff --git a/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs index c1926a260..cfa652636 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs @@ -503,7 +503,7 @@ await WaitForMultiple(2, partialDone => [ProtocolData] [Trait("spec", "RTP17")] [Trait("spec", "RTP17b")] - public async Task Presence_ShouldHaveInternalMapForCurrentConnectionId(Protocol protocol) + public async Task Presence_ShouldHaveInternalMapForCurrentConnectionId_Flaky(Protocol protocol) { /* * any ENTER, PRESENT, UPDATE or LEAVE event that matches @@ -1710,7 +1710,7 @@ async Task EnterPresenceAndCheckForError() [Theory] [ProtocolData] [Trait("spec", "RTN7d")] - public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_ShouldFailAckQueueMessages_WhenSendFails(Protocol protocol) + public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_ShouldFailAckQueueMessages_WhenSendFails_Flaky(Protocol protocol) { var client = await GetRealtimeClient(protocol, (options, settings) => { diff --git a/src/IO.Ably.Tests.Shared/Realtime/RealtimeWorkflowSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/RealtimeWorkflowSpecs.cs index 4d07db7e8..279eb8de5 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/RealtimeWorkflowSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/RealtimeWorkflowSpecs.cs @@ -22,40 +22,40 @@ public class GeneralSpecs : AblyRealtimeSpecs [Trait("spec", "RTN8b")] public void ConnectedState_UpdatesConnectionInformation() { - // Act - var connectedProtocolMessage = new ProtocolMessage(ProtocolMessage.MessageAction.Connected) - { - ConnectionId = "1", - ConnectionDetails = new ConnectionDetails - { - ClientId = "client1", - ConnectionKey = "validKey" - }, - }; - var client = GetRealtimeClient(options => options.AutoConnect = false); - client.Workflow.ProcessCommand(SetConnectedStateCommand.Create(connectedProtocolMessage, false)); - - // Assert - var connection = client.Connection; - connection.Id.Should().Be("1"); - connection.Key.Should().Be("validKey"); - client.Auth.ClientId.Should().Be("client1"); + // Act + var connectedProtocolMessage = new ProtocolMessage(ProtocolMessage.MessageAction.Connected) + { + ConnectionId = "1", + ConnectionDetails = new ConnectionDetails + { + ClientId = "client1", + ConnectionKey = "validKey" + }, + }; + var client = GetRealtimeClient(options => options.AutoConnect = false); + client.Workflow.ProcessCommand(SetConnectedStateCommand.Create(connectedProtocolMessage, false)); + + // Assert + var connection = client.Connection; + connection.Id.Should().Be("1"); + connection.Key.Should().Be("validKey"); + client.Auth.ClientId.Should().Be("client1"); } [Fact] public async Task SetFailedState_ShouldClearConnectionKeyAndId() { - var client = GetDisconnectedClient(); + var client = GetDisconnectedClient(); - client.State.Connection.Key = "Test"; - client.State.Connection.Id = "Test"; + client.State.Connection.Key = "Test"; + client.State.Connection.Id = "Test"; - client.ExecuteCommand(SetFailedStateCommand.Create(null)); + client.ExecuteCommand(SetFailedStateCommand.Create(null)); - await client.ProcessCommands(); + await client.ProcessCommands(); - client.State.Connection.Key.Should().BeEmpty(); - client.State.Connection.Id.Should().BeEmpty(); + client.State.Connection.Key.Should().BeEmpty(); + client.State.Connection.Id.Should().BeEmpty(); } public GeneralSpecs(ITestOutputHelper output) diff --git a/src/IO.Ably.Tests.Shared/Rest/ChannelSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/Rest/ChannelSandboxSpecs.cs index 7688292e8..113bfa30a 100644 --- a/src/IO.Ably.Tests.Shared/Rest/ChannelSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Rest/ChannelSandboxSpecs.cs @@ -214,7 +214,7 @@ public async Task IdempotentPublishing_MultipleMessagesWithSameId(Protocol proto [Theory] [ProtocolData] [Trait("spec", "RSL1k4")] - public async Task IdempotentPublishing_SimulateErrorAndRetry(Protocol protocol) + public async Task IdempotentPublishing_SimulateErrorAndRetry_Flaky(Protocol protocol) { const int numberOfRetries = 2; var client = await GetRestClient(protocol, opts => @@ -348,7 +348,7 @@ public async Task IdempotentPublishing_SendingAMessageMultipleTimesShouldOnlyPub [Trait("spec", "RSL6a")] // Uses the to publish the examples inside crypto-data-128.json to publish and then retrieve the messages - public async Task CanPublishAMessageAndRetrieveIt128(Protocol protocol) + public async Task CanPublishAMessageAndRetrieveIt128_Flaky(Protocol protocol) { var items = (JArray)_examples["items"]; diff --git a/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs b/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs index 402927e5d..fd952a763 100644 --- a/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs @@ -121,7 +121,7 @@ public async Task Request_SimpleGet(Protocol protocol) [Trait("docUrl", "https://ably.com/docs/api/rest-api#batch-publish")] [Theory] [ProtocolData] - public async Task BatchMessagePublishOnMultipleChannelsUsingHttpPostRequest(Protocol protocol) + public async Task BatchMessagePublishOnMultipleChannelsUsingHttpPostRequest_Flaky(Protocol protocol) { var client = TrackLastRequest(await GetRestClient(protocol)); diff --git a/src/IO.Ably.Tests.Shared/Rest/SandboxSpecExtension.cs b/src/IO.Ably.Tests.Shared/Rest/SandboxSpecExtension.cs index 4ba5374af..10f94d74c 100644 --- a/src/IO.Ably.Tests.Shared/Rest/SandboxSpecExtension.cs +++ b/src/IO.Ably.Tests.Shared/Rest/SandboxSpecExtension.cs @@ -35,7 +35,7 @@ internal static async Task WaitForState(this IRealtimeChannel channel, ChannelSt Result result = await channelAwaiter.WaitAsync(timespan); if (result.IsFailure) { - throw new Exception($"Channel '{channel.Name}' did not reach '{awaitedState}' in {timespan.TotalSeconds} seconds. Current state {channel.State}"); + throw new Exception($"Channel '{channel.Name}' did not reach '{awaitedState}' in {timespan.TotalSeconds} seconds. Current state {channel.State}"); } }