Specflow: Deadlocks when invoking async method (on SignalR connection)

Created on 4 Jun 2019  Â·  4Comments  Â·  Source: SpecFlowOSS/SpecFlow

SpecFlow Version:

  • [x] 3.0
  • [ ] 2.4
  • [ ] 2.3
  • [ ] 2.2
  • [ ] 2.1
  • [ ] 2.0
  • [ ] 1.9

Used Test Runner

  • [ ] SpecFlow+Runner
  • [ ] MSTest
  • [ ] NUnit
  • [x] Xunit


Version number:

Project Format of the SpecFlow project

  • [ ] Classic project format using packages.config
  • [x] Classic project format using <PackageReference> tags
  • [ ] Sdk-style project format

.feature.cs files are generated using

  • [x] SpecFlow.Tools.MsBuild.Generation NuGet package
  • [ ] SpecFlowSingleFileGenerator custom tool

Visual Studio Version

  • [x] VS 2019
  • [ ] VS 2017
  • [ ] VS 2015

Enable SpecFlowSingleFileGenerator Custom Tool option in Visual Studio extension settings

  • [x] Enabled
  • [ ] Disabled

Are the latest Visual Studio updates installed?

  • [x] Yes
  • [ ] No

.NET Framework:

  • [ ] >= .NET 4.5
  • [ ] before .NET 4.5
  • [ ] .NET Core 2.0
  • [ ] .NET Core 2.1
  • [x] .NET Core 2.2
  • [ ] .NET Core 3.0

Test Execution Method:

  • [x] Visual Studio Test Explorer
  • [ ] TFS/VSTS/Azure DevOps – Task – PLEASE SPECIFY THE NAME OF THE TASK
  • [ ] Command line – PLEASE SPECIFY THE FULL COMMAND LINE

<SpecFlow> Section in app.config or content of specflow.json

    <SpecFlowFeatureFiles Update="Bugged.feature">
      <Generator>SpecFlowSingleFileGenerator</Generator>
      <LastGenOutput>Bugged.feature.cs</LastGenOutput>
    </SpecFlowFeatureFiles>

Repro Project


https://github.com/NorekZ/SpecFlowSignalRBug

Issue Description


When calling InvokeAsync() on established SignalR connection in the same method (=step), everything works ok. But when invoking in another method (=step), process hangs in SpecFlow code on .WaitOne()
image

The reason I think it is related to SpecFlow is that plain xUnit test does work (see https://github.com/NorekZ/SpecFlowSignalRBug/blob/master/SpecFlowSignalRBug/WorkingXunitTest.cs ).

Weather or not it is related to SignalR itself, I don't know.

Thank you for any help or at least workaround.

Steps to Reproduce


Clone https://github.com/NorekZ/SpecFlowSignalRBug and run tests. There are 3 of them:

  • working with SpecFlow
  • not working with SpecFlow
  • working with just xUnit
Bug Runtime up-for-grabs prevents-update-to-latest-version hard high

Most helpful comment

SignalR client asynchronous model does not play well with SynchronizationContext . There are two issues I've faced ;

  1. SignalR client message subscription( HubConnection.On) not working with SpecFlow

  2. Stopping HubConnection synchronously causes deadlock. Let's say you have a driver (WebSocketDriver) that implements IDisposableinterface and you need to stop and dispose HubConnection, then you need to run HubConnection.StopAsync()and HubConnection.DisposeAsync()synchronously , since HubConnection doesn't have sync equivalent of those functions. And this ends up with deadlock.

I was runnning SpecFlow with xunit runner. Xunit itself sets MaxConcurrencySyncContext unless maxParallelThreads in xunit.runner.json is set to -1 explicitly. However , this doesn't fix the issue since Specflow also sets its own SynchronizationContext . Workaround i come up with was explicitly setting null to current SynchronizationContext before running tests :

SynchronizationContext.SetSynchronizationContext(null)

This worked for me. However it is a bit dirty workaround.

All 4 comments

This issue is preventing we upgrade from 2.4. It should be a common issue for everyone who relies heavily on async await on their code base.

My team is also running into this issue. We're on .NET Core 3 and attempting to write behavior tests using the .NET Core SignalR client.

SignalR client asynchronous model does not play well with SynchronizationContext . There are two issues I've faced ;

  1. SignalR client message subscription( HubConnection.On) not working with SpecFlow

  2. Stopping HubConnection synchronously causes deadlock. Let's say you have a driver (WebSocketDriver) that implements IDisposableinterface and you need to stop and dispose HubConnection, then you need to run HubConnection.StopAsync()and HubConnection.DisposeAsync()synchronously , since HubConnection doesn't have sync equivalent of those functions. And this ends up with deadlock.

I was runnning SpecFlow with xunit runner. Xunit itself sets MaxConcurrencySyncContext unless maxParallelThreads in xunit.runner.json is set to -1 explicitly. However , this doesn't fix the issue since Specflow also sets its own SynchronizationContext . Workaround i come up with was explicitly setting null to current SynchronizationContext before running tests :

SynchronizationContext.SetSynchronizationContext(null)

This worked for me. However it is a bit dirty workaround.

Was this page helpful?
0 / 5 - 0 ratings