/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.
*/
package org.jboss.arquillian.warp.impl.client.execution;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.arquillian.test.spi.event.suite.AfterClass;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import org.jboss.arquillian.warp.Activity;
import org.jboss.arquillian.warp.Inspection;
import org.jboss.arquillian.warp.Warp;
import org.jboss.arquillian.warp.WarpRuntimeInitializer;
import org.jboss.arquillian.warp.WarpTest;
import org.jboss.arquillian.warp.client.execution.SingleInspectionSpecifier;
import org.jboss.arquillian.warp.client.execution.WarpActivityBuilder;
import org.jboss.arquillian.warp.client.execution.WarpRuntime;
import org.jboss.arquillian.warp.client.filter.Request;
import org.jboss.arquillian.warp.impl.client.scope.WarpExecutionContext;
import org.jboss.arquillian.warp.impl.client.testbase.AbstractWarpClientTestTestBase;
import org.jboss.arquillian.warp.impl.shared.RequestPayload;
import org.jboss.arquillian.warp.impl.shared.ResponsePayload;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Lukas Fryc
*/
@RunWith(MockitoJUnitRunner.class)
// TODO add multiple request execution tests
public class TestRequestExecutionSynchronization extends AbstractWarpClientTestTestBase {
private CountDownLatch requestStarted;
private CountDownLatch responseFinished;
private CountDownLatch activityFinished;
@Mock
private ServiceLoader serviceLoader;
@Mock
private Inspection serverInspection;
private static AtomicReference<Throwable> failure = new AtomicReference<Throwable>(null);
private static AtomicReference<WarpActivityBuilder> requestExecutor = new AtomicReference<WarpActivityBuilder>();
private static AtomicReference<WarpContext> warpContextReference = new AtomicReference<WarpContext>();
@Inject
private Instance<WarpContext> warpContext;
@Inject
private Instance<WarpExecutionContext> warpExecutionContext;
@Before
public void initialize() throws Exception {
requestStarted = new CountDownLatch(1);
responseFinished = new CountDownLatch(1);
activityFinished = new CountDownLatch(1);
WarpRequestSpecifier requestExecutor = new DefaultWarpRequestSpecifier();
getManager().inject(requestExecutor);
TestRequestExecutionSynchronization.requestExecutor.set(requestExecutor);
ExecutionSynchronizer inspectionSynchronizer = new DefaultExecutionSynchronizer();
getManager().inject(inspectionSynchronizer);
WarpExecutor warpExecutor = new DefaultWarpExecutor();
getManager().inject(warpExecutor);
WarpRuntime warpRuntime = new DefaultWarpRuntime();
getManager().inject(warpRuntime);
WarpContext warpContext = new WarpContextImpl();
when(serviceLoader.onlyOne(WarpRequestSpecifier.class)).thenReturn(requestExecutor);
when(serviceLoader.onlyOne(ExecutionSynchronizer.class)).thenReturn(inspectionSynchronizer);
when(serviceLoader.onlyOne(WarpExecutor.class)).thenReturn(warpExecutor);
when(serviceLoader.onlyOne(WarpRuntime.class)).thenReturn(warpRuntime);
when(serviceLoader.onlyOne(WarpContext.class)).thenReturn(warpContext);
bind(ApplicationScoped.class, ServiceLoader.class, serviceLoader);
fire(new BeforeClass(TestingClass.class));
}
@After
public void finalize() {
fire(new AfterClass(TestingClass.class));
}
@Override
protected void addExtensions(List<Class<?>> extensions) {
extensions.add(WarpRuntimeInitializer.class);
extensions.add(DefaultWarpRequestSpecifier.class);
extensions.add(WarpExecutionObserver.class);
extensions.add(WarpExecutionInitializer.class);
}
@Test
public void test_zero_requests_execution() {
assertBefore();
Warp.initiate(new Activity() {
public void perform() {
assertDuringActivity();
}
}).group().expectCount(0).inspect(serverInspection).execute();
assertAfter();
}
@Test
public void test_single_request_with_blocking_client_activity() throws Exception {
assertBefore();
new Thread(new Runnable() {
public void run() {
awaitSafely(requestStarted);
singleRequestHandshake();
responseFinished.countDown();
}
}).start();
Warp.initiate(new Activity() {
public void perform() {
assertDuringActivity();
prepareForRequest();
requestStarted.countDown();
activityFinished.countDown();
}
}).inspect(serverInspection);
assertAfter();
awaitSafely(activityFinished);
}
@Test
public void test_single_request_with_blocking_client_activity_with_waiting_for_requests() {
assertBefore();
new Thread(new Runnable() {
public void run() {
awaitSafely(requestStarted);
if (warpContextReference.get().getSynchronization().isWaitingForRequests()) {
singleRequestHandshake();
}
responseFinished.countDown();
}
}).start();
Warp.initiate(new Activity() {
public void perform() {
assertDuringActivity();
prepareForRequest();
requestStarted.countDown();
activityFinished.countDown();
}
}).inspect(serverInspection);
assertAfter();
awaitSafely(activityFinished);
}
@Test
public void test_single_request_with_nonblocking_client_activity() throws Throwable {
assertBefore();
new Thread(new Runnable() {
public void run() {
awaitSafely(requestStarted);
try {
singleRequestHandshake();
} catch (Exception e) {
failure.set(e);
} finally {
responseFinished.countDown();
}
}
}).start();
Warp.initiate(new Activity() {
public void perform() {
assertDuringActivity();
prepareForRequest();
requestStarted.countDown();
}
}).inspect(serverInspection);
awaitSafely(responseFinished);
assertAfter();
if (failure.get() != null) {
throw failure.get();
}
}
@Test
public void test_multiple_request_with_nonblocking_client_activity() throws Throwable {
final CountDownLatch secondResponseFinished = new CountDownLatch(1);
final CountDownLatch secondRequestStarted = new CountDownLatch(1);
assertBefore();
new Thread(new Runnable() {
public void run() {
awaitSafely(requestStarted);
try {
handshakeForGroup(1);
} catch (Throwable e) {
failure.set(e);
} finally {
responseFinished.countDown();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
awaitSafely(secondRequestStarted);
try {
handshakeForGroup(2);
} catch (Throwable e) {
failure.set(e);
} finally {
secondResponseFinished.countDown();
}
}
}).start();
Warp
.initiate(new Activity() {
public void perform() {
assertDuringActivity();
prepareForRequest();
requestStarted.countDown();
secondRequestStarted.countDown();
}
})
.group(1)
.inspect(serverInspection)
.group(2)
.inspect(serverInspection)
.execute();
awaitSafely(responseFinished);
assertAfter();
if (failure.get() != null) {
throw failure.get();
}
}
private void prepareForRequest() {
WarpContext warpContext = this.warpContext.get();
warpContextReference.set(warpContext);
}
private void singleRequestHandshake() {
handshakeForGroup(SingleInspectionSpecifier.GROUP_ID);
}
private void handshakeForGroup(Object groupId) {
awaitSafely(requestStarted);
WarpContext warpContext = warpContextReference.get();
assertNotNull("WarpContext should be available", warpContext);
WarpGroup group = warpContext.getGroup(groupId);
RequestPayload requestPayload = group.generateRequestPayload(mock(Request.class));
ResponsePayload responsePayload = new ResponsePayload(requestPayload.getSerialId());
responsePayload.setInspections(requestPayload.getInspections());
warpContext.pushResponsePayload(responsePayload);
}
private void assertDuringActivity() {
assertTrue("warp execution context should be active", warpExecutionContext.get().isActive());
WarpContext warpContext = TestRequestExecutionSynchronization.this.warpContext.get();
assertNotNull("WarpContext should be available", warpContext);
}
private void assertBefore() {
assertFalse("warp execution context shouldn't be active before request", warpExecutionContext.get().isActive());
}
private void assertAfter() {
assertFalse("warp execution context shouldn't be active after response", warpExecutionContext.get().isActive());
}
private void awaitSafely(CountDownLatch latch) {
try {
latch.await(1, TimeUnit.SECONDS);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
@WarpTest
@RunAsClient
public static final class TestingClass {
@Deployment
public static Archive deploy() {
return null;
}
}
}