I have a in issue where I would like to swap out Moq for NSubstitute entirely. In most cases, this is extremely straightforward, however I have run across a fairly specialized issue.
Here's the Moq code.
_registrationCommandHandler.Setup(c => c.Execute
(It.Is<CheckUniqueUserCommand>(r => r.Request.UserName == "fred"))).
Callback((CheckUniqueUserCommand c) =>
{
c.Response = new CheckUserNameIsUniqueResponse()
{
IsUnique = true,
Success = true
};
c.Success = true;
});
The closest I seem to be able to get with NSubstitute is
_registrationCommandHandler.When(c => c.Execute
(Arg.Any<CheckUniqueUserCommand>())).Do
((CheckUniqueUserCommand c) =>
{
c.Response = new __Internal.CheckUserNameIsUniqueResponse()
{
IsUnique = true,
Success = true
};
c.Success = true;
});
which won't even compile. This leaves me a bit stuck. Does anyone have any suggestions?
I'm guessing a bit here, but try:
_registrationCommandHandler
.When(c => c.Execute(Arg.Is<CheckUniqueUserCommand>(r => r.Request.UserName == "fred")))
.Do(call => {
var c = call.Arg<CheckUniqueUserCommand>();
c.Response = new __Internal.CheckUserNameIsUniqueResponse()
{
IsUnique = true,
Success = true
};
c.Success = true;
});
NSubstitute does not do the same argument passing as Moq does for callbacks. Instead it passes a parameter with information about the call, and you can access the arguments using call.Arg<T> or call[i].
In addition to changing the .Do block, I also switched from using Arg.Any(..) to Arg.Is(..) to closer match the Moq sample.
Hope this helps.
Related
I have two sets of code (below) that fetches items from a container that match conditions specified in "where" statement. One with the sql query works as expected whereas the other with the Linq expressions doesn't. The Linq one would return items if I remove all "Where" statements but what I want is to fetch items matching the conditions in those "Where" statements. Can you help me understand why the Linq one doesn't work?
QueryRequestOptions queryRequestOptions = new QueryRequestOptions()
{
MaxItemCount = DefaultPageSize, // 100
};
// THIS CODE WORKS
string query = $"SELECT * FROM root r WHERE r.documentType = #documentType and r._ts > #timestamp";
QueryDefinition queryDefinition = new QueryDefinition(query);
queryDefinition.WithParameter("#documentType", docType);
queryDefinition.WithParameter("#timestamp", TimestampConverter.ToTimestamp(fromTime));
using (var feedIterator = container.GetItemQueryIterator<T>(
queryDefinition,
null,
queryRequestOptions))
{
while (feedIterator.HasMoreResults)
{
FeedResponse<T> feedResponse = await feedIterator.ReadNextAsync(cancellationToken);
// THIS CODE DOESN"T WORK
using (var feedIterator = container.GetItemLinqQueryable<T>(false, null, queryRequestOptions)
.Where(d => d.DocumentType == docType)
.Where(d => d.Timestamp > fromTime)
.ToFeedIterator())
{
while (feedIterator.HasMoreResults)
{
FeedResponse<T> feedResponse = await feedIterator.ReadNextAsync(cancellationToken);
}
you can try like this
select many is used wherever i have an array in document
container.GetItemLinqQueryable<>()
.Where(ar => ar.FiscalYear == fiscalYear)
.SelectMany(ar => ar.ResourcePrivileges.Where(arp => arp.ResourceName == accessRequest.PendingUserRequest.ResourcePrivileges.ResourceName)
.SelectMany(rp => rp.Filters.Where(f => (int)f.Role > 2 && subRegionLst.Contains(f.SubRegion) && reqProduct.Contains(f.ProductName)))
.Select(i => new
{
Alias = ar.UserAlias,
Filter = ar.ResourcePrivileges.Where(arp => arp.ResourceName == accessRequest.PendingUserRequest.ResourcePrivileges.ResourceName).SelectMany(x => x.Filters),
})).Distinct();
I believe your issue has to do with how the linq query in serialized. By default GetItemLinqQueryable doesn't use camel case.
You can control the serialization by passing serializing options:
container.GetItemLinqQueryable<T>(
linqSerializerOptions: new CosmosLinqSerializerOptions
{
PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
});
I'm trying to implement the ASP.NET Core 2.2 health check feature. Setting up the health check itself isn't the problem, but I also want to be able to use the UI feature in other project to monitoring all my apis. Right now I get the exception message
Unexpected character encountered while parsing value: <.
What I'm doing bad?
API Project:
var healthCheckOptions = new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = async (c, r) =>
{
c.Response.ContentType = MediaTypeNames.Application.Json;
var result = JsonConvert.SerializeObject(
new
{
Checks = r.Entries.Select(e =>
new
{
Description = e.Key,
Status = e.Value.Status.ToString(),
ResponseTime = e.Value.Duration.TotalMilliseconds
}),
TotalResponseTime = r.TotalDuration.TotalMilliseconds
});
await c.Response.WriteAsync(result);
}
};
app.UseHealthChecks("/live", new HealthCheckOptions
{
Predicate = _ => true
});
app.UseHealthChecks("/hc", healthCheckOptions);
app.UseHealthChecksUI(options => options.UIPath = "/healtcheck");
// Registers required services for health checks
services
.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddCheck("ComunContext Database", new SqlServerHealthCheck(configuration["ConnectionStrings:ComunContext"]));
Web project:
services.AddHealthChecksUI();
app.UseHealthChecksUI(config =>
{
config.UIPath = "/healthcheck";
});
appsettings.json
{
"HealthChecks-UI": {
"HealthChecks": [
{
"Name": "Local",
"Uri": "http://localhost:27365/hc"
}
],
"EvaluationTimeOnSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 60
}
}
Try adding a ResponseWriter:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/healthchecks", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "application/json; charset=utf-8";
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(report));
await context.Response.Body.WriteAsync(bytes);
}
});
app.UseHealthChecksUI();
}
After a few days struggling with this parser error, I've figured out that there are 2 problems:
1 - If you have an Exception, Health UI tries to convert Exception object field, resulting on error;
2 - If you try to pass your own anonymous object, Health UI fails to convert Entries collection, because it need to be an specific anonymous Dictionary.
Try this:
var healthCheckOptions = new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = async (c, r) =>
{
c.Response.ContentType = MediaTypeNames.Application.Json;
var result = JsonConvert.SerializeObject(
new
{
Checks = r.Entries.ToDictionary(
e => e.Key,
e =>
new
{
Description = e.Key,
Status = e.Value.Status.ToString(),
ResponseTime = e.Value.Duration.TotalMilliseconds
}),
TotalResponseTime = r.TotalDuration.TotalMilliseconds
});
await c.Response.WriteAsync(result);
}
};
currently I'm trying to check if there is a way to get the class names of all attributes on razor page classes.
I unit tests all my controllers to look for an AuthorizeFilter so that it is impossible to forget it
Currently this is how I do it via MVC (does not work in Razor Pages):
var values = actionDescriptorCollectionProvider
.ActionDescriptors
.Items
.OfType<ControllerActionDescriptor>()
.Select(a => new
{
a.DisplayName,
a.ControllerName,
a.ActionName,
AttributeRouteTemplate = a.AttributeRouteInfo?.Template,
HttpMethods = string.Join(", ", a.ActionConstraints?.OfType<HttpMethodActionConstraint>().SingleOrDefault()?.HttpMethods ?? new string[] { "any" }),
Parameters = a.Parameters?.Select(p => new
{
Type = p.ParameterType.Name,
p.Name
}),
ControllerClassName = a.ControllerTypeInfo.FullName,
ActionMethodName = a.MethodInfo.Name,
Filters = a.FilterDescriptors?.Select(f => new
{
ClassName = f.Filter.GetType().FullName,
f.Scope //10 = Global, 20 = Controller, 30 = Action
}),
Constraints = a.ActionConstraints?.Select(c => new
{
Type = c.GetType().Name
}),
RouteValues = a.RouteValues.Select(r => new
{
r.Key,
r.Value
}),
});
The problem is, that this code won't work with Razor Pages, i.e. FilterDescriptors is empty for PageActionDescriptor.
You need to use PageActionDescriptor for RazorPages instead of ControllerActionDescriptor:
var values = actionDescriptorCollectionProvider
.ActionDescriptors
.Items
.OfType<PageActionDescriptor>()
.Select(descriptor => new
{
// descriptor...,
// ...
});
In Reason, what would be the most elegant way of having an interval that clears itself when some condition is satisfied? In JavaScript I could do:
var myInterval = setInterval(function () {
// do some stuff
if (fancyCondition) {
clearInterval(myInterval);
}
}, 1000);
In Reason, the best I've come up with so far is this:
let intervalIdRef = ref(None);
let clearInterval = () =>
switch (intervalIdRef^) {
| Some(intervalId) => Js.Global.clearInterval(intervalId)
| None => ()
};
let intervalId = Js.Global.setInterval(() => {
/* do some stuff */
fancyCondition ? clearInterval() : ();
}, 1000);
intervalIdRef := Some(intervalId);
Is there a way to avoid using a ref?
setInterval/clearInterval is inherently mutable, but even if it wasn't your fancyCondition would be anyway, so removing the one ref here wouldn't buy you a lot. I think even with the ref it could improved through encapsulation though, and depending slightly on your fancyCondition we should be able to get the same behavior in a purely functional way by using setTimeout instead of setInterval/clearInterval.
First, let's make your example concrete by adding a counter, printing the count, and then clearing the interval when we reach count 5, so we have something to work with:
let intervalIdRef = ref(None);
let count = ref(0);
let clearInterval = () =>
switch (intervalIdRef^) {
| Some(intervalId) => Js.Global.clearInterval(intervalId)
| None => ()
};
let intervalId = Js.Global.setInterval(() => {
if (count^ < 5) {
Js.log2("tick", count^);
count := count^ + 1;
} else {
Js.log("abort!");
clearInterval();
}
}, 200);
intervalIdRef := Some(intervalId);
The first thing I think we should do is to encapsulate the timer state/handle by wrapping it in a function and pass clearInterval to the callback instead of having it as a separate function that we might call several times without knowing if it actually does anything:
let setInterval = (timeout, action) => {
let intervalIdRef = ref(None);
let clear = () =>
switch (intervalIdRef^) {
| Some(intervalId) => Js.Global.clearInterval(intervalId)
| None => ()
};
let intervalId = Js.Global.setInterval(() => action(~clear), timeout);
intervalIdRef := Some(intervalId);
};
let count = ref(0);
setInterval(200, (~clear) => {
if (count^ < 5) {
Js.log2("tick", count^);
count := count^ + 1;
} else {
Js.log("abort!");
clear();
}
});
We've now gotten rid of the global timer handle, which I think answers your original question, but we're still stuck with count as global state. So let's get rid of that too:
let rec setTimeout = (timeout, action, state) => {
let continue = setTimeout(timeout, action);
let _:Js.Global.timeoutId =
Js.Global.setTimeout(() => action(~continue, state), timeout)
};
setTimeout(200, (~continue, count) => {
if (count < 5) {
Js.log2("tick", count);
continue(count + 1);
} else {
Js.log("abort!");
}
}, 0);
Here we've turned the problem upside down a bit. Instead of using setInterval and clearInterval and passing a clear function into our callback, we pass it a continue function that's called when we want to carry on instead of when we want to bail out. That allows us to pass state forward, and to change the state without using mutation and refs by using recursion instead. And it does so with less code. I think that'd qualify as pretty elegant, if not precisely what you asked for :)
I am trying to publish forum replies to a specific thread, but I would like those reply documents to include extra information about the user that posted it.
I don't want to "save" that extra information on the reply itself but rather, publish an "improved" version of it.
I am doing something similar on client-side already with mycollection.find().map() and using the map function to embedded extra information on each of the returned documents, however, Meteor publish cannot seem to publish an array, only a Cursor, so the simple map function is off limits.
Is there a way to achieve this? Maybe a "map" function that returns a Cursor?
I am not using Meteor.methods so that I can have reactivity, because with them I could just return an array and use it as normal.
Here is an example of my code (that fails, but sends gives an idea of what I need):
Meteor.publish("forumthread", function(thread){
return forumReplies.find({thread: thread}).map(function(r){
// lets fill in additional data about each replies owner
var owner = Meteor.users.findOne({_id: r.owner});
if(!owner)
return; // no owner no reply..
if(!owner.forumStats){
owner.forumStats = {};
owner.forumStats.postCount = 0;
owner.forumStats.postLikes = 0;
owner.forumStats.title = "The Newbie";
owner.forumStats.tag = "Newbie";
Meteor.users.update({_id: owner._id}, {$set:{ forumStats:owner.forumStats }});
}
r.ownerid = owner._id;
r.ownerUsername = owner.username;
r.ownerPostCount = owner.forumStats.postCount;
r.ownerPostLikes = owner.forumStats.postLikes;
r.ownerTitle = owner.forumStats.title;
r.ownerTag = owner.forumStats.tag;
return r;
});
});
Thank you.
Ended up doing this (found out that Christian Fritz also suggested it):
Meteor.publish("serverforumthread", function(thread){
check(thread, String);
var replies = forumReplies.find({thread: thread});
var users = {};
replies.map(function(r){
users[r.owner] = r.owner;
});
var userids = _.map(users, function(value, key){ return value; });
var projectedFields = {_id:1, username:1, forumStats: 1, services: 0};
var usrs = Meteor.users.find({_id:{$in: userids}}, projectedFields);
var anyUpdateToUsers = false;
usrs.map(function(owner){
var changed = false;
if(!owner.username){
owner.username = owner.emails[0].address.split("#")[0];
changed = true;
}
//owner.forumStats = undefined;
if(!owner.forumStats){
owner.forumStats = {};
owner.forumStats.postCount = 0;
owner.forumStats.postLikes = 0;
owner.forumStats.title = "the newbie";
owner.forumStats.tag = "newbie";
owner.forumStats.img = "http://placehold.it/122x122";
changed = true;
}
if(changed){
anyUpdateToUsers = true;
Meteor.users.update({_id: owner._id}, {$set:{ forumStats:owner.forumStats }});
}
});
if(anyUpdateToUsers) // refresh it
usrs = Meteor.users.find({_id:{$in: userids}}, projectedFields);
usrs.map(function(owner){
console.log(owner);
});
return [replies, usrs];
});
It works great with the following client side:
Template.forumReplyOwner.helpers({
replyOwner: function(reply){
var owner = Meteor.users.findOne({_id: reply.owner});
console.log(reply, owner);
if(!owner || !owner.forumStats) return; // oh shait!
var r = {};
r.owner = owner._id;
r.ownerUsername = owner.username;
r.ownerPostCount = owner.forumStats.postCount;
r.ownerPostLikes = owner.forumStats.postLikes;
r.ownerTitle = owner.forumStats.title;
r.ownerTag = owner.forumStats.tag;
r.ownerImg = owner.forumStats.img;
return r;
},
ownerImgTab: function(){
return {src: this.ownerImg};
}
});
However, I am now facing another problem. Even tho I am restricting the fields I am publishing from the Users collection, it is still sending down the "services" field, that contains login data that shouldnt be sent, ideas?