Skip to content

Refactor observable tester #213

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

Merged
merged 18 commits into from
Apr 16, 2020
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
3 changes: 2 additions & 1 deletion .github/workflows/branches-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ on:
- 'release/**'
- 'releases/**'
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
MSBUILDSINGLELOADCONTEXT: 1
jobs:
generateVersionInfo:
name: GenerateVersionInfo
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/main-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
- V*
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
MSBUILDSINGLELOADCONTEXT: 1

jobs:
generateVersionInfo:
name: GenerateVersionInfo
Expand Down
2 changes: 1 addition & 1 deletion dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
]
},
"gitversion.tool": {
"version": "5.1.3",
"version": "5.2.4",
"commands": [
"dotnet-gitversion"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<PropertyGroup>
<Description>Abstractions for the Websocket transport used in GraphQL.Client</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<PropertyGroup>
<Description>A serializer implementation for GraphQL.Client using Newtonsoft.Json as underlying JSON library</Description>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../src.props" />

<Import Project="../src.props" />

<PropertyGroup>
<Description>A serializer implementation for GraphQL.Client using System.Text.Json as underlying JSON library</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
Expand Down
14 changes: 1 addition & 13 deletions src/GraphQL.Client/GraphQL.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,7 @@
<DefineConstants>NETFRAMEWORK</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Remove="GraphQLSerializationExtensions.cs" />
</ItemGroup>

<ItemGroup>
<None Include="GraphQLSerializationExtensions.cs" />
</ItemGroup>


<ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

Expand All @@ -37,7 +28,4 @@
<ProjectReference Include="..\GraphQL.Client.Abstractions\GraphQL.Client.Abstractions.csproj" />
</ItemGroup>




</Project>
6 changes: 2 additions & 4 deletions src/GraphQL.Client/GraphQLHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,9 @@ private async Task<GraphQLHttpResponse<TResponse>> SendHttpPostRequestAsync<TRes
var preprocessedRequest = await Options.PreprocessRequest(request, this);
using var httpRequestMessage = GenerateHttpRequestMessage(preprocessedRequest);
using var httpResponseMessage = await HttpClient.SendAsync(httpRequestMessage, cancellationToken);
if (!httpResponseMessage.IsSuccessStatusCode)
{
throw new GraphQLHttpException(httpResponseMessage);
}

httpResponseMessage.EnsureSuccessStatusCode();

var bodyStream = await httpResponseMessage.Content.ReadAsStreamAsync();
var response = await JsonSerializer.DeserializeFromUtf8StreamAsync<TResponse>(bodyStream, cancellationToken);
return response.ToGraphQLHttpResponse(httpResponseMessage.Headers, httpResponseMessage.StatusCode);
Expand Down
44 changes: 0 additions & 44 deletions src/GraphQL.Client/GraphQLSerializationExtensions.cs

This file was deleted.

1 change: 1 addition & 0 deletions src/GraphQL.Primitives/GraphQL.Primitives.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
<RootNamespace>GraphQL</RootNamespace>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>

</Project>
13 changes: 7 additions & 6 deletions src/src.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
<LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GitVersionTask" Version="5.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<!--TODO: remove condition when https://github.com/GitTools/GitVersion/issues/2063 is fixed-->
<ItemGroup Condition=" '$(DEBUG)' != ''">
<PackageReference Update="GitVersionTask" Version="5.2.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<PropertyGroup Condition=" '$(GitVersion_SemVer)' != ''">
<GetVersion>false</GetVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.0.1" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Microsoft.Reactive.Testing;

namespace GraphQL.Client.Tests.Common.FluentAssertions.Reactive
{
/// <summary>
/// Observer for testing <see cref="Observable"/>s using the FluentAssertions framework
/// </summary>
/// <typeparam name="TPayload"></typeparam>
public class FluentTestObserver<TPayload> : IObserver<TPayload>, IDisposable
{
private readonly IDisposable _subscription;
private readonly IScheduler _observeScheduler;
private readonly RollingReplaySubject<Recorded<Notification<TPayload>>> _rollingReplaySubject = new RollingReplaySubject<Recorded<Notification<TPayload>>>();

/// <summary>
/// The observable which is observed by this instance
/// </summary>
public IObservable<TPayload> Subject { get; }

/// <summary>
/// The stream of recorded <see cref="Notification{T}"/>s
/// </summary>
public IObservable<Recorded<Notification<TPayload>>> RecordedNotificationStream => _rollingReplaySubject.AsObservable();

/// <summary>
/// The recorded <see cref="Notification{T}"/>s
/// </summary>
public IEnumerable<Recorded<Notification<TPayload>>> RecordedNotifications =>
_rollingReplaySubject.GetSnapshot();

/// <summary>
/// The recorded messages
/// </summary>
public IEnumerable<TPayload> RecordedMessages =>
RecordedNotifications.GetMessages();

/// <summary>
/// The exception
/// </summary>
public Exception Error =>
RecordedNotifications
.Where(r => r.Value.Kind == NotificationKind.OnError)
.Select(r => r.Value.Exception)
.FirstOrDefault();

/// <summary>
/// The recorded messages
/// </summary>
public bool Completed =>
RecordedNotifications
.Any(r => r.Value.Kind == NotificationKind.OnCompleted);

/// <summary>
/// Creates a new <see cref="FluentTestObserver{TPayload}"/> which subscribes to the supplied <see cref="IObservable{T}"/>
/// </summary>
/// <param name="subject">the <see cref="IObservable{T}"/> under test</param>
public FluentTestObserver(IObservable<TPayload> subject)
{
Subject = subject;
_observeScheduler = new EventLoopScheduler();
_subscription = subject.ObserveOn(_observeScheduler).Subscribe(this);
}

/// <summary>
/// Creates a new <see cref="FluentTestObserver{TPayload}"/> which subscribes to the supplied <see cref="IObservable{T}"/>
/// </summary>
/// <param name="subject">the <see cref="IObservable{T}"/> under test</param>
public FluentTestObserver(IObservable<TPayload> subject, IScheduler scheduler)
{
Subject = subject;
_observeScheduler = scheduler;
_subscription = subject.ObserveOn(scheduler).Subscribe(this);
}

/// <summary>
/// Creates a new <see cref="FluentTestObserver{TPayload}"/> which subscribes to the supplied <see cref="IObservable{T}"/>
/// </summary>
/// <param name="subject">the <see cref="IObservable{T}"/> under test</param>
public FluentTestObserver(IObservable<TPayload> subject, TestScheduler testScheduler)
{
Subject = subject;
_observeScheduler = testScheduler;
_subscription = subject.ObserveOn(Scheduler.CurrentThread).Subscribe(this);
}

/// <summary>
/// Clears the recorded notifications and messages as well as the recorded notifications stream buffer
/// </summary>
public void Clear() => _rollingReplaySubject.Clear();

/// <inheritdoc />
public void OnNext(TPayload value) =>
_rollingReplaySubject.OnNext(new Recorded<Notification<TPayload>>(_observeScheduler.Now.UtcTicks, Notification.CreateOnNext(value)));

/// <inheritdoc />
public void OnError(Exception exception) =>
_rollingReplaySubject.OnNext(new Recorded<Notification<TPayload>>(_observeScheduler.Now.UtcTicks, Notification.CreateOnError<TPayload>(exception)));

/// <inheritdoc />
public void OnCompleted() =>
_rollingReplaySubject.OnNext(new Recorded<Notification<TPayload>>(_observeScheduler.Now.UtcTicks, Notification.CreateOnCompleted<TPayload>()));

/// <inheritdoc />
public void Dispose()
{
_subscription?.Dispose();
_rollingReplaySubject?.Dispose();
}

/// <summary>
/// Returns an <see cref="ReactiveAssertions{TPayload}"/> object that can be used to assert the observed <see cref="IObservable{T}"/>
/// </summary>
/// <returns></returns>
public ReactiveAssertions<TPayload> Should() => new ReactiveAssertions<TPayload>(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace GraphQL.Client.Tests.Common.FluentAssertions.Reactive
{
internal static class NoSynchronizationContextScope
{
public static T ExecuteInDefaultSynchronizationContext<T>(this Task<T> task)
{
using (NoSynchronizationContextScope.Enter())
{
task.Wait();
return task.Result;
}
}

public static DisposingAction Enter()
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
return new DisposingAction(() => SynchronizationContext.SetSynchronizationContext(context));
}

internal class DisposingAction : IDisposable
{
private readonly Action action;

public DisposingAction(Action action)
{
this.action = action;
}

public void Dispose()
{
action();
}
}
}
}
Loading