Right way to add a per-request response delay to a custom HttpService - armeria

Here's my current implementation of HttpService.serve()
#Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse Utils.toResponse(myResponse);
return httpResponse;
}));
}
I have a user-defined response delay which can vary per each individual request-response, and this is available in the myResponse object.
What is the best way to apply this delay in a non-blocking way, I can see some delay API-s but they are protected within HttpResponse . Any extra tips or pointers to the streaming API design or decorators would be helpful. I'm really learning a lot from the Armeria code base :)

If you know the desired delay even before consuming the request body, you can simply use HttpResponse.delayed():
#Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.delayed(
HttpResponse.of(200),
Duration.ofSeconds(3),
ctx.eventLoop());
}
If you need to consume the content or perform some operation to calculate the desired delay, you can combine HttpResponse.delayed() with HttpResponse.from():
#Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenApply(ahr -> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
MyResponse myResponse = Utils.handle(ahr);
HttpResponse httpResponse = Utils.toResponse(myResponse);
Duration myDelay = Utils.delayMillis(...);
return HttpResponse.delayed(httpResponse, myDelay, ctx.eventLoop());
// ^^^^^^^
});
}
If the delay is not actually delay but waiting for something to happen, you can use CompletableFuture.thenCompose() which is more powerful:
#Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(req.aggregate().thenCompose(ahr -> {
// ^^^^^^^^^^^
My1stResponse my1stRes = Utils.handle(ahr);
// Schedule some asynchronous task that returns another future.
CompletableFuture<My2ndResponse> myFuture = doSomething(my1stRes);
// Map the future into an HttpResponse.
return myFuture.thenApply(my2ndRes -> {
HttpResponse httpRes = Utils.toResponse(my1stRes, my2ndRes);
return httpRes;
});
});
}
For even more complicated workflow, I'd recommend you to look into Reactive Streams implementations such as Project Reactor and RxJava, which provides the tools for avoiding the callback hell. 😄

Related

Mock Ktor's http client with MockK

I want to mock requests with ktor's http client using MockK. The problem is all the methods related to making requests with the client are inline, so I cannot use coEvery on those methods. The next thing I tried was to go through the called methods until I found a method that wasn't inline and then mock that. After stepping through some functions, the HttpClient.request() function instantiates an HttpStatement and then calls execute() on it.
public suspend inline fun HttpClient.request(
builder: HttpRequestBuilder = HttpRequestBuilder()
): HttpResponse = HttpStatement(builder, this).execute()
If I can mock the constructor and .execute() functions, I can intercept the call and return my canned response. I can then check that the builder's params are correct inside of a verify function.
mockkConstructor(HttpStatement::class)
coEvery { anyConstructed<HttpStatement>().execute() } returns mockk {
coEvery { status } returns HttpStatusCode.OK
coEvery { body<RefreshToken>() } returns RefreshToken()
}
This code takes care of intercepting the execute call. The next step would be to verify the constructor params of HttpStatement. This code to verify execute was called works:
coVerify { anyConstructed<HttpStatement>().execute() }
Next thing is to verify the constructor params. This pull request in the MockK repo describes how to verify constructors:
coVerify { constructedWith<HttpStatement>(/* Matchers here */).execute() }
Note that I have to add the .execute() or else MockK tells me I'm not verifying anything.
Missing calls inside verify { ... } block.
io.mockk.MockKException: Missing calls inside verify { ... } block.
at app//io.mockk.impl.recording.states.VerifyingState.checkMissingCalls(VerifyingState.kt:52)
at app//io.mockk.impl.recording.states.VerifyingState.recordingDone(VerifyingState.kt:21)
...
Ok, so just add in the matchers. However, no combination of matchers I try works. I've tried doing a bunch of constant matchers for type Any (which should match anything right?)
coVerify { constructedWith<HttpStatement>(ConstantMatcher<Any>(true))}
I've tried a matcher for HttpRequestBuilder and HttpClient
coVerify {
constructedWith<HttpStatement>(
ConstantMatcher<HttpRequestBuilder>(true),
ConstantMatcher<HttpClient>(true)
).execute()
}
And a whole slew of others. Each time, I get this error:
Verification failed: call 1 of 1: HttpStatement(mockkConstructor<HttpStatement>(any(), any())).execute(any())) was not called
java.lang.AssertionError: Verification failed: call 1 of 1: HttpStatement(mockkConstructor<HttpStatement>(any(), any())).execute(any())) was not called
at io.mockk.impl.recording.states.VerifyingState.failIfNotPassed(VerifyingState.kt:63)
at io.mockk.impl.recording.states.VerifyingState.recordingDone(VerifyingState.kt:42)
...
Next thing I figured I could try would be to use an answers block earlier on in order to print out the types of the parameters being passed in case I was wrong, but that also runs into the "nothing being done in every block" error.
coEvery { anyConstructed<HttpStatement>() } answers {
args.filterNotNull().map { it::class.qualifiedName }.forEach(::println)
mockk {
coEvery { execute().status } returns HttpStatusCode.OK
coEvery { execute().body<RefreshToken>() } returns RefreshToken(
accessToken = accessToken,
expiresIn = expiresIn,
)
}
}
Is there a solution to mocking the http client? Do I have to mock something even more internal? Or do I just have to stick to using the ktor MockEngine?

Test that method is called in handler in Golang

I am implementing a API in Golang. I have a endpoint where I am calling a method with parameters of other package. Now I need to check that, that method has been called in the request.
Below is the small similar scenario what I am doing and what I am expecting.
My handler
package myPackage
import (
"log"
"github.com/myrepo/notifier" // my another package
)
func MyHandler(writer http.ResponseWriter, request *http.Request) {
// ...
// ...
notifier.Notify(4, "sdfsdf")
// ...
// ...
}
Testing handler
func TestMyHandler(t *testing.T) {
// Here I want to
req, _ := http.NewRequest("GET", "/myendpoint", nil)
// ... Want to test that notifier.Notify is called
// ...
}
In the TestMyHandler, I want to check that notifier.Notify has called.
Findings
I tried to understand the AssertNumberOfCalls, func (*Mock) Called, and func (*Mock) MethodCalled but I am not sure how to use them :(.
I am a newbie in Golang and really exicted to do that.
Please let me know if I missed anything or you may need more information for more understaing.
This is a good opportunity to use dependency injection and interfaces.
Namely, we need to extract the concept of a Notifier
(warning: code not tested directly)
type Notifier interface {
Notify(int, string)() error
}
Now to avoid any confusion with the notifier library, use a local alias.
import "github.com/myrepo/notifier" mynotifier
Then, because the library you're using exports it as a function, not within a struct, we'll need to make a struct that implements our interface
type myNotifier struct {}
func (mn *myNotifier) Notify(n int, message string) error {
return mynotifier.Notify(n, message)
}
Then you modify your function:
func MyHandler(writer http.ResponseWriter, request *http.Request, notifier Notifier) {
// ...
// ...
notifier.Notify(4, "sdfsdf")
// ...
// ...
}
Then in your test, you're now free to send in a spy Notifier
type spyNotifier struct {
called boolean
}
func (n *spyNotifier) Notify(n int, msg string) error {
n.called = true
return
}
Want to test that notifier.Notify is called.
No you don't. You are interested in that the handler does what it should do and this seems to consist of two things:
Return the right response (easy to test with a net/http/httptest.ResponseRecorder), and
Has some noticeable side effect, here issue some notification.
To test 2. you test that the notification was issued, not that some function was called.
Whatever notify.Notify results in (e.g. a database entry, a file, some HTTP call) should be tested. Formally this is no longer unit testing but testing for side effects is never strict unit testing.
What you can do: Wrap your handler logic into some object and observe that objects state. Ugly. Don't.
This approach is similar to Mathew's answer, but uses the mock package from testify instead. Here, you create a mock implementation of the Notifier, register the method call, and assert that the method has been called with the expected arguments.
Implementation
package handler
import (
"net/http"
"github.com/stretchr/testify/mock"
)
// the interface for the Notifier
type Notifier interface {
Notify(int, string) error
}
// the mock implementation of the interface above
type MockNotifier struct {
mock.Mock
}
// stub the notify method to ensure it can be expected later in the test
func (mockNotifier *MockNotifier) Notify(arg1 int, arg2 string) error {
args := mockNotifier.Called(arg1, arg2)
return args.Error(0)
}
// this handler which accepts a Notifier for dependency injection
type Handler struct {
notifier Notifier
}
// the MyHandler implementation which calls the notifier instance
func (h *Handler) MyHandler(writer http.ResponseWriter, request *http.Request) {
// this is what we want to test!
h.notifier.Notify(4, "sdfsdf")
}
Test
package handler_test
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestMyHandler(t *testing.T) {
t.Parallel()
mockNotifier := MockNotifier{}
handler := Handler{ notifier: &mockNotifier }
// register the mock to expect a call to Notify with the given arguments and return nil as the error
mockNotifier.On("Notify", 4, "sdfsdf").Return(nil)
// setup the test arguments
request := httptest.NewRequest(http.MethodGet, "/someapi", nil)
writer := httptest.NewRecorder()
// call the handler
handler.MyHandler(writer, request)
// this is the important part!!
// this ensures that the mock Notify method was called with the correct arguments, otherwise the test will fail
mockNotifier.AssertExpectations(t)
}

Async client response with cpp-netlib?

I am considering using cpp netlib for a new project. All of the examples show reading the body of the response in a blocking manner:
client::response response_ = client_.get(request_);
std::string body_ = body(response_);
If I construct my client object with the async tag:
basic_client<http_async_8bit_udp_resolve_tags, 1, 1> client_();
What affect does that have?
Is it possible to get the results of the body wrapper as a boost::shared_future<std::string>?
Do I just need to wrap the blocking call in it's own thread?
Look at the current http client doc: http://cpp-netlib.org/0.12.0/reference/http_client.html
the http client is now always async by default
you have an option to provide a callback function or object in the get or post call:
struct body_handler {
explicit body_handler(std::string & body)
: body(body) {}
BOOST_NETWORK_HTTP_BODY_CALLBACK(operator(), range, error) {
// in here, range is the Boost.Range iterator_range, and error is
// the Boost.System error code.
if (!error)
body.append(boost::begin(range), boost::end(range));
}
std::string & body;
};
// somewhere else
std::string some_string;
response_ = client_.get(request("http://cpp-netlib.github.com/"),
body_handler(some_string));
The client::response object already incapsulates the future object:
The response object encapsulates futures which get filled in once the values are available.

Why we should pass pointer in listenHTTP to &handleRequest?

I am reading vibed examples and can't understand next moment:
import vibe.d;
shared static this()
{
auto settings = new HTTPServerSettings;
settings.port = 8080;
listenHTTP(settings, &handleRequest);
}
void handleRequest(HTTPServerRequest req,
HTTPServerResponse res)
{
if (req.path == "/")
res.writeBody("Hello, World!", "text/plain");
}
Why we are passing in listenHTTP pointer to &handleRequest. I mean why we can't simply call it for every request?
And what about HTTPServerRequest req and HTTPServerResponse res? Are they are creating in moment of handleRequest calling or when?
The pointer is how the library knows what function you want it to call on every request.
You pass it the pointer to the function, then vibe creates the req and res at that point and calls the pointed to function each time it gets a new request.
If you tried to pass handleRequest without the pointer, it would try to call it at setup time, before a request was actually ready.

Injection in the setUp() method causes the framework not to wait for the Future to complete

I am testing an AngularDart component. I am trying to fetch the template and put it in TemplateCache in the setUp() method. For this I need to inject the template cache. However the inject in the setUp() makes the framework continue to the test method and not waiting for the Future to complete. Here is a simplified example.
import 'dart:async';
import 'package:angular/angular.dart';
import 'package:mock/mock.dart';
import 'package:unittest/unittest.dart';
import 'package:angular/mock/test_injection.dart';
import 'package:angular/mock/module.dart';
import 'package:di/di.dart';
class MyTest {
static main() {
group("SetUp with future that waits", () {
setUp(() {
return new Future.value("First").then((_) => print(_));
});
test("Welcome to the world of tomorrow!", () {
print("Second");
});
});
group("SetUp with future that doesn't wait", () {
setUp(inject((Injector inject) { // injection causes the test to not wait
return new Future.value("First").then((_) => print(_));
}));
test("Welcome to the world of tomorrow!", () {
print("Second");
});
});
}
}
In the console you can see the printed messages: First, Second, Second, First.
I think it must be that the inject is not returning the Future. What else can I do to both have the framework injecting objects that I need and waiting for the Future in the setUp()?
This is what I needed. The mistake was trying to return something from the inject itself. It is actually as simple as this:
setUp(() {
// ...
inject((Injectable injectable) {
// inject the objects here and save them in variables
});
// work with the variables
return new Future.value("First").then((_) => print(_));
});