for Control the flow of data at a certain rate(in C#.Net) i'm using SelectAysnc to implement Actor.Ask() but i'm getting error - c#

can someone tell me where i'm going wrong.
KafkaConsumer.PlainSource(
consumerSettings, subscription)
.SelectAsync(10, result => {
_UIC559PrcessorActorRef.Ask<TResponse>(result.Message.Value, TimeSpan.FromSeconds(3));
})
.RunForeach(result => // will now be of type TResponse
{
// do something with TResponse
_UIC559PrcessorActorRef.Tell(result.Message.Value);
}, materializer);

Related

Unit testing ViewModel property bound to ReactiveCommand IsExecuting

I'm new to ReactiveUI and am following the example set out here, and unit testing as I go.
As expected, the sample code works perfectly, but my unit test which asserts that the SpinnerVisibility property changes as expected when the IsExecuting property of my ReactiveCommand changes, does not.
As per the sample, I have properties on my view model for a spinner visibility and a command to execute a search:
public Visibility SpinnerVisibility => _spinnerVisibility.Value;
public ReactiveCommand<string, List<FlickrPhoto>> ExecuteSearch { get; protected set; }
And in the view model constructor I set up the ExecuteSearch command and SpinnerVisibility is set to change when the command is executing:
public AppViewModel(IGetPhotos photosProvider)
{
ExecuteSearch = ReactiveCommand.CreateFromTask<string, List<FlickrPhoto>>(photosProvider.FromFlickr);
this.WhenAnyValue(search => search.SearchTerm)
.Throttle(TimeSpan.FromMilliseconds(800), RxApp.MainThreadScheduler)
.Select(searchTerm => searchTerm?.Trim())
.DistinctUntilChanged()
.Where(searchTerm => !string.IsNullOrWhiteSpace(searchTerm))
.InvokeCommand(ExecuteSearch);
_spinnerVisibility = ExecuteSearch.IsExecuting
.Select(state => state ? Visibility.Visible : Visibility.Collapsed)
.ToProperty(this, model => model.SpinnerVisibility, Visibility.Hidden);
}
My initial attempt was to directly invoke the command:
[Test]
public void SpinnerVisibility_ShouldChangeWhenCommandIsExecuting()
{
var photosProvider = A.Fake<IGetPhotos>();
var fixture = new AppViewModel(photosProvider);
fixture.ExecuteSearch.Execute().Subscribe(_ =>
{
fixture.SpinnerVisibility.Should().Be(Visibility.Visible);
});
fixture.SpinnerVisibility.Should().Be(Visibility.Collapsed);
}
This did result in the state => state ? Visibility.Visible : Visibility.Collapsed lambda being executed, but the subsequent assertion fails as for some reason SpinnerVisibility is still Collapsed.
My next attempt was to indirectly invoke the command by emulating a search using TestScheduler:
[Test]
public void SpinnerVisibility_ShouldChangeWhenCommandIsExecuting()
{
new TestScheduler().With(scheduler =>
{
var photosProvider = A.Fake<IGetPhotos>();
var fixture = new AppViewModel(photosProvider);
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(
() => new List<FlickrPhoto> { new FlickrPhoto { Description = "a thing", Title = "Thing", Url = "https://thing.com" } });
fixture.SearchTerm = "foo";
scheduler.AdvanceByMs(801); // search is throttled by 800ms
fixture.SpinnerVisibility.Should().Be(Visibility.Visible);
});
}
As before, the lambda executes, state is true but then instantly re-executes, with state back to false, presumably because, being mocked, photosProvider.FromFlickr would return instantly (unlike retrieving images from the API normally), which would then mean the command was no longer executing.
I then came across Paul Bett's response to a similar question, and added an Observable.Interval to my mock:
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(
() =>
{
Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler);
return new List<FlickrPhoto> {new FlickrPhoto {Description = "a thing", Title = "Thing", Url = "https://thing.com"}};
});
and the corresponding test changes:
scheduler.AdvanceByMs(501);
fixture.SpinnerVisibility.Should().Be(Visibility.Collapsed);
This had no effect.
Finally, I awaited the Interval:
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(async
() =>
{
await Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler);
return new List<FlickrPhoto> {new FlickrPhoto {Description = "a thing", Title = "Thing", Url = "https://thing.com"}};
});
This allowed the fixture.SpinnerVisibility.Should().Be(Visibility.Visible) assertion to pass, but now regardless how far I advance the scheduler, the mocked method never seems to return and so the subsequent assertion fails.
Is this approach using TestScheduler correct/advised? If so, what am I missing? If not, how should this type of behaviour be tested?
First off, you are trying to test two independent things in one test. Separating the logic into more focused tests will cause you fewer headaches in the future when refactoring. Consider the following instead:
SearchTerm_InvokesExecuteSearchAfterThrottle
SpinnerVisibility_VisibleWhenExecuteSearchIsExecuting
Now you have unit tests that are verifying each piece of functionality individually. If one fails, you'll know exactly which expectation is broken because there is only one. Now, onto the actual tests...
Based on your code, I assume you're using NUnit, FakeItEasy, and Microsoft.Reactive.Testing. The recommended strategy for testing observables is to use the TestScheduler and assert the final outcome of the observable.
Here is how I would implement them:
using FakeItEasy;
using Microsoft.Reactive.Testing;
using NUnit.Framework;
using ReactiveUI;
using ReactiveUI.Testing;
using System;
using System.Reactive.Concurrency;
...
public sealed class AppViewModelTest : ReactiveTest
{
[Test]
public void SearchTerm_InvokesExecuteSearchAfterThrottle()
{
new TestScheduler().With(scheduler =>
{
var sut = new AppViewModel(A.Dummy<IGetPhotos>());
scheduler.Schedule(() => sut.SearchTerm = "A");
scheduler.Schedule(TimeSpan.FromTicks(200), () => sut.SearchTerm += "B");
scheduler.Schedule(TimeSpan.FromTicks(300), () => sut.SearchTerm += "C");
scheduler.Schedule(TimeSpan.FromTicks(400), () => sut.SearchTerm += "D");
var results = scheduler.Start(
() => sut.ExecuteSearch.IsExecuting,
0, 100, TimeSpan.FromMilliseconds(800).Ticks + 402);
results.Messages.AssertEqual(
OnNext(100, false),
OnNext(TimeSpan.FromMilliseconds(800).Ticks + 401, true)
);
});
}
[Test]
public void SpinnerVisibility_VisibleWhenExecuteSearchIsExecuting()
{
new TestScheduler().With(scheduler =>
{
var sut = new AppViewModel(A.Dummy<IGetPhotos>());
scheduler.Schedule(TimeSpan.FromTicks(300),
() => sut.ExecuteSearch.Execute().Subscribe());
var results = scheduler.Start(
() => sut.WhenAnyValue(x => x.SpinnerVisibility));
results.Messages.AssertEqual(
OnNext(200, Visibility.Collapsed),
OnNext(301, Visibility.Visible),
OnNext(303, Visibility.Collapsed));
});
}
}
Notice there is no need to even fake/mock IGetPhotos because your tests aren't verifying anything based on the duration of the command. They just care about when it executes.
Some things can be difficult to wrap your head around at first, such as when a tick actually occurs, but it's very powerful once you get the hang of it. Some debate could be had about the usage of ReactiveUI in the tests (e.g. IsExecuting, WhenAnyValue), but I think it keeps things succinct. Plus, you're using ReactiveUI in your application anyway so if those things broke your test I'd consider that a good thing.

How to chain constructors in Structuremap?

Is there a way to chain the constructors in Structuremap? I would want a more succinct code - basically trying to get rid of the new keyword in codebase.
Currently what I have:
container.Configure(c =>
{
c.For<IDataContext>()
.Singleton()
.Use(new CarDataContextWrapper(new CarDataContext(Settings.Default.ConnectionString)
{
CommandTimeout = 60
}));
});
To inject in the constructor parameters, I would want to using .Ctor declaration. But how would I do it for the second class that I want to initialize?
container.Configure(c =>
{
c.For<IDataContext>()
.Use<CarDataContextWrapper>()
.Ctor<CarDataContext>().Is(x=>); // HOW TO SET THIS?
});
container.Configure(c =>
{
c.For<IDataContext>()
.Use<CarDataContextWrapper>("getting context", ctx=>
{
return ctx.GetInstance<CarDataContextWrapper>();
});
// Also need to tell SM how to build CarDataContextWrapper
});

Generic policy type return

I want to retry when the NEST error is in a range of HttpCodeResponse and I have the follow generic policy:
public Policy<D> CreatePolicy<T, D>(
PolicyType policyType)
where T : Exception where D : IApiCallDetails
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.Handle<T>()
.OrResult<D>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains(r.HttpStatusCode.Value))
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (exception, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {exception.Exception.Message}.");
throw exception.Exception;
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
But when I try to apply to an elasticClient call, I receive the error:
can not implicity convert System.Threading.Tasks.Task<Nest.ISearchResponse<Model.Product>> to System.Threading.Tasks.Task<Elasticsearch.Net.IApiCallDetails>
Policy<IApiCallDetails> policyWaintAndRetry = this.policyFactory.CreatePolicy<ElasticsearchClientException, IApiCallDetails>(PolicyType.WaitAndRetryAsync);
var searchResponse = await policyWaintAndRetry.ExecuteAsync
action: () =>
this.client.SearchAsync<Product>(s => s
.From((request.PageNumber - 1) * request.PageSize)
.Size(request.PageSize)
.Index(GetIndexName(request.TenantId))
.Query(q => tq), CancellationToken.None),
contextData: new Polly.Context("SearchProductSearchAsync"))
.ConfigureAwait(false);
For NEST 5.x, I think D should have a generic parameter constraint of IResponse; every response within NEST implements IResponse and the ApiCall property inherited from IBodyWithApiCallDetails contains the IApiCallDetails with the HTTP status code.
It is not necessary to define two separate policies for handling exceptions and results. The two separate policies in this answer could be combined like this:
public Policy<TResult> CreatePolicyForResultAndException<TResult, TException>(PolicyType policyType)
where TResult : HttpResponseMessage
where TException: Exception
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.HandleResult<TResult>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains((int)r.StatusCode))
.Or<TException>()
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (outcome, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {outcome.Result ?? outcome.Exception.Message}.");
if (outcome.Exception != null) throw outcome.Exception; // [*] if desired - see note after code sample
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
[*] This line in the code sample above preserves the throwing of the exception within the onRetry from the original answer. However, it would be unusual to rethrow the exception within the onRetry, as the policy will not handle the exception rethrown there; throwing within onRetry will cause the policy to exit without making further tries.
Actually my problem was that I was trying to create a single policy for handling exception and result, while in fact I should create one for each and then merge them with a policyWrap
1st policy (for result):
public Policy<T> CreatePolicyForResult<T>(
PolicyType policyType)
where T : HttpResponseMessage
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.HandleResult<T>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains((int)r.StatusCode))
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries))
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
2nd policy (for exception):
public Policy CreatePolicyForException<T>(
PolicyType policyType)
where T : Exception
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
return Policy.Handle<T>()
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (exception, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {exception.Message}.");
throw exception;
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
Usage:
var policyWaintAndRetryForExeption = this.policyFactory.CreatePolicyForException<ElasticsearchClientException>(PolicyType.WaitAndRetryAsync);
var policyWaintAndRetryForResult = this.policyFactory.CreatePolicyForResult<HttpResponseMessage>(PolicyType.WaitAndRetryAsync);
PolicyWrap<HttpResponseMessage> policyWrap = policyWaintAndRetryForExeption.WrapAsync(policyWaintAndRetryForResult);

Composing a Polly Policy with user feedback

There are several policy's that need to be the same throughout my code. For example:
var myIOProblems = Policy
.Handle<IOException>()
.WaitAndRetryForever(i => TimeSpan.FromSeconds(2));
Then I'll have some code that will do the work:
myIOProblems
.Execute(() => otherPath.CopyTo(otherPathPart.FullName));
This works great, and I can litter the latter statements all over my code, change the behavior in one central place, and it all seems to work.
But in some places I need to provide the user/framework some feedback that problems are occurring. I can write a new policy:
Policy
.Handle<IOException>()
.WaitAndRetryForever(i => TimeSpan.FromSeconds(2), (e, t, c) =>
{
count++;
statusUpdate.PCall($"Copying {otherPath.Name}: {other.Name} -> {Name} (retry ({count}): {e.Message})");
})
.Execute(() => otherPath.CopyTo(otherPathPart.FullName));
But now I've lost the ability to re-use common code. What I'd really like to be able to write is something like the following:
myIOProblems
.OnRetry(e => statusUpdate.PCall($"Error ({e.Message}), retrying"))
.Execute(() => otherPath.CopyTo(otherPathPart.FullName));
Or something similar to that. I may be overlooking something in the library, in which case I apologize!
You can wrap your policy in a factory class and the getter function will optionally receive the onRetry callback:
public class PolicyFactory
{
public static Policy GetMyPolicy(Action<Exception, TimeSpan, Context> onRetry = null)
{
return Policy
.Handle<IOException>()
.WaitAndRetryForever(i => TimeSpan.FromSeconds(2), onRetry);
}
}

How to mock an interface returned as property from another mock?

I have the following interfaces:
interface IManufacturing
{
IJobApi JobApi {get;}
}
interface IJobApi
{
IList<JobSpec> GetSpecs (string wo, string name);
}
I have a class which uses IManufacturing and calls GetSpecs() like so:
var specs = _manufacturing.JobApi.GetSpecs (wo, name);
I setup my mocks like:
var jobApi = A.Fake<IJobApi> ();
A.CallTo (() => jobApi.GetSpecs (It.IsAny<string> (), It.IsAny<string> ()))
.Invokes (() => System.Diagnostics.Trace.WriteLine("GetSpecs called!"))
.Returns (new List<JobSpec>
{
new JobSpec("blablabla", "0.125", "something")
});
var manufacturing = A.Fake<IManufacturing> ();
A.CallTo (() => manufacturing.JobAPI)
.Invokes (() => System.Diagnostics.Trace.WriteLine ("JobAPI called!"))
.Returns (jobApi);
Upon running the test, I only see the "JobAPI called" string in the output.
So, the GetSpecs() does not get mocked and indeed the caller throws because it expected a list of specs whereas it received an empty string...
What could be the culprit here?
Thanks.
Dammit!
You're gonna laugh, I have!
Turned out that the following line
A.CallTo (() => jobApi.GetSpecs (It.IsAny<string> (), It.IsAny<string> ()))
was not correct for FakeItEasy. It should be written as
A.CallTo (() => jobApi.GetSpecs (A<string>.Ignored, A<string>.Ignored))
So, you may wonder why it did compile and run... Yeah me too. ;)
It.IsAny is for Moq (!)
I had a Using Moq lingering at the top of the class. (I'm in the process of switching to fakeiteasy from moq).
[face palm]
TGIF

Categories

Resources