Интеграционное тестирование с внедренным CDI-участником

У меня есть простой bean-компонент области запроса, который содержит введенного принципала, чтобы я мог определить идентификатор текущего пользователя. Затем этот bean-компонент вводится в сервлет, и сервлет использует bean-компонент для отображения идентификатора пользователя. Например:

Интерфейс:

public interface UserManager {

     public String getCurrentUserName();

}

Реализация:

@RequestScoped
public class CdiUserManager implements UserManager {

     @Inject
     private Principal principal;

     public CdiUserManager() {

     }

     @Override
     public String getCurrentUserName() {

         String name = null;

         if(principal != null && principal.getName() != null){
              name = principal.getName();
         }

         return name;
     }

 }

Сервлет:

@WebServlet({"/public/user", "/authenticated/user"})
public class UserServlet extends HttpServlet {

     @Inject
     private UserManager manager;

     public UserServlet() {
        super();
     }

     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         response.getWriter().write("UserName: " + manager.getCurrentUserName());
     }

 }

Сервлет отображается как для аутентифицированного, так и для неаутентифицированного доступа. У меня настроен файл web.xml с надлежащими ограничениями безопасности, поэтому базовая проверка подлинности требуется только для аутентифицированного URL-адреса.

У меня также есть файл EAR. Файл application.xml в EAR включает веб-модуль с сервлетом и управляемым компонентом, а также роль безопасности, определенную в файле web.xml. Кроме того, у меня есть файл ibm-application-bnd.xml, в котором роль безопасности в файлах web.xml и application.xml сопоставляется со специальной темой ALL_AUTHENTICATED_USERS.

У меня есть пустой файл beans.xml в каталоге WEB-INF файла WAR.

В настоящее время у меня есть две проблемы, которые я не могу решить.

1) Когда я получаю доступ к общедоступному URL-адресу в качестве пользователя, не прошедшего проверку подлинности, я ожидал, что либо ввод принципала, либо вызов принципала.getName() будет нулевым или каким-либо другим идентифицируемым значением... т.е. В настоящее время я получаю NPE с приведенной ниже трассировкой стека. Если я получаю доступ к аутентифицированному URL-адресу и вхожу в систему через обычную аутентификацию, сервлет возвращает мое имя пользователя, как и ожидалось. Я не уверен, что в этом случае следует вернуть стандарт, но я думаю, что это ошибка?

java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:273)
at [internal classes]
at org.javassist.tmp.java.lang.Object_$$_javassist_1.getName(Object_$$_javassist_1.java)
at com.testing.cdi.CdiUserManager.getCurrentUserName(CdiUserManager.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.intercept.InterceptorHandler.invoke(InterceptorHandler.java:327)
at [internal classes]
at com.testing.cdi.CdiUserManager_$$_javassist_0.getCurrentUserName(CdiUserManager_$$_javassist_0.java)
at com.testing.cdi.UserServlet.doGet(UserServlet.java:31)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
at [internal classes]

2) Второй вопрос, который у меня есть, заключается в том, как провести интеграционное тестирование с использованием внедренного принципала? В настоящее время я использую Arquillian, и я создал метод развертывания, который выглядит следующим образом:

 @Deployment
 public static EnterpriseArchive createDeployment() {

    EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class, CONTEXT_ROOT + ".ear");
    WebArchive war = ShrinkWrap.create(WebArchive.class, CONTEXT_ROOT + ".war");

    war.addPackages(true, UserManager.class.getPackage());

    war.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    war.setWebXML(new File("src/main/webapp/WEB-INF/web.xml"));

    ear.setApplicationXML(new File("../testing-ear/src/main/application/META-INF/application.xml"));
    ear.addAsManifestResource(new File("../testing-ear/src/main/application/META-INF/ibm-application-bnd.xml"));
    ear.addAsModule(war);

    return ear;
 }

Я аутентифицирую своего тестового пользователя перед каждым тестовым случаем следующим образом:

@Before
public void setup() throws LoginException, WSSecurityException {

    // WLP provided classes to authenticate a user.
    CallbackHandler wscbh = new WSCallbackHandlerImpl("user", "password");
    LoginContext ctx = new LoginContext("WSLogin", wscbh);
    ctx.login();

    // Set the user as the current user on the thread.
    Subject mySubject = ctx.getSubject();
    WSSubject.setRunAsSubject(mySubject);

}

Затем в тестовом случае я проверяю, является ли имя пользователя нулевым, например:

@Test
public void testAuthenticatedPrincipal() throws LoginException, WSSecurityException {


    assertNull("User name should not be null.", manager.getCurrentUserName());
}

Выполнение этого теста всегда приводит к NPE с трассировкой стека:

java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:273)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:267)
at org.javassist.tmp.java.lang.Object_$$_javassist_2.getName(Object_$$_javassist_2.java)
at com.testing.cdi.CdiUserManager.getCurrentUserName(CdiUserManager.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.intercept.InterceptorHandler.invoke(InterceptorHandler.java:327)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:117)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:108)
at com.testing.cdi.CdiUserManager_$$_javassist_1.getCurrentUserName(CdiUserManager_$$_javassist_1.java)
at com.testing.cdi.test.UserManagerTest.testAuthenticatedPrincipal(UserManagerTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.jboss.arquillian.junit.Arquillian$6$1.invoke(Arquillian.java:325)
at org.jboss.arquillian.container.test.impl.execution.LocalTestExecuter.execute(LocalTestExecuter.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:99)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:81)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:145)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:116)
at org.jboss.arquillian.core.impl.EventImpl.fire(EventImpl.java:67)
at org.jboss.arquillian.container.test.impl.execution.ContainerTestExecuter.execute(ContainerTestExecuter.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:99)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:81)
at org.jboss.arquillian.test.impl.TestContextHandler.createTestContext(TestContextHandler.java:102)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.test.impl.TestContextHandler.createClassContext(TestContextHandler.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.test.impl.TestContextHandler.createSuiteContext(TestContextHandler.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:145)
at org.jboss.arquillian.test.impl.EventTestRunnerAdaptor.test(EventTestRunnerAdaptor.java:135)
at org.jboss.arquillian.junit.Arquillian$6.evaluate(Arquillian.java:318)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.jboss.arquillian.junit.Arquillian$5.evaluate(Arquillian.java:277)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.jboss.arquillian.junit.Arquillian$2.evaluate(Arquillian.java:202)
at org.jboss.arquillian.junit.Arquillian.multiExecute(Arquillian.java:377)
at org.jboss.arquillian.junit.Arquillian.access$200(Arquillian.java:52)
at org.jboss.arquillian.junit.Arquillian$3.evaluate(Arquillian.java:216)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.jboss.arquillian.junit.Arquillian.run(Arquillian.java:164)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
at org.jboss.arquillian.junit.container.JUnitTestRunner.execute(JUnitTestRunner.java:66)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.executeTest(ServletTestRunner.java:159)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.execute(ServletTestRunner.java:125)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.doGet(ServletTestRunner.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:776)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:473)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1104)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:4845)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:297)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:981)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:262)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:955)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1157)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:627)
at java.lang.Thread.run(Thread.java:863)

В прошлом я создавал проекты EJB и тестировал их с помощью этого метода. Инжект SessionContext заменяет участника в этом сценарии. У кого-нибудь есть какие-либо советы или опыт о том, как запустить этот тестовый пример?

P.S. Я использую IBM JDK v1.7.1 с WebSphere Liberty Developer Edition v8.5.5.5.


person Thomas Lawless    schedule 07.06.2015    source источник


Ответы (1)


Обычно нулевое значение используется для принципала пользователя, который не вошел в систему, например. HttpServletRequest.getUserPrincipal() возвращает null, если пользователь не прошел аутентификацию.

Поэтому я не думаю, что необоснованно, чтобы введенный Принципал был нулевым. Тем не менее, Принципал также является компонентом CDI, который проксируется. Поскольку у вас есть введенный прокси-объект, вы не можете проверить его на нулевое значение, но когда вы вызываете getName(), CDI пытается найти реального принципала для вошедшего в систему пользователя и вызывает для него getName(), что приводит к исключению NullPointerException.

Я понимаю, что это не очень полезно, поскольку вы не можете использовать основной компонент для проверки подлинности пользователя, но я не думаю, что это неправильно.

Для теста Arquillian вы можете запустить тест как клиент, а не на сервере, чтобы вы могли вручную вызвать URL-адрес сервлета и предоставить учетные данные для аутентификации. Вам нужно, чтобы сервлет распечатал имя пользователя и проверил правильность ответа на клиенте.

Некоторая информация о выполнении тестов в клиентском режиме приведена здесь: https://docs.jboss.org/author/display/ARQ/Test+run+modes

person Azquelt    schedule 09.06.2015