Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AutoFlushActivityProcessorTests] fix flaky flush test #897

Closed
wants to merge 1 commit into from
Closed

[AutoFlushActivityProcessorTests] fix flaky flush test #897

wants to merge 1 commit into from

Conversation

TimothyMothra
Copy link
Contributor

This test occasionally fails, impacting other PRs.

  Failed OpenTelemetry.Extensions.Tests.Trace.AutoFlushActivityProcessorTests.AutoFlushActivityProcessor_FlushAfterLocalServerSideRootSpans_EndMatchingSpan_Flush [149 ms]
  Error Message:
   Moq.MockException : 
Expected invocation on the mock once, but was 2 times: mock => mock.OnForceFlush(5000)

Performed invocations:

   Mock<BaseProcessor<Activity>:1> (mock):

      BaseProcessor<Activity>.SetParentProvider(TracerProviderSdk)
      BaseProcessor<Activity>.SetParentProvider(TracerProviderSdk)
      BaseProcessor<Activity>.OnStart(Activity)
      BaseProcessor<Activity>.OnEnd(Activity)
      BaseProcessor<Activity>.OnForceFlush(5000)
      BaseProcessor<Activity>.OnEnd(Activity)
      BaseProcessor<Activity>.OnForceFlush(5000)

  Stack Trace:
     at Moq.Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage) in C:\projects\moq4\src\Moq\Mock.cs:line 330
   at Moq.Protected.ProtectedMock`1.InternalVerify(String methodName, Type[] genericTypeArguments, Times times, Boolean exactParameterMatch, Object[] args) in C:\projects\moq4\src\Moq\Protected\ProtectedMock.cs:line 234
   at Moq.Protected.ProtectedMock`1.Verify(String methodName, Times times, Object[] args) in C:\projects\moq4\src\Moq\Protected\ProtectedMock.cs:line 206
   at OpenTelemetry.Extensions.Tests.Trace.AutoFlushActivityProcessorTests.AutoFlushActivityProcessor_FlushAfterLocalServerSideRootSpans_EndMatchingSpan_Flush() in D:\a\opentelemetry-dotnet-contrib\opentelemetry-dotnet-contrib\test\OpenTelemetry.Extensions.Tests\Trace\AutoFlushActivityProcessorTests.cs:line 45
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

Changes

  • change Times.Once() to Times.AtLeastOnce()

Please provide a brief description of the changes here.

For significant contributions please make sure you have completed the following items:

  • Appropriate CHANGELOG.md updated for non-trivial changes
  • Design discussion issue #

@TimothyMothra TimothyMothra requested a review from a team January 12, 2023 23:46
@github-actions github-actions bot requested a review from CodeBlanch January 12, 2023 23:46
@codecov
Copy link

codecov bot commented Jan 13, 2023

Codecov Report

Merging #897 (2f75988) into main (6cafab9) will not change coverage.
The diff coverage is n/a.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #897   +/-   ##
=======================================
  Coverage   68.88%   68.88%           
=======================================
  Files         188      188           
  Lines        7081     7081           
=======================================
  Hits         4878     4878           
  Misses       2203     2203           
Impacted Files Coverage Δ
...etry.Exporter.Instana/Implementation/SpanSender.cs 61.53% <0.00%> (-7.70%) ⬇️
...try.Extensions/Trace/AutoFlushActivityProcessor.cs 85.18% <0.00%> (+3.70%) ⬆️

@@ -42,7 +42,7 @@ public void AutoFlushActivityProcessor_FlushAfterLocalServerSideRootSpans_EndMat
using var activity = source.StartActivity("name", ActivityKind.Server);
activity.Stop();

mockExporting.Protected().Verify("OnForceFlush", Times.Once(), 5_000);
mockExporting.Protected().Verify("OnForceFlush", Times.AtLeastOnce(), 5_000);
Copy link
Member

Choose a reason for hiding this comment

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

This test again! Such a pain 🤣 I spent a bunch of time on it a while back. Updating moq seemed to help. Is it failing only on some older runtimes now?

Copy link
Contributor Author

@TimothyMothra TimothyMothra Jan 13, 2023

Choose a reason for hiding this comment

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

This test failed for me on net7 today. I recognized this test, I've seen it fail before, but I haven't kept a record of what platforms.

My intent with this PR is to make the test more resilient.
Actually, I have on ongoing conflict with Activity-based unit tests and I've been working to make them more resilient when I see them fail.

Copy link
Member

Choose a reason for hiding this comment

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

The branch where it failed up-to-date with the version bump from my PR? I think this change is fine but it does change the test where it might not catch an actual regression, no? Any desire on your part to rewrite it so that it doesn't use moq? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we're going to continue to have problems unit testing Activities because the ActivityStopped can get triggered twice.
See: dotnet/runtime#76757 and Azure/azure-sdk-for-net#31567

Regarding a rewrite...
I see that it's asserting the mock and not actually asserting the AutoFlush Processor.
I could change this to verify that OnForceFlush is called while exporting this specific Activity (by asserting the Activity.Name).
But this won't avoid that the Activity can be exported twice.

Copy link
Member

Choose a reason for hiding this comment

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

I think for the sake of this test we only care to track invocations to OnForceFlush so it should be fine! Try this:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using OpenTelemetry.Trace;
using Xunit;

namespace OpenTelemetry.Extensions.Tests.Trace;

public class AutoFlushActivityProcessorTests
{
    [Fact]
    public void AutoFlushActivityProcessor_FlushAfterLocalServerSideRootSpans_EndMatchingSpan_Flush()
    {
        var processor = new ForceFlushTrackingProcessor();

        var sourceName = GetTestMethodName();

        using var provider = Sdk.CreateTracerProviderBuilder()
            .AddProcessor(processor)
            .AddAutoFlushActivityProcessor(a => a.Parent == null && (a.Kind == ActivityKind.Server || a.Kind == ActivityKind.Consumer), 5000)
            .AddSource(sourceName)
            .Build();

        using var source = new ActivitySource(sourceName);
        using var activity = source.StartActivity("name", ActivityKind.Server);
        activity.Stop();

        Assert.Equal(1, processor.ForceFlushInvocations);
    }

    [Fact]
    public void AutoFlushActivityProcessor_FlushAfterLocalServerSideRootSpans_EndNonMatchingSpan_DoesNothing()
    {
        var processor = new ForceFlushTrackingProcessor();

        var sourceName = GetTestMethodName();

        using var provider = Sdk.CreateTracerProviderBuilder()
            .AddProcessor(processor)
            .AddAutoFlushActivityProcessor(a => a.Parent == null && (a.Kind == ActivityKind.Server || a.Kind == ActivityKind.Consumer))
            .AddSource(sourceName)
            .Build();

        using var source = new ActivitySource(sourceName);
        using var activity = source.StartActivity("name", ActivityKind.Client);
        activity.Stop();

        Assert.Equal(0, processor.ForceFlushInvocations);
    }

    [Fact]
    public void AutoFlushActivityProcessor_PredicateThrows_DoesNothing()
    {
        var processor = new ForceFlushTrackingProcessor();

        var sourceName = GetTestMethodName();

        using var provider = Sdk.CreateTracerProviderBuilder()
            .AddProcessor(processor)
            .AddAutoFlushActivityProcessor(_ => throw new Exception("Predicate throws an exception."))
            .AddSource(sourceName)
            .Build();

        using var source = new ActivitySource(sourceName);
        using var activity = source.StartActivity("name", ActivityKind.Server);
        activity.Stop();

        Assert.Equal(0, processor.ForceFlushInvocations);
    }

    private static string GetTestMethodName([CallerMemberName] string callingMethodName = "")
    {
        return callingMethodName;
    }

    private sealed class ForceFlushTrackingProcessor : BaseProcessor<Activity>
    {
        private int forceFlushInvocations;

        public int ForceFlushInvocations => this.forceFlushInvocations;

        protected override bool OnForceFlush(int timeoutMilliseconds)
        {
            Interlocked.Increment(ref this.forceFlushInvocations);

            return true;
        }
    }
}

@Kielek Kielek added the comp:extensions Things related to OpenTelemetry.Extensions label Jan 19, 2023
@github-actions
Copy link
Contributor

This PR was marked stale due to lack of activity. It will be closed in 7 days.

@github-actions github-actions bot added the Stale label Jan 27, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2023

Closed as inactive. Feel free to reopen if this PR is still being worked on.

@github-actions github-actions bot closed this Feb 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:extensions Things related to OpenTelemetry.Extensions Stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants