How to assert method invocation? - fakeiteasy

Trying to verify that my service has been invoked. I don't care about the arguments, just that it was called once. I tried this
A.CallTo(() => topicWriterFake.Write(A<string>.Ignored, A<string>.Ignored, A<IEnumerable<string>>.Ignored))
.Returns(Task.CompletedTask);
//code that causes message to be written to bus
// now i try to verify that it has been called, but it fails with a message " Expected to find it once exactly but didn't find it among the calls:"
A.CallTo(() => topicWriterFake.Write(A<string>.Ignored, A<string>.Ignored, A<IEnumerable<string>>.Ignored))
.MustHaveHappenedOnceExactly();

Related

Scalatra: printing the HTTP status code of all APIs

I have a scalatra servlet with multiple REST APIs. For logging purposes, I use the after() method to print out the return status code after each API is called.
after() {
logger.info("request {} {} returned with status code {}", request.getMethod, request.getRequestURL, response.getStatus.toString)
}
I have noticed that when a method returns with halt, the status code is printed correctly, but when the method return a status code in the last line (without halt), the status code which will be printed will always be 200, regardless of real status returned.
For example:
post("/users/:user") {
try {
//some logic here...
if(condition)
halt(InternalServerError("DB error")) //this will cause status 500 to be printed in the 'after' method
} catch {
case e: Exception =>
InternalServerError("an unknown error occurred") //this will cause status 200 to be printed in the 'after' method
}
}
The user gets back the real status code (500) in both cases.
Any idea why this happens? Is this a bug?
I posted this question on the scalatra-user mailing list, but the list seems to be quite inactive.
Aliza
(disclaimer: I'm not a Scalatra developer but I have been using it for a project. This is based on me reading the code some time ago.)
This has to do with the way Scalatra is handling thrown exceptions (the relevant code seems to be start from this one). If the somewhere in runActions an exception is thrown (halt throws a HaltException), the catch block of cradleHalt will be called and we go to renderHaltException which will set the response status code.
It's not exactly the same when you're not calling halt but returns an ActionResult directly. In that case, executeRoutes seems to produce a value which is then passed on to renderResponse, which will then call renderResponseBody and finally the renderPipeline. This block seems to be the place where the actual status code from an ActionResult is actually set. However, the after function is already called (it was called in actionResult, before executeRoutes returns). So what you get is exactly your behavior: when you don't use halt, the correct response status is only set in the actual response but not your logging call.
You've probably tried this, but the quick fix to your InternalServerError not generating the correct HTTP status code when logged is to simply wrap it in another halt call.
As to whether this is a bug, I can't say. I'm guessing probably not, because they did say in the executeRoutes documentation that after is called before the actionResult is passed to renderResponse. What was not clear was that the act of rendering actionResult also sets the HTTP error code, which you wanted to log before.
You'll have to confirm with them on that :).

Why does this attempt to customize a type constraint error message fail?

The following construct creates a type constraint that functions as expected (checks for the "Roles::Thing" role when an attribute is set) When an attribute is rejected due to not passing the constraint I would expect the custom error message "Not a thing" to appear; however the default error message is still being given. What am I doing wrong?
role_type 'DoesThing', {
role => 'Roles::Thing',
message => sub { "Not a thing." }
};
Update: I did not provide enough context in the original post. The way I am trying to use the new type is:
has things => (
isa => 'ArrayRef[DoesThing]'
);
The type validation does work as expected; however I still get the default error message. My custom "Not a thing" error message is not propagated as I would have expected it to be.
The error message is what you get for an ArrayRef type, regardless of what you're expecting inside it.
To get a custom error message you'll need to incorporate ArrayRef into your type declaration:
subtype 'ArrayOfThings',
as 'ArrayRef[Roles::Thing]',
message { 'Not an array of things' };

Spray.io test response not matching actual output

I'm trying to set up some tests for an API made by a coworker with spray.io, and I'm encountering some odd behavior. When a request results in an error for any reason, we want to return a JSON value along the lines of:
{"status":false,"message":"useful message here"}
This happens just fine in the actual browser. I have navigated to an unhandled route in the web browser, and I get the desired JSON value. So, I want to test this. Now, since I'm new to spray.io, I started off with the very simple test:
"leave GET requests to root path unhandled" in {
Get() ~> myRoute ~> check {
handled must beFalse
}
}
This went fine, no problems. Since it's my first time playing with spray.io, I looked at some of the sample tests for testing false routes, and wrapped myRoute with sealRoute() so I could check the response without failing tests:
"leave GET requests to root path unhandled" in {
Get() ~> sealRoute(myRoute) ~> check {
handled must beTrue
}
}
This also works fine. So, I decided to just make sure the text of the response was usable with this, before I went to the trouble of parsing JSON and verifying individual values:
"leave GET requests to root path unhandled" in {
Get() ~> sealRoute(myRoute) ~> check {
responseAs[String] contains "false"
}
}
This is failing. To investigate, I threw a simple line of code in to log the actual value of responseAs[String] to a file, and I got this:
The requested resource could not be found.
Can anyone tell me what I'm doing wrong? I'm thinking that one of the following is occurring:
responseAs[String] is doing more than taking the exact response and giving it back to me, applying some type of filter along the way
The framework itself is not fully evaluating the query, but rather making a mockup object for the test framework to evaluate, and therefore not executing the desired 'turn errors to json' methods that my co-worker has implemented
I have tried searching google and stack overflow specifically for similar issues, but I'm either not putting in the right queries, or most other people are content to have the default error messages and aren't trying to test them beyond checking handled must beFalse.
Edit - This is the relevant part of the RejectionHandler:
case MissingQueryParamRejection(paramName) :: _=>
respondWithMediaType(`application/json`) {
complete(BadRequest, toJson(Map("status" -> false, "message" -> s"Missing parameter $paramName, request denied")))
}
Okay, so with insight from here and a coworker, the problem has been found:
Basically, the custom RejectionHandler was defined within our custom Actor object, and it wasn't coming into scope in the tests. To resolve this, the following steps were taken:
Moved the definition for the custom RejectionHandler into its own object in a separate file (as it had to do its own imports, it was causing a "encountered unrecoverable cycle resolving import" error)
Imported this new object into both the original file and the test spec.
(fun fact - http://spray.io/documentation/1.2.2/spray-routing/key-concepts/rejections/#rejectionhandler seems to demonstrate the RejectionHandler as a top-level object but you can't have top-level implicit vals in Scala, hence the need for an object)

Why is the loop portion of this loop react block not "looping" the way I expect?

I'm working on a homework assignment, modifying code created by my professor. Unfortunately, he's not available to me currently so I'm reaching out to the stackoverflow crowd.
This snippet is from a file "Peer.scala", which communicates with an actor from another class "RemoteActorChat.scala". I have only included the snippet that I believe is the cause of my issue, for the sake of brevity. Should the rest of the code be useful in finding a solution, I'll gladly post it.
My intent is to have the Peer capture input from the console in a continuous loop, while simultaneously reacting to any messages received from the RemoteChatActor.
...
def act {
...
loop {
val textInput = Console.readLine(name + ">").toString()
textInput match {
case "Unsubscribe" =>
unsubscribe
case "Subscribe" =>
subscribe(name))
case "?" =>
println("Type any message to send it to the chatroom")
println("Type 'Unsubscribe' (without quotes) to leave the chatroom")
println("Type 'Subscribe' (without quotes) to re-join the chatroom")
case _ =>
post(textInput)
}
react {
case Post(msg) =>
println(name + " got a post = " + msg)
}
}
}
...
When the inputText is matched to _ the post function is called, does it's thing and I get another prompt. I can post messages all day long like this if I want.
However, when inputText is matched to "Unsubscribe", "Subscribe", or "?", the behavior is different. The statements in the case are executed IE) the unsubscribe or subscribe functions are called and do their thing as expected. However, I don't get the prompt back to continue sending input from the console. The peer basically just hangs at this point. I expect another prompt but the console window is just empty and doesn't take any additional input.
Clearly my understanding of how this should work is flawed.
What am I misunderstanding, and how can I make this do what I intend?
The actor is waiting for a Post inside react. It won't continue until it gets one. Since you only send one in one case, only that case gets through.
If you want to make the other cases work, either have them also send a message that the react block can receive (at least as a case _ inside the react block), or move the react block so it will only be entered if there will in fact be a Post coming back its way at some point.

Zend_Validate_Abstract custom validator not displaying correct error messages

I have two text fields in a form that I need to make sure neither have empty values nor contain the same string.
The custom validator that I wrote extends Zend_Validate_Abstract and works correctly in that it passes back the correct error messages. In this case either: isEmpty or isMatch.
However, the documentation says to use addErrorMessages to define the correct error messages to be displayed.
in this case, i have attached
->addErrorMessages(array("isEmpty"=>"foo", "isMatch"=>"bar"));
to the form field.
According to everything I've read, if I return "isEmpty" from isValid(), my error message should read "foo" and if i return "isMatch" then it should read "bar".
This is not the case I'm running into though. If I return false from is valid, no matter what i set $this->_error() to be, my error message displays "foo", or whatever I have at index[0] of the error messages array.
If I don't define errorMessages, then I just get the error code I passed back for the display and I get the proper one, depending on what I passed back.
How do I catch the error code and display the correct error message in my form?
The fix I have implemented, until I figure it out properly, is to pass back the full message as the errorcode from the custom validator. This will work in this instance, but the error message is specific to this page and doesn't really allow for re-use of code.
Things I have already tried:
I have already tried validator chaining so that my custom validator only checks for matches:
->setRequired("true")
->addValidator("NotEmpty")
->addErrorMessage("URL May Not Be Empty")
->addValidator([*customValidator]*)
->addErrorMessage("X and Y urls may not be the same")
But again, if either throws an error, the last error message to be set displays, regardless of what the error truly is.
I'm not entirely sure where to go from here.
Any suggestions?
I think you misinterpreted the manual. It says
addErrorMessage($message): add an
error message to display on form
validation errors. You may call this
more than once, and new messages are
appended to the stack.
addErrorMessages(array $messages): add
multiple error messages to display on
form validation errors.
These functions add custom error messages to the whole form stack.
If you want to display validation error messages when the validation fails, you have to implement the message inside your validator.
ie.
const EMPTY = 'empty';
protected $_messageTemplates = array(
self::EMPTY => "Value is required and can't be empty",
);
public function isValid($value)
{
if(empty($value)) {
$this->_error(self::EMPTY);
return false;
}
return true;
}
This way, after the validation fails, you can get the error codes using $validator->getErrors() and the error messages using $validator->getMessages().
If you have the $_messageTemplates properly defined, Zend_Form automatically uses the error messages instead of error codes and prints them out.
Hope this helps.