/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.wisdom.executors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.wisdom.api.annotations.scheduler.Async;
import org.wisdom.api.concurrent.ManagedExecutorService;
import org.wisdom.api.concurrent.ManagedFutureTask;
import org.wisdom.api.exceptions.HttpException;
import org.wisdom.api.http.AsyncResult;
import org.wisdom.api.http.Result;
import org.wisdom.api.http.Results;
import org.wisdom.api.http.Status;
import org.wisdom.api.interception.RequestContext;
import org.wisdom.api.router.Route;
import org.wisdom.test.parents.FakeConfiguration;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
/**
* Checks the Async Interceptor.
*/
public class AsyncInterceptorTest {
AsyncInterceptor interceptor = new AsyncInterceptor();
ManagedExecutorService executor = new ManagedExecutorServiceImpl("test", new FakeConfiguration(Collections.<String, Object>emptyMap()), null);
@Before
public void setUp() throws ClassNotFoundException {
BundleContext context = mock(BundleContext.class);
Bundle bundle = mock(Bundle.class);
when(bundle.getBundleId()).thenReturn(1L);
when(context.getBundle()).thenReturn(bundle);
doAnswer(
new Answer<Class>() {
@Override
public Class answer(InvocationOnMock invocation) throws Throwable {
return AsyncInterceptorTest.class.getClassLoader().loadClass((String) invocation.getArguments()[0]);
}
}
).when(bundle).loadClass(anyString());
interceptor.executor = executor;
}
@After
public void tearDown() {
executor.shutdownNow();
}
@Test
public void testWithoutTimeout() throws Exception {
RequestContext rc = mock(RequestContext.class);
Route route = mock(Route.class);
when(route.getUrl()).thenReturn("/");
when(rc.proceed()).thenReturn(new Result(Status.OK));
Async async = mock(Async.class);
when(async.timeout()).thenReturn(0l);
when(async.unit()).thenReturn(TimeUnit.SECONDS);
Result result = interceptor.call(async, rc);
assertThat(result).isInstanceOf(AsyncResult.class);
final int[] code = {0};
ManagedFutureTask<Result> r = executor.submit(((AsyncResult) result).callable())
.onSuccess(new ManagedFutureTask.SuccessCallback<Result>() {
@Override
public void onSuccess(ManagedFutureTask<Result> future, Result result) {
code[0] = result.getStatusCode();
}
});
Thread.sleep(100);
assertThat(code[0]).isEqualTo(200);
}
@Test
public void testWithTimeout() throws Exception {
RequestContext rc = mock(RequestContext.class);
when(rc.proceed()).thenReturn(new Result(Status.OK));
Async async = mock(Async.class);
when(async.timeout()).thenReturn(1l);
when(async.unit()).thenReturn(TimeUnit.SECONDS);
Result result = interceptor.call(async, rc);
assertThat(result).isInstanceOf(AsyncResult.class);
final int[] code = {0};
ManagedFutureTask<Result> r = executor.submit(((AsyncResult) result).callable())
.onSuccess(new ManagedFutureTask.SuccessCallback<Result>() {
@Override
public void onSuccess(ManagedFutureTask<Result> future, Result result) {
code[0] = result.getStatusCode();
}
});
Thread.sleep(100);
assertThat(code[0]).isEqualTo(200);
}
@Test
public void testWithFunctionalError() throws Exception {
RequestContext rc = mock(RequestContext.class);
doAnswer(new Answer<Result>() {
@Override
public Result answer(InvocationOnMock invocation) throws Throwable {
throw new IllegalAccessException("Bad, but expected");
}
}).when(rc).proceed();
Route route = mock(Route.class);
when(route.getUrl()).thenReturn("/");
when(rc.route()).thenReturn(route);
Async async = mock(Async.class);
when(async.timeout()).thenReturn(10l);
when(async.unit()).thenReturn(TimeUnit.SECONDS);
Result result = interceptor.call(async, rc);
assertThat(result).isInstanceOf(AsyncResult.class);
final Throwable[] errors = {null};
ManagedFutureTask<Result> r = executor.submit(((AsyncResult) result).callable())
.onFailure(new ManagedFutureTask.FailureCallback<Result>() {
@Override
public void onFailure(ManagedFutureTask<Result> future, Throwable throwable) {
errors[0] = throwable;
}
});
Thread.sleep(100);
assertThat(errors[0]).isNotNull().isInstanceOf(HttpException.class);
assertThat(errors[0].getCause().getMessage())
.contains("Bad, but expected");
}
@Test
public void testWithTimeoutReached() throws Exception {
RequestContext rc = mock(RequestContext.class);
doAnswer(new Answer<Result>() {
@Override
public Result answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(1000);
return Results.ok("Done");
}
}).when(rc).proceed();
Route route = mock(Route.class);
when(route.getUrl()).thenReturn("/");
when(rc.route()).thenReturn(route);
Async async = mock(Async.class);
// Must be below the thread.sleep from the action.
when(async.timeout()).thenReturn(10l);
when(async.unit()).thenReturn(TimeUnit.MILLISECONDS);
Result result = interceptor.call(async, rc);
assertThat(result).isInstanceOf(AsyncResult.class);
final Result[] retrieved = {null};
final Throwable[] errors = {null};
ManagedFutureTask<Result> r = executor.submit(((AsyncResult) result).callable())
.onSuccess(new ManagedFutureTask.SuccessCallback<Result>() {
@Override
public void onSuccess(ManagedFutureTask<Result> future, Result result) {
retrieved[0] = result;
}
})
.onFailure(new ManagedFutureTask.FailureCallback() {
@Override
public void onFailure(ManagedFutureTask future, Throwable throwable) {
errors[0] = throwable;
}
});
Thread.sleep(100);
assertThat(retrieved[0]).isNull();
assertThat(errors[0]).isNotNull().isInstanceOf(HttpException.class);
assertThat(errors[0].getMessage())
.contains("Request timeout");
}
}